حماية خدمات WCF ( الجزء الثاني )

مرحبا, تحدث في المقالة السابقة كيف يمكن بناء Ceritifcate و تثبيتها على جهاز العميل و الخادم من اجل بدء العمل مع حماية خدمات الويب من خلال استخدام الـ Ceritifcate , في هذا الجزء سنبدأ العمل مع هذه الشهادات, سوف نقوم ببناء خدمات ويب Hello Ceritifacte و التي تحتوي على الطريقة SayHello.

في البداية سأحتاج لتسجل شهادة العميل في قائمة الشهادة الموثوقة حيث سيرسل العميل هذه الشهادة مع كل طلب, أيضا سأحتاج تثبيت شهادة الخادم في المتجر MY الخاص بـ Local Computer حيث ستقوم الخدمة بأرسال هذه الشهادة إلى العميل و نفس الامر سنقوم بعمله و لكن بعكس الشهادات , بمعنى سنتثبت شهادة الخادم في جهات الموثوقة عند العميل و شهادة العميل في المتجر MY الخاص بـ Local Computer , ربما توضح الصورة الفكرة اكثر:

1- شهادة الخادم مثبتة في متجر Personel في الحاسب Local Computer .

Server

2- شهادة العميل مثبته في Truseted People  في الحساب Local Computer :

Client

الأن نأتي للعميل:

1- شهادة العميل مثبتة في المتجر MY في الحساب Local Computer:

Client

2- شهادة الخادم مثبتة في الجهات الموثوقة عند العميل:

 

server

بهذا نكون قد انتهينا بـ 50% من العمل , الأن نحتاج إلى أمرين , الأول من الخادم , حيث يجب أن نخبر الـ WCF بأنها ستستخدم الـ Ceritifcate كطبقة أمان و أن العميل يجب أن يزودني بهذه الشهادة, أيضا يجب على الخدمة أن توفر للعميل شهادة من طرفها, لعمل ذلك سنحتاج إلى endpoint و service behaviros و binding , نبدأ من الاساس:

الأول الـ : Binding

Binding

نحن في الـ Bindings نخبر العميل بأننا سنستخدم الـ Certificate كوسيلة للحماية, نأتي الأن إلى الـ Service Behaviros:

bahiver

هنا اقوم بإنشاء Service Bahaviors جديدة و امنحها الاسم الـ LoadCertitifate حيث تطلب هذه الخدمة من العميل شهادة على أن تكون مسجلة في الـ Trust او Personel , اخيرا يقوم الـ Bahaviors بتمرير الشهادة التي تحمل الاسم HelloCeritifcateServer إلى العميل.

النقطة الأخير علينا الأن إنشاء endpoint و ربطها بهذه الاعدادات , الشفرة:

end point

الأن الخدمة جاهزة للعمل, يمكنك باستخدام معالج Add Service References استدعاء الرابط , سينتج عند العميل أمر مشابه لهذا :

Certificate

اذا قمت الأن بتشغيل التطبيق , ستخبرك الخدمة بأنها بحاجة إلى شهادة موثقة للعمل, الصورة :

Cleint

الأن لتزويد الخدمة بشهادة سنحتاج إلى Bahavior , الشفرة:

client cert

الأن اذا حولت ارسال شهادة سينجح الأمر, الصورة:

 

Client Test

الأن اذا حذفنا الشهادة من قائمة الموثوقين في الخادم , سنجد بأنه ليس لدينا الصلاحية للوصول للخدمة:

error

ما زال لدينا مشكلة في حتى هذه النقطة , المشكلة أن الخدمة تثق بأي شهادة موجودة في الـ Trusted نحمل الاسم HellleCeritifcateClient و هذا الأمر طبعا غير صحيح عليا ان نتحقق بأن الشهادة المرسلة هي فعلا الشهادة التي نغرب بها لعمل ذلك سنحتاج التحقق بشكل يدوي.

1- في البداية سنحتاج إنشاء عملية توثيق يدوية و ذلك من خلال اشتقاق الكائن CertificateValidator من الكائن X509CertificateValidator هذا الكائن بدوره عبارة عن abstrac و لذك سيجبرك على وجود الطريقة Validate التي تستقبل الشهادة المرسلة من العميل, كل ما أحتاج فعله عن اذا هو التحقق من أن رقم Serial Number له متوافق مع الشهادة الموثقة , الشفرة:

Server sss

الأن و في ملف الـ Web.Config عليا أن اخبر الـ WCF باستخدام هذا التصنيف بدلا عن التصنيف الافتراضي , الشفرة:

 

khdsfkjsf

لاحظ في الشفرة التي في الأعلى أنني اخزن قيمة الشهادة في ملف الـ Web.Config , الشفرة:

lkglkge

و بهذا ليس فحسب يجب أن تكون الشهادة موجودة في قائمة Truested people بل أيضا يجب أن يكون الـ SerailNumber الخاص بها مساوي للقيمة التي في الأعلى, مازالت هناك مشكلة قائمة, حيث أن الشفرة التي في الأعلى تفترض أن الشهادات التي ستستقبلها شهادة واحدة فقط , بمعنى أن جميع التطبيق التي ستستخدم هذه الخدمة يجب ان تمرر نفس الشهادة , و هذا طبعا غير صحيح, لحل هذه المشكلة علينا إنشاء مصفوفة من الـ Serail Number و من ثم المرور على قيم هذه المصفوفة و البحث عن عنصر مطابقة لشهادة التي يتم يتمر تمريرها مع كل Requets الشفرة:

array

التغير الذي قمت به في الشفرة بسيط جدا, في البداية انا استخدم علامة " ; " للفصل بين كل Serail Number و اخر, ثم اقوم بالبحث عن الـ Serail Number داخل المصفوفة و مقارنته مع قيمة  الـ Serail Number الخاص بالشهادة اذا لم أعثر في المصفوفة على شيء مطابقة اقوم برمي استثناء بأن الشهادة غير موثقة, ملف الـ Web.Config :

=Cert 2

بهذا اكون قد انتهيت تقريبا من العمل مع الشهادات و WCF في المقالة القادمة سأتحدث كيف يمكنك استخدام كلمة المرور و اسم المستخدم مع WCF.

حماية خدمات WCF ( الجزء الأول )

مرحبا, سأتحدث في مجموعة من المقالات عن حماية خدمات الويب ( WCF ) على مختلف المستويات, ستتطرق هذه المقالات إلى النقاط التالية:

  • تأمين خدمات WCF باستخدام الـ Certificate .
  • تأمين خدمات الـ WCF باستخدام اسم مستخدم و كلمة المرور.
  • تأمين خدمات الـ WCF باستخدام الـ Certificate  واسم المستخدم و كلمة  المرور.
  • تامين خدمات الـ WCF باستخدام الـ Certificate  و اسم المستخدم و كلمة المرور و التشفير الثنائي العشوائي.

حتى نتمكن من إكمال العمل علينا في البداية الحصول على الشهادات الازمة للعمل, سواء الـ Root أو شهادة الـ Server او شهادة الـ Client , سيكون حديثنا في الجزء الأول عن إنشاء هذه الشهادات الثلاثة, و تثبيتها الخادم و العميل.

إنشاء شهادة الـ Certificate Authority :

في معظم الأحيان تستطيع الشركة أو المنظمة التي تعمل بها توفير شهادة موثقة من أحد الجهات مثل ( GoDaDay او Verisign) و غيرها من الشركات, و لكن قد تكون العملية مكلفة اذا ما احتجنا إلى شهادة مع كل تطبيق نحتاج إلى تطويره, لذلك يمكنك إنشاء شهادة حقيقة و لكن بوجود الـ Authority  خاصة بك, سيعمل الأمر بشكل أكثر من جيد و تؤدي هذه الشهادة الغرض المطلوب منها في توثيق و تشفير الاتصال و بيانات التي تنقل من خلالها العيب الوحيد في هذه الشهادة هو أنها ستكون حمراء طيلة الوقت, على أية حال لا تستخدم هذه التعليمات عند الانتقال إلى بيئة الانتاج.

افتح المفكرة, و انسخ الشفرة التالية:

   1: makecert.exe ^
   2: -n "CN=ALGHABBAN" ^
   3: -r ^
   4: -pe ^
   5: -a sha512 ^
   6: -len 4096 ^
   7: -cy authority ^
   8: -sv CARoot.pvk ^
   9: CARoot.cer
  10:  
  11: pvk2pfx.exe ^
  12: -pvk CARoot.pvk ^
  13: -spc CARoot.cer ^
  14: -pfx CARoot.pfx ^
  15: -po Test123


في المعامل –n يمكنك تمرير بيانات الشهادة إليك التفاصيل:


CN= اسم المنظمة التي وقعت الشهادة.


UO= القسم في المنظمة الذي سيستخدم الشهادة.


O= اسم المنظمة المستفيذة من الشهادة


L= مكان أو الحي الخاص بالمنظمة المستفيده من الشهادة.


S= الولاية للمنظمة المستفيده من الشهادة.


C= الدولة


يجب أن تلاحظ هنا بأن المتغير –po بأنه يستقبل علامة ** و هنا كلمة المرور الخاصة بهذه الشهادة و التي ستستخدمها لاحقا عند استيرادها في IIS مثلا, –pe و يعني أن المفتاح الخاصة بهذه الشهادة سيتم تولديه تلقائيا و تخزينه داخل الشهادة, –a نوع الهاش و –len طول التشفير, اسم الشهادة سوف يكون CARoot.cer و اسم ملف المفتاح سيكون CARoot.pvk .


الأن احفظ الملف باسم CARoot.cmd داخل المجلد في الاسفل,  الان افتح CMD و انت administrator  و توجه إلى الرابط المجلد التالي:


C:\Program Files (x86)\Windows Kits\8.0\bin\x64


اكتب اسم الملف و انتظر قليلا, ستظهر نافذة تطلب من كلمة المرور اضغط على None فلا فائدة منها تذكر كوني قمت بتزويد الشهادة فعلا بكلمة مرور من قبل من خلال المعامل po.


none


عد إلى المجلد C:\Program Files (x86)\Windows Kits\8.0\bin\x64 و قم بترتيب الملفت حسب تاريخ التعديل, الاحدث في الاعلى, مبروك يجب أن تشاهد الأن شهادة الـ Root كما ترى في الصورة في الاسفل:


ALGHABBAN Cert


 


في الحقيقة لا فائدة تذكر من الـ Root حقيقة :-) سوا أنك ستستخدم الـ Root من أجل أصدارة الشهادة المختلفة, سواء للعميل أو الخادم في كلا الحالتين أن ستقوم بأرسال الـ Root للعميل و الخادم, لأن سنقوم ببناء شهادة الخادم افتح المفكرة مجددا:



   1: makecert.exe ^
   2: -n "CN=alghabban.net" ^
   3: -iv CARoot.pvk ^
   4: -ic CARoot.cer ^
   5: -pe ^
   6: -a sha512 ^
   7: -len 4096 ^
   8: -b 01/01/2014 ^
   9: -e 01/01/2016 ^
  10: -sky exchange ^
  11: -eku 1.3.6.1.5.5.7.3.1 ^
  12: -sv ServerCert.pvk ^
  13: ServerCert.cer
  14:  
  15: pvk2pfx.exe ^
  16: -pvk ServerCert.pvk ^
  17: -spc ServerCert.cer ^
  18: -pfx ServerCert.pfx ^
  19: -po 1986Gabban2015*C



اعتقد أن الشفرة في الأعلى واضحة جدا مجددا n يمكنك فعل نفس الأمر في الرووت ,iv تعني الحصول على المفتاح الخاص بـ Root من ملف CARoot.pvk و b تعني تاريخ الشهادة و e تعني متى تنتهي, اخيرا ما يمز أن هذه الشهادة هي شهادة خادم هو eku و هو ما يعرف بـ OID او object Idintify .


ارجو أنك لم تغلق الـ CMD نفس ما فعلنا في الأعلى و لكن هذه المرة سنقوم بكتابة اسم الملف الجديد, مجددا لست بحاجة لكلمة مرور فتجاهل الأمر عد للمجلد, الأن نفس الأمر مع شهادة العميل, وهذه الخطوة ستحتاج لعملها مع كل عميل, الشفرة:



   1: makecert.exe ^
   2: -n "CN=alghabban.net" ^
   3: -iv CARoot.pvk ^
   4: -ic CARoot.cer ^
   5: -pe ^
   6: -a sha512 ^
   7: -len 4096 ^
   8: -b 01/01/2014 ^
   9: -e 01/01/2016 ^
  10: -sky exchange ^
  11: -eku 1.3.6.1.5.5.7.3.2 ^
  12: -sv ClientCert.pvk ^
  13: ClientCert.cer
  14:  
  15: pvk2pfx.exe ^
  16: -pvk ClientCert.pvk ^
  17: -spc ClientCert.cer ^
  18: -pfx ClientCert.pfx ^
  19: -po ****************


لأن نحتاج لتثبيت هذه الشهادات داخل متجر الشهادات, من قائمة ابدأ ابحث عن mmc ثم من file  اختر add/ remove snap-in ابحث الـ ceritifcate , الصورة:


compter


أكمل مع المعالج حتى الانتهاء, الأن ابحث عن المجلد Trusted Root Certification Authorities , افتح المجلد و توجه لـ Certificate بزر الفأرة الأيمن اضغط على All Task ثم Import  أكمل مع العالج حتى يطلب منك الشهادة , هذه المرة ستختار شهادة الـ Root , الصورة:



root cet


بنسبة لكلا من الخادم و العميل فإن عملية تثبيتهما ستكون في الـ Personal و لا يختلف الأمر عن خطوات الـ root , النتيجة,


alghabban cer2


alghabban server cert


بهذا نكون قد انتهينا من اعداد الشهادات , في المقالة القادمة سأتحدث عن استخدام هذه الشهادة لتأمين خدمات WCF .

فقط ارجع بيانات من فضلك , شكرا

قضيت ليلة الامس و انا أفكر في الحكمة التي تقول " الثرثار هو من تسأله عن الوقت فخبرك كيف صنعة الساعة " بطريقة أو اخرى تذكرة حجم الشفرة التي اكتبها باستخدام مكتبة GeniusesCode.Framework.Data.SqlServer

   3: namespace GeniusesCode.UnitTest
   4: {
   5:     public class Applications
   6:     {
   7:         public int ID { get; set; }
   8: 
   9:        public string Name { get; set; }
  10:  
  11:         public bool IsEnabled { get; set; }
  12:  
  13:         public DateTime CreateDate { get; set; }
  14:  
  15:         [ForeignKey]
  16:         public Merchant Merchant { get; set; }
  17:     }
  18: }
  19:  
  20: 
  21: static void Main(string[] args)
  22: {
  23:     Applications application = new Operations().ExecuteQueryToObject<Applications>("select * from Applications where ID = @ID");
  24:     Console.WriteLine(application.ID);
  25:     Console.ReadLine();
  26: }

قبل أن الشرح ما هي المشكلة في الشفرة التي في الأعلى دعوني اشرح ما احاول عملة في الطريقة Main هو الحصول على رقم الكائن Application !! و هذه المشكلة التي تؤرقني كثيرا لقد قمت بكتابة كائن و من تمريرة ثم الحصول على الخاصية كل هذا العمل من اجل الحصول على رقم التطبيق فقط !! الأمر شبيه تمام بالحكمة التي في الأعلى " انا اطلب قيمة الـ ID فقط و انت تخبرني بتفاصيل كثيرة انا في غنى عنها " هذه التفاصيل مثل الخصائص و انواعها و اسمائها و غيرها من الامور.

ما اريد عمله بسيط للغاية اريد أن أكتب شفرة بسيطة امرر لها جملة استعلام و تعيد لي كائن جهاز بخصائصه دون أن اقوم بأي شكل من الاشكال بتعريف الكائن, بمعنى أخر اريد عمل امر شبيه بتالي:

image

المتغير application لم يتم تعريفة في المشروع نهائيا كما أنه الخاصية ID ليست موجودة على الطلاق و هنا يأتي Dynamic هذه الكلمة السحرية التي سنستخدمها لمعالجة هذه المشكلة, هذه احدى المميزات الجديدة التي اعمل عليها الاصدار الجديد من مكتبة GeniusesCode.Framework.Data.SqlServer , تأتي الطريقة ExecuteQueryToDynimcObject و التي تعيد كائن من النوع dynamic , للنظر إلى الشفرة:

   1: dynamic application = new Operations().ExecuteQueryToDynamicObject("select * from applications where ID = 3460");
   2: Console.WriteLine(application.ID);
للنظر كيف يتم الامر يتحدث كل شيء بشكل طبيعي للغاية دون أدن تغير حتى نحصل على DataTable بعد الحصول على DataTable اقوم بالمرور على كل Row بداخل الجدول مع كل سطر أقوم بالمرور على كل عمود داخل هذا السطر و من اقوم بإنشاء كائن من النوع dynamic مع تمرير اسم العمود كاسم للخاصية و محتويات العمود كمحتوى لعمود ثم اقوم بإضافة كائن إلى قائمة و اخيرا عود بالعنصر الأول من القائمة الشفرة:
   1: internal static List<dynamic> ConvertDataTableToDynimcObject(DataTable table)
   2: {
   3:     if (table != null)
   4:     {
   5:         var dynamicDt = new List<dynamic>();
   6:         dynamic dyn = new ExpandoObject();
   7:         foreach (DataRow row in table.Rows)
   8:         {
   9:            foreach (DataColumn column in table.Columns)
  10:             {
  11:                 var dic = (IDictionary<string, object>)dyn;
  12:                 dic[column.ColumnName] = row[column];
  13:             }
  14:  
  15:             dynamicDt.Add(dyn);
  16:         }
  17:  
  18:         return dynamicDt;
  19:     }
  20:  
  21:     return null;
  22: }

   1: public dynamic ExecuteQueryToDynamicObject(string command, CommandType commandType = CommandType.Text, params Parameter[] paramters)
   2: {
   3:     List<dynamic> listOfDynimcObject = DataMapper.ConvertDataTableToDynimcObject(this.ExecuteQueryToDataTable(command, commandType, paramters));
   4:     if (listOfDynimcObject != null && listOfDynimcObject.Count > 0)
   5:     {
   6:         return listOfDynimcObject[0];
   7:     }
   8:  
   9:     return null;
  10: }
و بالتالي استطعت ان احصل على البيانات فقط دون الخوض في الانواع أو التفاصيل و خلافة فقط أعطني الـ ID .
image

الشفرة ذات الرائحة النتنة ( الجزء الثاني )

دائما عندما تبدء المشاريع تكون بسيطة و واضحة , يبدأ المطور بكل بساطة بتنفيذ المشروع و كتابة الشفرات , البعض منى حتى لا ينظر و لا يقرأ المتطلبات بل يقفز مباشرة إلى كتابة الشفرة , على اية حال سأتحدث في هذه المقالة عن جزء أخر من اجزاء الشفرة ذات الرائحة النتنة و هي النصوص و الطلاسم الفرعونية  , هناك شرط يقول " يجب على الشفرة أن تحتوي على شفرة فقط " بمعنى اخر للنظر إلى الشفرة التالية:

1- الطلاسم الفرعونية
   1: public int IsUserHasAccess(string userName)
   2: {
   3:     if(userName == "ALGHABBAN")
   4:     {
   5:        return 1;
   6:     }
   7:  
   8:     return 0;
   9: }

ما المشكلة في الشفرة التي في الأعلى؟ ما معنى واحد و صفر ! اعلم تمام انك ستخبرني بأنك كتبتها في التوثيق و هذا بحذ ذاته خطئ ساتحدث عنه لاحقا ,عموما هذه وحدة من النقاط و هي الرموز الفرعونية غير مفهومة إلا من قبل المطور.

الاشخاص الذي يستخدمون هذا النظام في العادة يستخدمونه بطرق  غريبة فهم على سبيل المثال يقومون بكتابة طرق للإضافة سجل معين إلى جدول في قاعدة البيانات فإذا تمت الاضافة بشكل الصحيح تعيد الطريقة 1 و اذا لم تمم تعيد 0 , قس على ذلك تسجيل الدخول مثلا اذا كانت بيانات تسجيل الدخول صحيح تعيد الطريقة 0 و اذا كانت صحيحة و لكن المستخدم غير مرخص له في الدخول تعيد الطرقة الرقم 7.

اذا ما المشكلة في الاسلوب؟

اخفاء المنطق
للنظر إلى المحادثة التالية:
ص : ما هي السورة التي توجب الجنة ؟
ي : الفجر ..
ص: –1 .

سأل ( ص ) المستخدم ( ي ) سؤال فجاوب المستخدم  ( ي ) اجابة و كانت الاجابة خاطئة جوابه ( ص ) بإجابة اكثر حماقة من اجابته ( –1 ) لماذا لا تجاوب بـ " الاجابة خاطئة " , ما احاول قوله هنا بأن المستخدم أو من يستخدم شفرتك اي مان يتوقع اجابات منطقية على الاسئلة المطروحة امامه و انت بإجابتك بـ –1 او رمز فرعوني تضرب المنطق بالحائط  كما ترى في الاعلى.

صعبة في القراءة

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

الحجة التي يستخدمها الكثير في الاجابة على هذا التساؤل : لماذا تقوم باستخدام هذا الاسلوب ؟ فكر عندما تقوم ببناء خدمة ويب مثلا من الممكن ان تقوم رمي نص صريح مثلا " الاجابة خاطئة " عندها من الممكن ان تكون الجملة تحتوي على مسافة على رموز خاصة نتيجة الانتقال من شبكة إلى أخرى بينما عند ارسال ارقام فيمكن استخدام جملة If بشكل أكثر وضوحا.

كيف يتم علاج المشكلة , هنا يأتي دور Exception للنظر إلى نفس الشفرة التي في الاعلى:

   1: public bool IsUserHasAccess(string userName)
   2: {
   3:     if(userName == "ALGHABBAN")
   4:     {
   5:         return true;
   6:     }
   7:  
   8:     throw new FaultException(new FaultReason(" you don't have access to this page "),
   9:      new FaultCode("0"));
  10: }

في الشفرة التي في الاعلى يمكنك أن ترى كيف اصبح الامر اكثر وضوحا بأن المستخدم ALGHABBAN هو الوحيد الذي لديه الصلاحية للوصول إلى شيء ما , و اذا تم ادخال اي مستخدم أخر ستقوم الشفرة برمي FaultException مع الرقم 1 و تفاصيل الخطأ.

2- النصوص

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

في الشفرة التي في الاعلى اذا اتى طلب معين بتغير النص الموجود فيها من You don't have access to this page  إلى Access Denied فعليا سيكون عليك تعديل الشفرة و من ثم عمل Update للمشروع فإذا كان ويب ستقوم عنها بعمل Deplay جديد كليا , اذا لمعالجة هذه المشكلة عليك دوما عزل هذه النصوص عن الشفرة في ملفات مستقله بها, إليك الحل الذي اتبعه في شفرات هنا, فكرتي بسيط اقوم بإنشاء ملف XML حيث يحتوي هذا الملف على جميع الخطاء التي من الممكن ان تقع في المشروع كل خطئ معرف بدخله ID معين حيث سأقوم بالبحث في ملف الـ XML عن هذا الخطء و بالتالي عرضة على المستخدم , للنظر إلى ملف XML التالية:

   1: <Errors>
   2:   <Error>
   3:     <code>E013002</code>
   4:     <Description>Application is disabled</Description>
   5:   </Error>
   6:   <Error>
   7:     <code>E013001</code>
   8:     <Description>Application not found</Description>
   9:   </Error>
  10: </Errors>
من جهة C# سأقوم بكتابة شفرة بسيطة لبحث عن الخطء في هذا الملف:

   1: public static FaultException GetFaultException(string exceptionCode)
   2: {
   3:     XmlDocument doc = new XmlDocument();
   4:     doc.Load(Common.AssemblyDirectory + "\\Errors.xml");
   5:     XmlNodeList errors = doc.SelectNodes("/Errors/Error");
   6:     foreach (XmlNode error in errors)
   7:     {
   8:         if (error["code"].InnerText == exceptionCode)
   9:         {
  10:             throw new FaultException(new FaultReason(error["Description"].InnerText), new FaultCode(exceptionCode));
  11:         }
  12:     }
  13:  
  14:     throw new FaultException(new FaultReason("undefined Error"), new FaultCode("1500"));
  15: }
ثم يمكنن استدعاء الطريقة مع الشفرة التي في الاعلى بشكل مختلف , إليك الشفرة
   1: public bool IsUserHasAccess(string userName)
   2: {
   3:    if(userName == "ALGHABBAN")
   4:     {
   5:         return true;
   6:     }
   7:  
   8:     throw this.GetFaultException("E013004");
   9: }
بهذه الطرقة إذا اردت تغير نص الخطء فلن احتاج تعديل الشفرة فقط أبحث عن الخطء في ملف XML , هناك مشكلة يجب أن تلاحظها في الشفرة التي تقوم بقراءة ملف Error.xml , المشكلة في الحقيقة هي اسم هذا الملف الذي مازال يعتبر نص و يجب تغيره و هذا الحديث يقودني إلى الحديث على نقطة اخرى في النصوص و هي النصوص التي تحتاج إلى اتخاذ قرار و ما زلنا نكتبها داحل الشفرة, للنظر إلى الشفرة التالية:
   1: private string VerifyOlpIdAlias(string value)
   2: {
   3:     if (!string.IsNullOrWhiteSpace(value))
   4:     {
   5:         if (value.Length >= 6)
   6:         {
   7:             if (value.Length <= 12)
   8:             {
   9:                 if (Regex.IsMatch(value, "^[a-zA-Z0-9_@.]+$"))
  10:                 {
  11:                     return value;
  12:                 }
  13:  
  14:                 throw EntitiesException.GetFaultException("E013112");
  15:             }
  16:  
  17:             throw EntitiesException.GetFaultException("E013111");
  18:         }
  19:  
  20:         throw EntitiesException.GetFaultException("E013110");
  21:     }
  22:  
  23:     throw EntitiesException.GetFaultException("E013010");
  24: }
الشفرة في الاعلى تفترض بشكل دائما أن طول الخاصية Alias دائما يبكون اكبر من 6 حروف و انه بحد اقصى 12 حرفا ثم يجب ان يحتوي الـ alies على ارقام و حروف و فقط @ , . , _ كعلامات خاصة , المشكلة ان الشفرة تفترض بشكل دائما ان هذه الشروط ثابته و غير قابلة لتغير , لنفترض أن العميل قرر قبول حروف خاصة اخرى كيف سيكون ردك ؟ , لمعالجة هذه المشكلة انضر لهذه الشفرة:
   1: private string VerifyOlpIdAlias(string value)
   2: {
   3:     if (!string.IsNullOrWhiteSpace(value))
   4:     {
   5:         if (value.Length >= ConfigManager.GetIntegerValue("MinAliasLength"))
   6:         {
   7:             if (value.Length <= ConfigManager.GetIntegerValue("MaxAliasLength"))
   8:             {
   9:                 if (Regex.IsMatch(value, ConfigManager.GetStringValue("AliasMatchStirng")))
  10:                 {
  11:                     return value;
  12:                 }
  13:  
  14:                 throw EntitiesException.GetFaultException("E013112");
  15:             }
  16:  
  17:             throw EntitiesException.GetFaultException("E013111");
  18:         }
  19:  
  20:         throw EntitiesException.GetFaultException("E013110");
  21:     }
  22:  
  23:     throw EntitiesException.GetFaultException("E013010");
  24: }
لا تخدعك الشفرة على الرغم من أنها نفسها تقريبا إلى انها أكثر قابلية لصيانة و التعديل و التغير مستقبلا في الواقع الشفرة في الاسفل يستطيع المستخدم العادي تعديل هذه الاعدادات دون العودة للمطور على الاطلاق , اذ ان  الشفرة التي في الاسفل تقوم بحفظ هذه الاعدادات في ملف Confgiration و بتالي يمكن صناعة واجه لتعديل هذه الاعدادات , ملف Configration :
   1: <configuration>
   2:   <appSettings>
   3:     <add key="MaxAliasLength" value="12"/>
   4:     <add key="MinAliasLength" value="6"/>
   5:     <add key ="AliasMatchStirng" value="^[a-zA-Z0-9_@.]+$"/>
   6:   </appSettings>
   7: </configuration>
اذا متى ما وجهت شفرة تتخذ قرار بناء على رقم او قيمة دائما و ابدا احفظ هذه القيمة في الاعدادات و ليس داخل الشفرة, هناك قاعدة تقول بأن العميل دائما يكذب من اجل انقاص التكلفة و الوقت لذلك عندما تتعامل مع قوانين من قبل العميل عليك دائما ان تتيح الفرص لتغير و التعديل و ليس تثبيتها.