> ## Content Index
> Fetch the complete content index at: https://informatic-ar.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# بناء نظام جوازات المواطنين باستخدام الـ ASP.NET MVC والـ Unit Tests
- URL: https://informatic-ar.com/aspnet-mvc-passports-unit-tests/
- Published: 2018-06-30T00:10:08.000Z
- Updated: 2026-10-03T22:31:29.000Z
- Author: محمد أحمد حسين
- Tags: برمجة, دوت نت, قواعد البيانات, الويب, #wordpress-archive, #Import 2026-10-03 20:48

هل أنت مستعد للعمل هنا؟...ستكتب 1000 سطر برمجي اليوم... لنبدأ

يتكون هذا التطبيق من ثلاثة أجزاء..وجميعها سنعمل عليها هنا..يتكون من إنشاء قاعدة البيانات والتطبيق...ويتكون من إنشاء إدارة التطبيق..ويتكون من عمل إختبار الشفرات للتطبيق.

مقدمة

هذا التطبيق به العديد من الخصائص التي قمت بحذفها منه وذلك تسهيلا للشرح والتطبيق الفعلي الذي أنشأته يختلف اختلافا تاما عن ما سأقدمه لك هنا عزيزي المطور ولكن هذا التطبيق الذي ستنشئه هنا سيكون مكتملا من ناحية تعليمية وليس من ناحية عملية..أي لا تستطيع تقديمه لإدارة الجوازات لنشره، اللهم إلا اذا قمت بتطويره بصورة محترفين..وفي الحقيقة سنستخدم في قاعدة البيانات جدول واحد Persons وهذا غير منطقي في حال اردت أن تقوم بتقديمه لإدارة الجوازات ..ففكرة التطبيق هنا (وليس الحقيقي) بسيطة، المواطن سيقدم جوازه للتجديد وسيأتي لإستلامه..والجواز الخاص به سيكون جاهزا فهنا لم أقم بإنشاء جدول يوضح هل تم تجديد الجواز ام لا ولم أقم بإنشاء جدول يوضح في حال تجديد الجواز أين يوجد الجواز الآن وفي أي رفٍ يوجد بمكتب التسليم.

> *ملاحظة: هل هذا يعني بأنني لا أريد مشاركة الشفرات التي أكتبها معك عزيزي المطور؟! الإجابة بلا..لا أعني هذا ابدا.. لكن حتى تكون على علم...المشروع هذا به العديد من الخصائص التي قمت بحذفها حتى يصبح بسيطا في الشرح هنا فالمشروع هذا قد قمت بتقديمه في ورشة صغيرة في إحدى الجامعات بالسوان لقسم تقانة المعلومات بتلك الجامعة...وقد قمت بإكماله بعد سفري من السودان بصورة تامة حيث من حيث الـ* *Security* *والـ* *Performance* *وتعديل جميع الشفرات التي ستراها انت هنا جميعها قمت بتغييرها وقد قمت بإستخدام انماط التصميم* *Design patterns* *والـ* *Instrumentation*   *والـ* *Profiler* *والـ* *CLR Profiler* *و مكتبات الـ* *Jquery* *و مكتبة الـ* *Caching* *والكثير من الخصائص..كل تلك الخصائص قمت بحذفها من هنا حتى لا يصبح الشرح عسيرا بالنسبة لي أو لانه سيأخذ أيام عديدة ومع ظروف عملي قد يبدو صعبا كتابة شرح لجميع الأكواد والخصائص..وأيضا لتكون على علم عزيزي المطور لقد قمت بعرض المشروع على المسؤولين (...) هناك ولكن لم أجد أي استجابة (...)..فعندما أقول بأنني لن أقوم بعرض جميع شفرات المشروع الحقيقي وشفرات الإختبار Unit Tests فهذا يعني تقليلا للعمل هنا فقط...وسأحاول في مرات قادمات نشر مقالات توضح كيفية اختبار الأكواد مع شرحها ولأنني هنا قمت بنشر أكواد اختبار الشفرات بدون شرح و التي تساعدنا في اختبار برمجياتنا.*

**الجزء الأول – إنشاء قاعدة البيانات والتطبيق**

بسم الله والصلاة والسلام على رسول الله...في هذا التطبيق سنقوم بمراجعة تامة للـ ASP.NET MVC التطبيق بسيط جدا..وقد كنت قمت ببنائه لغرض مــا..كنت في السودان قبل فترة وعندما أردت تجديد الجواز الخاص بي وعند استلام الجوازكان الإستلام بالبحث عن اسم صاحب الجواز على سبورة وبالتالي العملية كانت صعبة جدا..فقررت بناء تطبيق متكامل لتسليم الجوازات عن طريق جهاز الحاسوب..وقمت ببناء التطبيق وللحقيقة التطبيق الذي ستبنيه اليوم هو تطبيق مصغر جدا من التطبيق الحقيقي، حيث يحتوي التطبيق الحقيقي على العديد من الإمكانيات المتقدمة جدا والتي قمت بحذفها من هنا لكي نتعلم بسهولة تامة كيفية إستخدام الـ ASP.NET MVC في بناء التطبيقات، هذا من ناحية، من الناحية الأخرى ستتعلم كيفية استخدام مختبر الشفرات Unit Tests وعمل اختبار للشفرات التي ستكتبها هنا...وكل هذا سيتم داخل بيئة الفيجوال ستديو...وكالعادة البيئة التي اعمل عليها هو نظام التشغيل Windows بالإضافة للـ Visual Studio 2013 زائداً لغة قواعد البيانات SQL Server من داخل بيئة الـ SQL Server Management Studio، لكن يمكنك استخدام بيئة الفيجوال ستديو نفسها لإنشاء قواعد البيانات والجداول لقواعد البيانات تلك والإجراءات المخزنة Stored Procedures إذا أردت أيضا عن طريق استخدام الـ LocalDB والتي يتم تثبيتها مع الفيجوال ستديو 2013، أيضا بإمكانك استخدام فيجوال ستديو 2012 أو 2015 أو 2017 لعمل هذا التطبيق.

سأحاول بقدر الإمكان وضع التطبيق في سياقه الصحيح مع شرح الأكواد التي سنكتبها.

**إنشاء المشروع**

قم بفتح الفيجوال ستديو وقم بإنشاء تطبيق جديد قم بإختيار الفريم وورك 4.5 ومن على يسار الشاشة قم بالضغط على Web مرتين Double-Click وقم بإختيار Visual Studio 2012 وقم بإختيار المشروع ASP.NET MVC 4 Application قم بتسمية المشروع MvcExplain (بإمكانك تسميته بما يعجبك) وقم بتحديد مسار حفظ التطبيق على أي قرص صلب على جهازك وقم بالضغط على OK. (مرفق الصورة)، بعدها ستظهر شاشة قم بإختيار Basic لهيكلية المشروع ولا تنسى ان تختار No Authentication للمشروع قم أيضا بإختيار محرك نصوص Razor لصفحات الـ Html وقم بالضغط على OK.

![](https://informatic-ar.com/wp-content/uploads/2018/06/1-300x181.png)  
**إنشاء قاعدة البيانات**

بعد أن يقوم الفيجوال ستديو بإنشاء التطبيق قم بفتح الـ Server Explorer، من تلك الشاشة قم بالضغط على العلامة التي بها شعار موصل الكهرباء والتي ملصق عليها علامة الجمع (إنظر للصورة في الأسفل) بالضغط عليها ستفتح معك شاشة لإدخال المزود الخاص بك قم بإدخال LocalDb)\\v11.0) على خانة الـ Server name وفي خانة Select or enter a database name قم بإدخال اسم قاعدة البيانات التالية PassportRecive واضغط على Ok سيسألك الفيجوال ستديو بأنه لاتوجد قاعدة بيانات بهذا الإسم في المزود الخاص الذي قمت بإدخاله، هل تريد إنشاء قاعدة بيانات جديدة بهذا الإسم قل له نعم بالضغط على OK.

![](https://informatic-ar.com/wp-content/uploads/2018/06/2-300x228.png)

الآن لقد أنهيت الخطوة الأولى التي تعنى بإنشاء قاعدة البيانات، الآن سنقوم بإنشاء الجدول والحقول التي ستعيننا على تكملة هذا المشروع بصورة صحيحة.

قم بالضغط مرتين Double-Click بالزر الأيسر للمؤشر (ماوس) على قاعدة البيانات التي أنشئتها ستفتح معك عدة خيارات داخل قاعدة البيانات تلك قم بالضغط بالزر الأيمن للمؤشر (ماوس) على Table ومن الشاشة التي ستظهر لك قم بإختيار Add New Table قم بلص الشفرة التالية على أسفل الشاشة او شاشة الإستعلامات التي سيفتحها الفيجوال ستديو تلقائيا:

```sql
CREATE TABLE Persons
(
 [PersonID] INT NOT NULL PRIMARY KEY IDENTITY,
 [Name] NVARCHAR(50) NOT NULL,
 [NID] NVARCHAR(50) NOT NULL,
 [Recived] BIT NULL,
 [RecivedDate] DATETIME NULL
)
```

أعلى الشاشة في نفس الصفحة توجد كلمة Update قم بالضغط عليها حتى يقوم الفيجوال ستديو بإنشاء الجدول وحقول ذلك الجدول. ستفتح لك صفحة تأكيدية بها خاصيتان واحدة لعمل تحديث والأخرى لتوليد نص لقاعدة البيانات، قم بالضغط على Update Database.

في هذا الجدول لدينا رقم المواطن الذي ستتولى قاعدة البيانات توليده، ولدينا اسم المواطن ورقمه الوطني NID ولدينا حقل من النوع BIT ويعنى بإستلام الجواز من عدمه وحقل أخير يُعنى بتاريخ استلام الجواز.

قم بتنفيذ الجملة الإستعلامية تلك على قاعدة البيانات..وستقوم تلك الجملة بإضافة حقلين لقاعدة البيانات:

```sql
SET IDENTITY_INSERT [dbo].[Persons] ON
INSERT INTO [dbo].[Persons] ([PersonID], [Name], [NID], [Recived], [RecivedDate]) VALUES (1, N'Mohammed', N'123-87847-888', NULL, NULL)
INSERT INTO [dbo].[Persons] ([PersonID], [Name], [NID], [Recived], [RecivedDate]) VALUES (2, N'Ahmed', N'554-78478', NULL, NULL)
SET IDENTITY_INSERT [dbo].[Persons] OFF
```

*\*\*\* ملاحظة: في المشاريع الكبيرة دائما ما نستخدم شاشة الإستعلام النصي لإنشاء قواعد البيانات وحفظها على الأقراص الصلبة وعمل أرشفة لقاعدة البيانات بتقنية الـ JSON أو الـ XML أو الـ BSON..ومن خلال خبرتنا فهي مهمة جدا...لكن لأن المشروع هذا بسيط جدا مقارنة بالمشاريع الكبيرة فلن تحتاج لعمل كهذا...لكن إذا قامت إدارة الجوازات بطلب تنفيذ هذا المشروع فبالتالي لن يكون بتلك الصورة كما ذكرت لكم في المقدمة بأنني حذفت العديد من الخواص والخصائص حتى يكون الشرح هنا مبسطا.*  
**العمل على المشروع الآن**

بعد إنشاء قاعدة البيانات سنقوم بعمل ربط بين قاعدة البيانات والتطبيق من خلال ملف الـ Web.Config عن طريق فرع الإتصال connectionString ولتقوم بالربط قم بفتح ملف الـ Web.config وقم بلصق الشفرة التالية عليه:

```markup
<connectionStrings>
    <add name="PersonDbContext" providerName="System.Data.SqlClient" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=PassportRecive;Integrated Security=True" />
  </connectionStrings>
```

لا تنسى كتابة شفرة الإتصال تلك في سطر واحد..وان لم تفعل فلن يتم الإتصال بين التطبيق وقاعدة البيانات.

في نص الإتصال لقد قمت بإدخال المزود الخاص بي وهو LocalDb\\v11.0 وإذا كنت تعمل على هذا المزود قم بإدخاله كما مبين سابقا وإن كنت تعمل على مزوّد آخر قم بإدخال المزوّد الذي تعمل عليه.

قم بالضغط بالزر الأيمن على المؤشر (ماوس) على ملف الـ Models وقم بإنشاء فئة جديدة بإسم Person وقم بلصق الشفرة التالية في صفحة تلك الفئة:

```csharp
   [Table("Persons")]
    public class Person

   
{
            [HiddenInput(DisplayValue = false)]
        public int PersonID { get; set; }

            [Required(ErrorMessage = "Please Enter The Name")]
        public string Name {
        get; set;
    }

            [Required(ErrorMessage = "Please Enter The NID")]
        public string NID {
        get; set;
    }

            [HiddenInput(DisplayValue = false)]
        public bool ? Recived { get; set; }

            [HiddenInput(DisplayValue = false)]
        public Nullable<DateTime> RecivedDate {
        get; set;
    }
       
}
```

قم بإضافة فضاء الأسماء التالية أعلى الفئة:

```csharp
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
```

الفئة Person توجد بها نفس الحقول الموجود على الجدول الذي أنشأناه بقاعدة البيانات مع بعض الخواص لكل Property والخواص تلك فرضا تظهر في اسم المواطن توجد خاصية Attribute بإسم Required وستفيدنا عند إستلام الجواز من المواطن حيث ستفرض على المستخدم العادي ادخال الاسم وإلا ستظهر له رسالة خطأ كما موضّحة في المعامل Parameter الذي تأخذه تلك الخاصية..الخاصية الأخرى HiddenInput وقد قمنا ببلورتها لبعض الحقول أيضا كتاريخ استلام الجواز وتعني هنا عدم إظهار الحقل أثناء إنشاء حقل جديد لمواطن ما..لا تقلق سترى كيف تعمل تلك الخواص عندما ننشئ صفحات الـ Html.

بالإمكان استخدام الـ Regular Experssion إذا أردت لعمل تحقق يجبر المستخدم على إدخال ارقام فقط بالنسبة للرقم الوطني.

لو لاحظت أن اسم المزوّد في ملف الـ web.Config هو PersonDbContext ولكي نقوم بربط التطبيق بقاعدة البيانات سنُنشئ فئة Class بهذا الإسم داخل الملف Models وسنقوم بكتابة الشفرة التالية عليها:

```csharp
public class PersonDbContext : DbContext
   
{
            public PersonDbContext() : base("name=PersonDbContext")
       
    {

               
    }
            public DbSet<Person> Persons { get; set; }
       
}
```

لا تنسى ان تقوم بإستدعاء فضاء الأسماء التالي في أعلى الفئة:

```csharp
using System.Data.Entity;
```

في هذه الفئة قمنا بإستخدام تقنية الـ Entity Framework وهي تقنية من مايكروسوفت تقوم بإنشاء جداول وهمية على شكل فئات تمكننا من العمل عليها بدلا من العمل مباشرة على الجداول التي موجودة بقاعدة البيانات وتلك الجداول الوهمية تعتبر كـ Strongly type أي بمعنى أنه سيقوم الفيجوال ستديو بمساعدتنا للعمل عليها من خلال التكملة عند الكتابة في بيئته أو إذا كان هناك خطأ سيقوم الفيجوال ستديو بإخطارنا بالخطأ Compile time error ومساعدتنا على الأخطاء التي تظهر..وتلك التقنية أتت بديلا لتقنية الـ ADO.NET التي نذكرها جميعا والتي تعمل على تنفيذ الجمل الإستعلامية بصورة نصية داخل بيئة الفيجوال ستديو..وكما هو معروف العمل على الإستعلام النصي سيكون به أخطاء مؤكدة في كتابة الكلمات..ولن يستطيع الفيجوال ستديو اكتشاف الخطأ لأنه من النوع String وسنستخدم تقنية الـ LinQ لتنفيذ الجمل الإستعلامية في التطبيق نسبة لسهولتها وأيضا هي Strongly type.

الفئة التي أنشأناها سابقا تحتوي على خاصية Property واحدة وهي Persons وهذه الخاصية مطابقة لإسم الجدول الذي أنشأناه في قاعدة البيانات PassportRecive سابقا، أيضا الفئة ترث من فئة أخرى وهي الـ DbContext وهي تمكننا من عمل الإستعلامات في قاعدة البيانات والجداول الموجود في قاعدة البيانات تلك. أيضا إذا لاحظت قمنا بتعريف اسم الإتصال بصورة صريحة Explicitly من خلال مُنشئ الفئة Constructor. وهذا يقوم بإخبار التطبيق بإستخدام اسم الإتصال PersonDbContext هذا لعمل إتصال مع قاعدة البيانات الموضحة في ملف الـ web.Config.من خلال الجزع Catalog.

> *ليس بالضرورة استدعاء منشئ الفئة* *Constructor* *... لكن هذا للتوضيح..لكن ستحتاجه إذا كان اسم الفئة* *Class* *مغاير لإسم الإتصال في ملف الـ* *web.Config* *.*

قم بالضغط بالزر الأيمن للمؤشر (ماوس) على اسم المشروع في الفيجوال ستديو وقم بإنشاء المجلدات التالية:

```csharp
Infrastructure Repo
```

في نفس ملف الـ Models قم بإنشاء واجهة Interface جديدة بالإسم IPerson وقم بلصق الشفرة التالية داخلها:

```csharp
public interface IPerson
   
{
            IQueryable<Person> GetAllPersons { get; }
            Person GetPersonByID(int personID);
            Person GetPersonByHisNID(string personNID);
            Person RecivedHisPassport(int personID);
            void SavePassportInfo(Person person);
          
   
}
```

سنقوم يإستخدام فصل الأشياء عن بعضها DI وسنستخدم تقنية الـ Entity Framework لإنشاء مستودع لجلب وتنفيذ العمليات التي نريدها من قاعدة البيانات عن طريق تلك التقنية EF وقد قمنا بإستخدام الـ Code First بإنشائنا للفئة Person يدويا وعدم توليدها من قاعدة البيانات..ولفصل الأشياء من بعضها سنحتاج لإحدى المكتبات التي تساعدنا على ذلك وسنستخدم مكتبة الـ Ninject، إذا كنت تريد فهم ماذا نعني بـ Dependency Injection قم بمراجعة المقال الموضح في الرابط أدناه والمنشور على نفس منصة **انفورماتيك** والتي شرحت فيها طريقة فصل الأشياء DI عن طريق استخدام مكتبة الـ Ninject، وسترى كيفية تهيئة تلك المكتبة للعمل مع تطبيقات الـ ASP.NET MVC.

[كيفية تهيئة مكتبة الـ Ninject للعمل مع مشروع الـ ASP.NET MVC](https://informatic-ar.com/ninject-aspnet-mvc/)

اضغط على TOOLS في اعلى الشريط المساعد الخاص بالفيجوال واختار الـ Library Package Manager والتي ستظهر لك خيارات عدة إضغط على اول خيار Package Manager Console واكتب السطر التالي:

```csharp
PM > Install - Package Ninject - Version 3.0.1.10
```

في هذه الخطوة قمنا بتنزيل مكتبة الـ Ninject وهي المكتبة التي تساعدنا على فصل الفئات عن بعضها البعض بإستخدام الواجهات Interfaces.

في الواجهة التي أنشأناها سابقا لدينا خمسة أساليب Methods الأسلوب الأول يُعني بإرجاع جميع المواطنين من قاعدة البيانات والآخر يقوم بإرجاع مواطن واحد بالرقم الذي تنشئه قاعدة البيانات Identity والأسلوب الثالث يقوم بإرجاع بيانات المواطن عن طريق رقمهُ الوطني والرابع يقوم بتنفيذ جملة Query على قاعدة البيانات في حقل المواطن بعمل تسليم لجواز المواطن والأسلوب الأخير يُعني بحفظ بيانات مواطن جديد يريد عمل إصدار أو تجديد جواز جديد.

بعد إنشاء تلك الواجهة سنقوم بإنشاء فئة ستقوم بعمل تنفيذ Implementation للأساليب الخمسة التي ذكرناها آنفا. وستتولى مكتبة الـ Ninject مهمة حقن تلك الفئة عندما نقوم بطلبها من بيئة الـ MVC Framework من خلال عمل طلب Request او إرسال Response من خلال فئة التحكم Controller من المتصفح لديك.

قم بإنشاء فئة Class في ملف الـ Repo الذي أنشأته سابقا وقم بتسمية تلك الفئة بـ PersonRepository وتلك الفئة عبارة عن تنفيذ للأساليب الموجودة بالواجهة IPerson لذلك سترث منها، الآن قم بنسخ الشفرة التالية داخل تلك الفئة:

```csharp
public class PersonRepository : IPerson
   
{
            private PersonDbContext _dbContext = new PersonDbContext();

            public IQueryable<Person> GetAllPersons
    {
        get {
            return _dbContext.Persons;
        }
    }

            public Person GetPersonByID(int personID)
       
    {
                    return _dbContext.Persons.FirstOrDefault(p => p.PersonID == personID);
               
    }

            public Person GetPersonByHisNID(string personNID)
       
    {
                    return _dbContext.Persons.FirstOrDefault(p => p.NID == personNID);
               
    }

            public Person RecivedHisPassport(int personID)
       
    {
            // First
            Person p = (from x in _dbContext.Persons
                        where x.PersonID == personID
                        select x).First();

            // Second
            p.Recived = true;
            p.RecivedDate = DateTime.Now;
            _dbContext.SaveChanges();

            return p;

       
    }

            public void SavePassportInfo(Person person)
       
    {
                    if (person.PersonID == 0) // Save new one
           
        {
                            person.RecivedDate = DateTime.Now;
                            person.Recived = false;
                            _dbContext.Persons.Add(person);
                           
           
        }
                    else // Edit exciting one
           
        {
                            Person dbEntry = _dbContext.Persons.Find(person.PersonID);
                            if (dbEntry != null)
               
            {
                                    dbEntry.Name = person.Name;
                                    dbEntry.NID = person.NID;
                                    dbEntry.Recived = false;
                                
            }
                       
        }
                    _dbContext.SaveChanges();
               
    }
              
   
}
```

لا تنسى إستدعاء فضاء الأسماء التالي:

```csharp
using MvcExplain.Models;
using System.Data.Entity;
```

ماذا لدينا في تلك الفئة التي أنشأناها سابقا؟ في لغة الـ C# هناك متحكم شامل بتلك اللغة يدعى CLR وهو الذي يتولى ترجمة الأكواد التي نكتبها بتلك اللغة..في حالة الواجهات Interfaces لو لاحظت لقد قمنا بإنشاء واجهة اسمها IPerson تلك الواجهة تأخذ النوع public للوصول إليها وجميع الأساليب التي بها يجب ان لا تأخذ أي نوع وصول Member accessibility ولذلك سيجبرك المترجم على تعريفها داخل الفئات التي سترث من تلك الواجهة IPerson وفي حالتنا تلك ستكون الفئة هي الـ PersonRepository فجميع الأساليب أخذت أمكانية الوصول لجميع عناصرها النوع public. أيضا الـ CLR سيقوم ببلورة تلك العناصر بالكلمة virtual أثناء عمل التطبيق وإن لم تقوم بكتابة تلك الكلمة بصورة صريحة للعنصر سيقوم المترجم بكتابتها بدلا منك وسيضيف الكلمة sealed إليها وذلك يعني لن تستطيع الوراثة من هذا الإسلوب Method. والعكس إن قمت بكتابتها بصورة صريحة سيقوم المترجم بإتاحة الفرصة لك بالوراثة منها والكتابة فوقها override مع الأخذ في الإعتبار أن المترجم سيضيف كلمة virtual في كلا الحالتين.(لا تشغل نفسك بتلك المعلومات ان كنت لا تملك خبرة عن كيفية ترجمة أكواد لغة الـ C# وهي ليست ضرورية لفهم عمل وآليه التطبيق الذي نبنيه الآن...فقط أردت أن أشرح لك كيفية عمل الوراثة من الواجهات Interfaces).

الآن الفئة PersonRepository ترث من الواجهة IPerson وتقوم بتنفيذ جميع الأساليب الموجودة بالواجهة IPerson. ولأننا سنعمل مع قاعدة لبيانات قمنا بتعريف مثيل للفئة التي تربط التطبيق بقاعدة البيانات وهي الفئة PersonDbContext من النوع private وهذا يعني عدم الوصول إليها من خارج تلك الفئة.

الإسلوب الأول GetAllPersons يتولى مهمة جلب جميع المواطنين من قاعدة البيانات وقمنا بإستخدام الـ Generic من النوع IQuerable والتي بدورها ترث من الـ IEnumarable والتي تقوم بتنفيذ عملية Foreach بالنسبة لقاعدة البيانات .

الإسلوب الثاني GetPersonByHisID يقوم بجلب مواطن واحد من قاعدة البيانات وقمنا بإستخدام تقنية الـ LinQ بإستخدام الـ Element Operator والتي تُدعى FirstOrDefault والتي تقوم بعمل تجميع للمواطنين ثم تقوم بإستدعاء المواطن المطلوب الذي تمت إضافته في الـ constructor هذه العملية تقوم بإرجاع القيمة null إذا لم تجد في التجميع الذي تقوم بعمله الرقم المطابق للرقم الذي أسندناه في الـ constructor.

ويمكنا كتابتها بتلك الصورة فرضا لو كنا نريد أرجاع المواطن الذي رقمه 1

```csharp
var person = (from c in _dbContext.Persons
                          where c.PersonID == 1
                          select c).FirstOrDefault();
```

بإمكانك بدلا من الرقم واحد إسناد المعاملpersonID.

الإسلوب الثالث شبيه بالعنصر الثاني..الفرق اننا سنقوم بإسترجاع قيمة من النوع String.

الإسلوب الرابع RecivedHisPassport يقوم بعمل تنفيذ لجملة في قاعدة البيانات لمواطن مــا، تقوم بتغير الحقل Recived في قاعدة البيانات لـ True والتي تعني أن المواطن قد استلم جوازه..في هذا الإستعلام يتم عمل تجميع للمواطن اولا..هنا:

```csharp
Person p = (from x in _dbContext.Persons
                        where x.PersonID == personID
                        select x).First();
```

بعدها يتم إختيار المواطن الذي رقمه مطابق للمعامل Parameter الذي تم اسناده للأسلوب هذا.. بعدها سنقوم بعمل عمليتين على هذا المواطن وهي تغيير الحقل Recived للقيمة True وأيضا سيتم إضافة تاريخ الإستلام للحقل RecivedDate ونقوم بالحفظ وإرجاع القيمة للمواطن داخل قاعدة البيانات والذي يتم في تلك الجملة:

```csharp
p.Recived = true;
            p.RecivedDate = DateTime.Now;
            _dbContext.SaveChanges();
            return p;
```

الإسلوب الأخير يُعني بحفظ مواطن جديد وتعديل مواطن موجود مسبقا على قاعدة البيانات..وتعمل بصورة مبسطة إذا كان الرقم الذي تم إرساله لقاعدة البيانات موجود إذاً قم بالتعديل الذي تستلمه من الـ Caller وإذا كان غير موجود قم بإنشاء حقل جديد.

الآن انتهينا من تهيئة قاعدة البيانات والجمل التي سنستخدمها لتعيينعا على العمل على قاعدة البيانات...الآن سنقوم بالتوجه لعمل صفحات الـ Html وسنرى كيفية استخدام الجمل التي أنشأناها مسبقا.

في المجلد Infrastructure قم بإنشاء فئة Class بالإسم التالي NinjectControllerFactory وقم بلصق الكود التالي بداخلها:

```csharp
public class NinjectControllerFactory : DefaultControllerFactory
   
{
            private IKernel _kernel;

            public NinjectControllerFactory()
       
    {
                    _kernel = new StandardKernel();
                    AddDefaultBingings();
               
    }

            protected override IController GetControllerInstance(RequestContext requestContext,
                                                                 Type controllerType)
       
    {
                    return controllerType == null ? null : (IController)_kernel.Get(controllerType);
               
    }

            private void AddDefaultBingings()
        
    {
                    _kernel.Bind<IPerson>().To<PersonRepository>();
               
    }
       
}
```

لا تنسى أن تقوم بإستدعاء فضاء الأسماء التالي:

```csharp
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using Ninject;
using MvcExplain.Models;
using MvcExplain.Repo;
```

قم بلص الشفرة التالية على ملف الـ Global.asax داخل الإسلوب Application\_Start

```csharp
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
```

iقم بإنشاء Controller جديدة وأعطها اسم PersonController بالضغط على ملف Controllers وأختيار Add لا تقم بتغيير أي شئ عدا الاسم وقم بالضغط على OK. كما موضح بالصورة التالية:

![](https://informatic-ar.com/wp-content/uploads/2018/06/3-300x200.png)

قم بلصق الكودة التالي بتلك الفئة:

```csharp
public class PersonController : Controller
   
{
            private IPerson repository;

            public PersonController(IPerson repo)
       
    {
                  this.repository = repo;
               
    }
            //
        // GET: /Person/

        public ActionResult Index()
       
    {
                    return View(repository.GetAllPersons);
               
    }

            public ActionResult SerachForPerson(string q)
       
    {
                    var persons = repository.GetPersonByHisNID(q);

                    if (persons != null)
           
        {
                            return PartialView("_PersonSearch", persons);
                       
        }

                    else            
        {
                            return View("NotFound");
                       
        }
               
    }

            [HttpGet]
        public ViewResult PersonRecivedHisPassport(int passID)
       
    {
                    Person person = repository.GetPersonByID(passID);

                    if (person == null)
           //
                return View("HasRecived");

                    else if (person.Recived == true)
                    return View("HasRecived");
                    else             return View();
               
    }

            [HttpPost]
        public ActionResult PersonRecivedHisPassport(int passID, FormCollection form)
       
    {
                    Person person = repository.RecivedHisPassport(passID);
                    if (person != null)
           
        {
                            TempData["message"] = string.Format("{0} OK", person.Name);
                            return RedirectToAction("Index");
                       
        }
                    else            
        {
                            return View("NotFound");
                       
        }
               
    }
       
}
```

لا تنسى استدعاء فضاء الاسماء التالي:

```csharp
using MvcExplain.Models;
using MvcExplain.Repo;
```

لدينا ثلاثة أساليب واحد يُعني بإرجاع جميع المواطنين والثاني يُعني بالبحث عن مواطن نريد أن نقوم بتسليمه لجوازه والثالث بقوم بتنفيذ الإسلوب RecivedHisPassport الذي أنشأناه في فئة الـ PersonDbContect والذي مهمته تغيير حقلي الـ Recived والـ RecivedDate في قاعدة البيانات.

قم بالضغط على مرتين Double-Click بالمؤشر (ماوس) على ملف الـ Content ستجد بداخله ملف لتنسيق صفحات الـ Html واسمه Site.css قم بفتحه ولصق الشفرة التالية بداخله:

```css
TABLE.Grid TD, TABLE.Grid TH { border-bottom: 1px dotted gray; text-align:left; }
TABLE.Grid {border-collapse: collapse;width:50%; margin:30px 0 0 100px;}
TABLE.Grid TH.NumericCol, Table.Grid TD.NumericCol {text-align: right; padding-right: 1em; }
#mainform {}
#searchform { margin:120px 0 0 400px;}
DIV.searchresults  {margin:120px 0 0 400px; font-size:x-large;}
input.text {width:50%;padding:16px 20px;box-sizing:border-box;border:2px solid red;border-radius:5px;font-size:x-large;}
input.button {width:50%; padding:8px 32px; box-sizing:border-box;font-size:x-large;}
```

> *ملاحظة: دائما إذا كنت تريد أداء أفضل لتطبيقك قم بكتابة خصائص ملف الـ* *Css* *في سطر واحد بالنسة للـ Element.*

قم بفتح ملف الـ \_Layout.chtml وستجده في ملف الـ Views داخل ملف الـ Shared وقم بلصق الكود التالي داخل الـ Element التي تُسمى Body:

```markup
<div id="messagetemp">
        @if (TempData["message"] != null)
        {
             <div class="message" style="background:green;color:white;padding:.2em;margin-top:.25em">
            @TempData["message"]
        </div>
        }
            <div class="savemessage">
                @if (TempData["savemessage"] != null)
        {
             <div class="message" style="background:green;color:white;padding:.2em;margin-top:.25em">
            @TempData["savemessage"]
            </div>
        }
    </div>
            </div>
```

في الشفرة أعلاه قمنا بإستخدام الخاصية TempData لحالتين لدينا كإشعار في حال تم تسليم المواطن لجوازه في حال تم استلام جواز لمواطن ما..وتلك الخاصية في بيئة الـ MVC ترث من TempDataDictionary وكما معروف عنها تحميل قيمتان على هذا المنوال Key-Vlaue وصفحة الـ \_Layout.chtml تعتبر مثل صفحة الـ master page في الـ ASP.NET Web Form وستقرأ هذه الرسالة من الأسلوبين الموجودين في فئتي التحكم HomeController والـ AdminControler والتي سنضيفها لاحقا.

قم بفتح ملف الـ RouteConfig.cs والذي ستجده في ملف الـ App\_Start وقم بلصق الكود الشفرة التالية داخل الأسلوب RegisterRoutes:

```csharp
     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "PassRecive",
                url: "person/recivehispassport/{passID}",
                defaults: new { controller = "Person", action = "PersonRecivedHisPassport", passID = (int?)null
}
                );

            routes.MapRoute(
                name: "EditExcitePersonInfo",
                url: "person/passport/Edit/{personId}",
                defaults: new { controller = "Admin", action = "EditPersonInfo", personId = (int?)null
}
                );

            routes.MapRoute(
                name: "CreateNewPersonInfo",
                url: "person/passport",
                defaults: new { controller = "Admin", action = "CreatePersonInfo" }
                );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new {
    controller = "Person", action = "Index", id = UrlParameter.Optional
}
            );
```

هنا قمنا بإضافة أربعة عناوين وصول..الأول لصفحة تسليم الجواز والثاني لتعديل بيانات مواطن والثالث لإنشاء بيانات جديدة لمواطن ما..والأخير للصفحة الرئيسية التي لدينا.

> *ملاحظة: الكثير من المبرمجين لا يقومون بإستخدام عناوين وصول مشابهة للأساليب التي ينشؤونها في فئات التحكم بل يقومون بإستخدام عنوان الوصول الإفتراضي الذي ينشئه الفيجوال ستديو...من خلال خبرتنا العملية أود أن تأكيد أن إنشاء عناوين وصول خاصة بك سيسهل عملية البحث في موقع بالنسبة للزوار الذين يستخدمون محركات البحث كـ* *Google* *و* *Bing* *وهذا ما يعرف بالـ* *SEO* *وهي إختصار لـ* ***S*** *earch *E*ngine *O*ptimization*   *وتعريف بتحسين البحث على محركات البحث والتي تتم عن طريق إنشاء عناوين الوصول الخاصة بك على مشروعك.*

الآن سننشئ صقحة الـ Html الأولى وهي صفحة الـ Index

قم بفح الـ HomeContoller التي أنشأناها سابقا وقم بالضغط بالزر الأيمن للمؤشر (ماوس) على الإسلوب Index وقم بالضغط على OK سيقوم الفيجوال ستديو بإنشاء صفحة بإسم Index داخل الملف Person والذي بدروه أنشئ داخل الملف Views

> *ملاحظة: هذه طريقة متبعة* *Convention* *في تقنية الـ* *MVC* *وهي كالتراتيبية للملفات والحرف الأوسط لتلك التقنية حرف الـ* *V* *والذي يعني* *View* *الخاص بالصفحات التي تم إنشاءها في الحرف الأخير* *C* *والتي تعني الـ* *Controller*   *والتي بدورها تقرأ جميع بيناتها من الحرف الأول* *M* *التي تُعنى بالفئات داخل الـ* *Models* *هذا ببساطة شديدة.*

قم بلصق الشفرة التالية داخل صفحة الـ Index:

```csharp
@model IEnumerable<MvcExplain.Models.Person>

    @ {
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<div id="mainform">
@using (Ajax.BeginForm("SerachForPerson", "Person",
    new AjaxOptions {
     InsertionMode=InsertionMode.Replace,
     HttpMethod="GET",
     UpdateTargetId="searchresults",              
}))

{
   <div id="searchform">
 <input type="text" name="q" class="text"/><br /><br />
 <input type="submit" value="Search" class="button" />
   </div>  
}
</div>
<div id="searchresults">
</div>
```

هذه الصفحة يوجد بها مربع نص وزر إدخال يقوم ومهمته البحث عن مواطن عن طريق رقمه الوطني..قم بإنشاء صفحة Html أخرى بنفس الطريقة السابقة وقم بتسميتها NotFound وقم بلصق الشفرة التالية داخلها:

```csharp
@ {
    ViewBag.Title = "NotFound";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>NotFound</h2>
    <h1>Sorry There is somthing <i>ERROR</i></h1>
```

وتلك صفحة تعنى بإظهار أي خطأ يحدث في حال قام المستخدم بإدخال رقم وطني خاطئ لمواطن ما.

قم بالضغط بالزر الأيمن للمؤشر (ماوس) فوق ملف الـ Person الموجود داخل الملف Views وقم بإختيار Add وإختيار View كما موضح بالصورة التالية وقم بكتابة اسم الصفحة HasRecived وقم بالضغط على OK.

![](https://informatic-ar.com/wp-content/uploads/2018/06/4-300x218.png)

> *ملاحظة: هذه طريقة أخرى أيضا لإنشاء صفحات الـ* *Html* *إذا كنت لا تريد إنشائها بالطريقة الأولى..الآن لقد وضحت لديك طريقة إنشاء صفحات الـ* *Html* *في المرات القادمة لن أشير لكيفية طريقة إنشائها..فقط سأقول لك أنشئ صفحة* *Html* *وأعطها الإسم (...).*

قم بنسخ الشفرة التالية داخل ملف الـ HasRecived.cshtml:

```csharp
@ {
    ViewBag.Title = "HasRecived";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>HasRecived</h2>
<hr />
<h1><i>Sorry</i> This person has <i>Recived</i> his passport!</h1>
```

وهذه الصفحة تُعني في حال تم إدخال رقم وطني لموطن وقد قام بإستلام جواز مسبقا ستقوم بتوضيح أن هذا المواطن قد استلم جوازه وفي التاريخ الفلاني.

قم بالضغط على ملف Shared بالزر الأيمن للمؤشر (ماوس) وقم بإختيار Add à View وقم بتسميتها \_PersonShearch وقم بالضغط على المربع Create as a partial view وقم بالضغط على Ok

![](https://informatic-ar.com/wp-content/uploads/2018/06/5-300x295.png)

وقم بلصق الشفرة التالية بداخلها:

```markup
@model MvcExplain.Models.Person

@{
    ViewBag.Title = "Result";
    Layout = "~/Views/Shared/_Layout.cshtml";
    }

<div class="searchresults">
    <ul>
        <li>@Model.Name</li>
        <li>@Model.NID</li>
        <li>@Model.Recived</li> |
        <li>
 @Html.ActionLink("please Perss here","PersonRecivedHisPassport",new {passID=Model.PersonID})
        </li>
        <li>@Html.RouteLink("Go", "PassRecive", new { passID = Model.PersonID }) | @Model.Recived</li>
    </ul>
</div>
```

وهذه الصفحة تُعنى بنتيجة البحث عن مواطن لم يستلم جوازه..وهي من النوع Partial أي هي ليست صفحة Html متكاملة بمعني ستظهر كجزء من صفحة أخرى...وهي شبيهة بصفحات الـ User Control في الـ ASP.NET Web Form.

الصفحة الأخيرة والتنفيذية والتي بها خاصية تسليم المواطن لجوازه والتي اسمها PersonRecivedHisPassport.chtml ..قم بإنشائها وقم بلصق الشفرة التالية عليها:

```csharp
@model MvcExplain.Models.Person

    @ {
    ViewBag.Title = "PersonRecivedHisPassport";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>PersonRecivedHisPassport</h2>
<hr />
<div id="recivedform">
    @using (Html.BeginForm())
    {
    <p>
        <input type="submit" value="Recive" /> |
        @Html.ActionLink("Back to Search Page", "Index")
    </p>
    }
</div>
<hr />
```

هنيئا لك...الآن لقد أنتهيت من تنفيذ 80% من التطبيق..لدينا خطوة أخيرة وهي تثبيت أداة تُسمى Glimpse وهي أداة جميلة ومهمة جدا دائما ما نستخدمها في تطبيقاتنا وسنستفيد من تلك الأداة في رؤية عناوين الوصول الخاصة بنا التي ستسخدمها الصفحات من خلال المتصفح ومنها سنتأكد هل ستقوم الـ MVC Framework بإختيار روابط الوصول من ملف الـ RouteConfig.cs بصورة صحيحة كما قمنا بتهيئتها.

قم بالضغط بالزر الأيمن للمؤشر (ماوس) وقم بإختيار Manage Nuget Packages ستفتح معك شاشة..قم بإدخال كلمة Glimpse على يمين الشاشة في مربع البحث واضغط Enter ستجد مكتبة Glimpse.mvc4 قم بتثبيت تلك المكتبة... بعد الإنتهاء من تثبيتها قم تشغيل التطبيق لتعمل عليه الآن.

بعد أن تقوم بتشغيل التطبيق قم بكتابة السطر التالي على رابط التطبيق..لتقوم بإعطاء مكتبة Glimpse خاصية العمل مع تطبيق...(عليك بتوقيف عمل تلك المكتبة عندما تقرر نشر تطبيقك على موقع الإستضافة الذي ستستخدمه Web server)

```csharp
http: //localhost:58419/glimpse.axd
```

بعد كتابة هذا السطر ستفتح معك صفحة تستطيع من خلالها بدء وتوقيف عمل تلك المكتبة. قم بالضغط على Turn Glimpse on كما موضح بالصورة.

![](https://informatic-ar.com/wp-content/uploads/2018/06/6-300x188.png)

والآن بإمكانك كتابة الرابط التالي على رابط الوصول في متصفحة لفتح الصفحة الرئيسية للتطبيق:

```csharp
http: //localhost:58419/Person/Index
```

لا تنسى سيكون عنوان المنفذ مختلفا..لأنني استخدم الـ IIS Express والذي يقوم بتغيير عنوان المنفذ في كل مرة او في كل تطبيق مختلف.

سيكون التطبيق على تلك الشاكلة كما مبين في تلك الصورة

![](https://informatic-ar.com/wp-content/uploads/2018/06/7-300x188.png)

..قم بإدخال الرقم 123-87847-888 في مربع النص وقم بالضغط على Search ستظهر معك تفاصيل المواطن الذي اسمه Mohammed قم بالضغط على please press here أو بالضغط على Go ستنقلك لصفحة تنفيذ استعلام تسليم الجواز..بالمناسبة الرابطين الموضحين هنا هما يؤديان نفس المهمة فقط قمت بكتابتهما مرتين لأوضح لك الـ Html Helper الخاصة بعناوين الوصول ففي الأول استخدمت Html.RouteLink والذي يقرأ اسم العنوان من ملف الـ RouteConfig.cs والثاني استخدمت فيه Html.ActionLink والذي يقرأ من فئة التحكم الـ HomeController.

لو لاحظت أيضا في الصورة السابقة شكل مكتبة Glimpse وبتمريرك المؤشر (ماوس) على تبويب الـ Views سيظهر لك الوقت الذي أخذته الصفحة في عملية التنفيذ وستظهر لك عنوان الوصول الذي قام الـ MVC Framework بإختياره.

الآن بإمكانك تجريب التطبيق بالبحث عن المواطنين وتسليمهم الجوازات.

> *ملاحظة لا تنسى لقد تبقى لدينا مهمتين مهة إدارة قاعدة البيانات وعمل إختبار* *Unit Tests* *للشفرات..!!*

**الجزء الثاني – إدارة التطبيق**

قم بإنشاء فئة تحكم Controller جديدة وقم بإعطاءها الإسم AdminController وقم بلصق الشفرة تلك بداخلها:

```c
public class AdminController : Controller
   
{
            private IPerson _repository;
            public AdminController(IPerson repo)
       
    {
                    _repository = repo;
               
    }
            //
        // GET: /Admin/
        public ViewResult Index()
       
    {
                    return View(_repository.GetAllPersons.Where(p = > p.Recived == false));
               
    }

            [HttpGet]
        public ViewResult EditPersonInfo(int personId)
       
    {
                    Person person = _repository.GetPersonByID(personId);
                    return View(person);
               
    }

            [HttpPost]
        public ActionResult EditPersonInfo(Person person)
       
    {
                    if (ModelState.IsValid)
           
        {
                            _repository.SavePassportInfo(person);
                            TempData["savemessage"] =
                string.Format("{0} has been saved ", person.Name);
                            return RedirectToAction("Index", "Person");
                       
        }

                    else            
        {
                            return View(person);
                       
        }
               
    }

            public ViewResult CreatePersonInfo()
       
    {
                    return View("EditPersonInfo", new Person());
               
    }
       
}
```

لا تنسى استدعاء فضاء الاسماء التالي:

```csharp
using MvcExplain.Models;
using MvcExplain.Repo;
```

في هذه الفئة لدينا ثلاثة أساليب الاولى لعرض جميع المواطنين الذين لم يستلموا جوازاتهم والثانية لتعديل بيانات مواطن موجود لدينا..والثالثة لحفظ بيانات مواطن جديد.

> *لاحظ في الإسلوب الأول* *Index* *لقد قمت بإستخدام الجملة التنفيذية داخل الإسلوب نفسه وهذه طريقة خاطئة لانه من المفترض علىّ ان انقل هذا التنفيد* *Logic* *داخل الواجهة* *IPerson* *واقوم بعمل التنفيذ داخل ملف الـ* *PersonRepository.cs* *والذي يرث من الـ* *IPerson* *وأقوم بإستدعاء داخل فئة التحكم* *AdminController*   *مثيل الواحهة* *\_repository* *بإمكانك عمل تلك العملية للتأكيد على قدرة إستيعابك لما قمنها بعمله على هذا التطبيق. وتلك الجملة بسيطة تستخدم الـ* *Restriction operator* *وهي جملة* *where* *في تنقية* *LinQ* *وهي شبيهة بجملة* *where* *في قواعد البيانات* *SQL* *وتقوم بعمل تنقيب في مجموعة بيانات محتملة وتقوم بإرجاع قيمة مطابقة للشرط الذي تأخذه في المعامل الخاص بها* *parameter* *.*

قم بإنشاء صفحة Html للإسلوب Index وقم بلصق الشفرة التالية داخله:

```csharp
@model IEnumerable<MvcExplain.Models.Person> @ {
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2> Admin Page</ h2> @Html.RouteLink("Go To Add New Info",
                                      "CreateNewPersonInfo")<div id = "persons">
    < table class
= "Grid" >
        <tr>
        <th> Person</ th>
        <th> NID</ th>
        <th> Status</ th>
           </ tr>
        @ foreach (var p in Model)
       
{
            <tr>
            <td> @Html
        .RouteLink(p.Name, "EditExcitePersonInfo", new { personId = p.PersonID })</ td>          
             <td> @p.NID</ td>
             <td> @p.Recived</ td>
             </ tr>
       
}
    </ table></ div>
```

وصفحة أخري لـ EditPersonInfo وقم بلصق الشفرة التالية داخلها:

```csharp
@model MvcExplain.Models.Person

    @ {
    ViewBag.Title = "EditPersonInfo";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2> EditPersonInfo</ h2> @using(Html.BeginForm("EditPersonInfo", "Admin"))
{
    @Html.EditorForModel();
        <input type = "submit" value = "Save" />
    @Html.ActionLink("Cancel", "Index")
}
```

الإسلوب CreatePersonInfo لن يحتاج لصفحة Html لأنه سيقوم بإستدعاء صفحة الـ EditPersonInfo وإذا رأيت في في الإسلوب بأننا قمنا بإسناد كائن الـ Person لتقوم الصفحة بإرجاعه من خلال صفحة التعديل كالتالي:

```csharp
return View("EditPersonInfo", new Person());
```

الـ MVC Framewrok تقوم بإستخدام الـ Command pattern لإرجاع صفحات الـ Hmlt.

أخيرا قم بفتح ملف الـ Global.asax وقم بلصق الشفرة التالية داخل الإسلوب Application\_Start:

```csharp
ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new RazorViewEngine());
```

تلك الشفرة ستحسن من عمل التطبيق ولأن منصة الـ MVC لديها محركين للعمل على صفحات الـ HTML وهما الـ Razor والـ Web Form وعند تشغيلك للتطبيق ستقوم المنصة بالبحث بالمحركين عن صفحة الـ Index وهذه ستأخذ وقت إضافي..لكن بكتبابتنا لتلك الشفرة السابقة قمنا بإخبار منصة الـ MVC بإن تقوم بعمل تنظيف لجميع محركات إنشاء الـ HTML وثانيا أخبرناها بإنشاء المحرك Razor فقط ليعمل مع التطبيق..وإذا كنت تذكر في بدابة هذا التطبيق عندما أنشأناه لقد إخترنا الـ View Engine الخاص بتطبيقنا هو الـ Razor.

الآن بإمكانك تشغيل التطبيق وكتابة الرابط التالي:

```csharp
http: //localhost:58419/admin/index
```

لا تنسى سيكون المنفذ مختلفا..هذه الصفحة ستعرض جميع بيانات المواطنين الذي لم يستلموا جوازاتهم..وبإمكانك من تلك الصفحة إضافة بيانات مواطن جديد...والتعديل على بيانات موجودة مسبقا.

**الجزء الثالث – عمل أختبار للشفرات** **Unit tests**

كثير من المبرمجين لا يقومون بالقيام بإختبار شفراتهم؛ وهذا خطأ كبير ولأن اختبار الشفرات مهم جدا وكما متعارف عليه في اختبار شفرات بيئة الـ MVC Framework يُقال لك أقلّاها عليك اختبار روابط عناوين الوصول لتطبيقك لأنه إن لا كانت لا تعمل لن يعمل تطبيق أبدا.

قم بالضغط على الـ Solution وليس اسم التطبيق وقم بإنشاء مشروع جديد كما موضح بالصورة التالية:

![](https://informatic-ar.com/wp-content/uploads/2018/06/8-300x197.png)

قم بإختيار Test من على يسار الشاشة وإختيار Unit Test Project كما موضح بالصورة وقم بتسمية المشروع PersonData.UnitTests واضغط Ok.

![](https://informatic-ar.com/wp-content/uploads/2018/06/9-300x185.png)

قم بالضغط على خيار References من داخل المشروع الذي أنشأته مؤخرا وقم بالضغط على Add References من يسار الشاشة إختار Solution وستجد مشروع الـ MvcExplain قم بإختياره ثم قم بضغط OK.

في تلك الخطوة قمنا بربط مشروع إختبار الشفرات بمشروعنا الفعلي وذلك حت نقوم بعمل إختبار لأجزاءه بالطريقة التي نريدها

اضغط على TOOLS في اعلى الشريط المساعد الخاص بالفيجوال واختار الـ Library Package Manager والتي ستظهر لك خيارات عدة إضغط على اول خيار Package Manager Console واكتب السطر التالي:

```csharp
PM > Install - Package Moq - version 4.0.10827
```

هنا قمنا بتنزيل مكتبة الـ Moq وهي مكتبة تتيح لنا إنشاء بيانات وهمية في حال أردنا إختبار شفراتنا بدلا من اغختبارها ببيانات حقيقية من داخل قاعدة البيانات وذلك لأنها ستزيد من بطء النظام لذلك نقوم بإستخدام تلك المكتبة.

في شفرات الإختبار تلك لقد قمت بعمل إختبار لفئة التحكم PersonController وفئة الـ RouteConfige.cs فقط ولم أقم بعمل إختبار لجميع الأكواد.

عند إنشائك لمشروع اختبار البرمجيات سيقوم الفيجوال ستديو بإنشاء فئة Class بإسم UnitTest1 سنقوم بكتابة شفرتنا عليها...لكن لا تفعل ذلك في برمجياتك الرسمية والكبيرة...فمثلا إذا أردت إختبار فئة التحكم AdminController قم بإنشاء فئة اسمها AdminControllerUnitTest حتى يكون عملك محترفا ومقبولا..ولا تنسى بأنه قد تترك العمل في الشركة التي تعمل بها وبالتالي هذا يعني تسهيلك للمطورين والمبرمجين الذي سيأتون من بعدك سيكون عليهم سهلا معرفة الأكواد التي كتبتها وهذا ما يعرف بأخلاقيات العمل (قم بالإطلاع على مواضيع **هندسة البرمجيات** على الإنترنت).

في تلك الفئة UnitTest1 قم بإستدعا فضاء الإسماء التالي:

```csharp
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using Moq;
using System.Collections;
using System.Collections.Generic;
using System.Web.Mvc;
using MvcExplain.Models;
using MvcExplain.Repo;
using MvcExplain.Controllers;
using System.Web.Routing;
```

وقم بكتابة الشفرة التالية داخل تلك الفئة:

```csharp
[TestClass]
    public class UnitTest1
   
{
            [TestMethod]
        public void Can_List_AllPersonInMainPage()
       
    {
                    Mock<IPerson> mock = new Mock<IPerson>();
                    mock.Setup(m => m.GetAllPersons).Returns(new Person[] {
                new Person { PersonID = 1, Name = "Mohammed", NID = "23-1234", Recived = false },
                new Person { PersonID = 2, Name = "Ahmed", NID = "23-1235", Recived = true },
                new Person { PersonID = 3, Name = "Hussien", NID = "23-1236", Recived = true },
                new Person { PersonID = 4, Name = "babiker", NID = "23-1237", Recived = true },
                new Person { PersonID = 5, Name = "Ali", NID = "23-1238", Recived = false },
                new Person { PersonID = 6, Name = "Khalid", NID = "23-1239", Recived = false }
        }.AsQueryable());

                    PersonController target = new PersonController(mock.Object);

                    //ViewResult result = target.Index() as ViewResult;
            IEnumerable<Person> result = (IEnumerable<Person>)target.Index().Model;
                   
            Person[] personData = result.ToArray();

                    // Assert
            Assert.IsNotNull(result);
                    Assert.IsTrue(personData.Length == 6);
                    Assert.AreEqual(personData[0].Name, "Mohammed");
                           
       
    }

            [TestMethod]
        public void Can_SearchForSpesificPerson_ByHidsNID()
       
    {
                    // Arrange
            Mock<IPerson> mock = new Mock<IPerson>();
                    // Arrange - Initil obj
           Person n = new Person { NID = "23-1234" };
                    // Action
           PersonController target = new PersonController(mock.Object);

                    // Action
           ActionResult result = target.SerachForPerson("23-1234") as ViewResult;

                   Assert.IsNotNull(result);
                   Assert.AreEqual("23-1234", n.NID);
               
    }

            [TestMethod]
        public void WhenYouWantToRecivePassPort_Return_HasRecived_View()
       
    {
                    Mock<IPerson> mock = new Mock<IPerson>();
                    PersonController target = new PersonController(mock.Object);
                    Person person = new Person { Recived = false };

                    ViewResult result = target.PersonRecivedHisPassport(person.PersonID);

                    Assert.AreEqual("HasRecived", result.ViewName);
               
    }

            [TestMethod]
        public void PersonHasBeenRecived_ShouldReturnTrue_WhenNotRecive()
        
    {
                    Mock<IPerson> mock = new Mock<IPerson>();

                    // Arrange
            PersonController target = new PersonController(mock.Object);

                    Person rec = new Person { Recived = false };
                    //int p = 1;
            ActionResult result = target.PersonRecivedHisPassport(rec.PersonID, null);

                    mock.Verify(m => m.RecivedHisPassport(rec.PersonID));
                    Assert.IsInstanceOfType(result, typeof(ViewResult));
               
    }

            [TestMethod]
        public void RouteToHomePage()
       
    {
                    // Arrange
            var mockContext = new Mock<HttpContextBase>();

                    mockContext.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath)
            .Returns("~/");
                    // Arrange
            var routes = new RouteCollection();
                    MvcExplain.RouteConfig.RegisterRoutes(routes);
                    RouteData routeData = routes.GetRouteData(mockContext.Object);

                    // Assert
            Assert.IsNotNull(routeData);
                    Assert.AreEqual("Person", routeData.Values["controller"]);
                    Assert.AreEqual("Index", routeData.Values["action"]);
                    Assert.AreEqual(UrlParameter.Optional, routeData.Values["id"]);
               
    }

            [TestMethod]
        public void RouteToPassRecivePage()
       
    {
                    var mockContext = new Mock<HttpContextBase>();

                    mockContext.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath)
            .Returns("~/person/recivehispassport");

                    var routes = new RouteCollection();
                    MvcExplain.RouteConfig.RegisterRoutes(routes);
                    RouteData routeData = routes.GetRouteData(mockContext.Object);

                    Assert.IsNotNull(routeData);
                    Assert.AreEqual("Person", routeData.Values["controller"]);
                    Assert.AreEqual("PersonRecivedHisPassport", routeData.Values["action"]);
               
    }
       
}
```

لإختبار تلك الشفرة ورؤيتها تعمل بصورة صحيحة قم بالضغط على Testعلى شريط الأدوات في فيجوال ستديو وقم بإختيار Windows ومنها إختار Test Explorer ستفتح معك شاشة على يسار الفيجوال ستديو...قم بالضغط على Run All سيقوم الفيجوال ستديو بعمل بناء للتطبيق Build وسيقوم بالتأكد من عمل الأكواد التي قمت بكتابتها وستعطيك إشارة خضراء إذا كانت الأكواد تعمل بصورة صحيحة ... وإشارة حمراء إن كان هناك خطأ.

وكما موضح بالصورة التالية أن جميع الأكواد التي إختبرناها تعمل بشكل جيّد.

![](https://informatic-ar.com/wp-content/uploads/2018/06/10-248x300.png)

في هذه الفئة قمنا بعمل اختبار للصفحة الرئيسية وصفحة تسليم الجوازات...أيضا قمنا بالتأكد من من صفحة الـ Index تقوم بإرجاع جميع البيانات الموجودة بقاعدة البيانات..أيضا اختبرنا اسلوب نتيجة البحث...وأيضا في حالة كنا نريد تسليم مواطن لجواز اختبرنا ان ذلك الاسلوب سيقوم بإرجاع الصفحة المخصصة لذلك واخيرا اختبرنا تنفيذ الـ Logic الخاص بتسليم الجواز للمواطن من تغيير False الي True في حقل قاعدة البيانات.

توجد في فضاء الاسماء التالي العديد من الخواص على سبيل المثال منها TestClass والتي تبين ان الفئة تلك تحت الإختبار وسيكون بها العديد من الأساليب التي سيتم إختبارها..وأي اسلوب سيتم أختباره لابد أن يبلور بالخاصية TestMethod,

```csharp
using Microsoft.VisualStudio.TestTools.UnitTesting;
```

تحياتي.