مادة:مواضيع متقدمة في إطار دوت نت
Advance Topics in .NET Framework Programming-part 1 : Assemblies
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
الجزء الأول: المُجّمعات
مقدمة
يُعتبر موضوع المجمعات (Assemblies ) من المواضيع المتقدمة في إطار عمل دوت نت NET Framework والتي على أساسها تم بناء مكتبات النت كافةً, لذلك من الضروري فهم المجمعات بداية لفهم آلية تنفيذ البرنامج في .NET وكيف يعمل مترجم C# ,VB.NET,F#,… لأنه في النهاية كل مترجمات لغات .NET تولد نفس الشيفرة الوسيطة MSIL و ما هي بنية الملف التنفيذي EXE الذي يولده لنا مترجم .NET , ثم سنتكلم عن بنية ملف DLL وما هي أوجه التشابه بينه EXE ثم سنتعرف على ماهية المجمعة وبنيتها الداخلية بشيء من التفصيل .
تعريف المجمعات
تُعرّف المجمعة على أنها برنامج نت تنفيذي (أو جزء من برنامج تنفيذي) على هيئة وحدة واحدة, تستخدم المجمعات لتحزيم البرامج المكتوبة بلغة C# أو VB.NET أو أي لغة .NET جديدة لتصبح قابلة للتنفيذ و للنقل من لغة إلى أخرى تحت منصة ال .NET (مثلاً يمكن لمبرمج أن يقوم بعملة على C# ثم يحوله إلى مجمعة DLL)) ليستخدمها مبرمج أخر يعمل على VB.NET أو C++.NET وبذلك لن نحتاج إلى إعادة تنفيذ الكود في كل مرة نحتاجه ).
عند بناء برنامج بلغة .NET سيتولد ملف EXE (طبعاً لا نقصد أنه موجه لنظام التشغيل Windows وحسب إنما هو برنامج محمول Portable ليعمل على أنظمة مختلفة أي أنه لا يحوي شيفرة محلية خاصة ب windows إنما شيفرة MSIL ومعلومات أخرى والدليل على ذلك هو أنه عند تشغيل برنامج .NET على نظام Windows لا يحوي مكتبات ال .NET فأنه سيفشل في تنفيذ التطبيق مع أن Windows يُشغل ملفات تنفيذية! ) و عند بناء مكتبة أصناف Class Library سيتولد ملف DLL يمثل مجمعة أيضاً (المجمعة هي ملف EXE أو DLL).
-لنتذكر الآن كيف يتم تنفيذ تطبيق مكتوب بلغة .NET
-لقد صُممت المجمعات بطريقة تمكننا من تقديم شكل أخر للبرامج تسمى بالمكونات , إن فهم المكونات أساسي لفهم المجمعات بسبب التشابه الكبير بينهما.
المكونات
المكون هو عبارة عن برنامج فرعي أو جزء من برنامج يحوي شيفرة تنفيذية وليس شيفرة مصدرية مما يعني أن بإمكان البرامج الأخرى أن تستخدمه دون الحاجة إلى لإعادة ترجمة الشيفرة المصدرية ودون الحاجة لمعرفة الشيفرة المصدرية الخاصة بالمجمعة مما يوفر نوعاً من الأمن .
مزايا المكونات
من أهم مزايا المكونات:
- إعادة استخدام البرامج الفرعية في برامج عديدة (في حال قمت ببناء مكبة خاصة بك وأردت أن تعطيها لصديقك دون أن يعرف ما هي الخوارزميات المتبعة في كتابة الكود الخاص بك يمكنك أن تعطيه ملف DLL بدلا من ال Source Code).
- المجمعة التي قمت ببنائها يمكنك أن تقوم ببيعها ويمكنك أن توقعها ب اسم فريد
لتكون وحيدة على مستوى العالم ولحفظ حقوقك من السرقة أو الاستخدام غير المشروع .
نبذة تاريخية عن المُجمّعات
- في هذه الفقرة ما يهمنا ليس هو التاريخ بحد ذاته ولكن ما يهمنا هو المشاكل التي كانت تعاني منها الشركات في السابق بسبب صعوبة التعامل مع المكونات وسأقدم مثالا عن COM : - COM (Component Object Model) : هو أول مكون حقيقي قدمته شركة Microsoft مشاكل COM تتلخص في :
- صعوبة تعلم وبرمجة COM علماً أن المصدر الرئيسي لمكونات COM هو لغة C++ بااستخدام مكتبة ATL .
- تثبيت مكونات COM صعب جداً ويحتاج إلى معلومات موجودة في مسجل النظام وإزالة تثبيت المكون تحتاج إلى جهد كبير أيضاً .
- مشكلة تحديث المكونات حيث لا تستطيع التطبيقات التمييز بين ملفات DLL لها نفس الإصدار وهذا يؤدي إلى أخفاق أحد البرامج عن العمل وهذه المشكلة كانت تعرف ب "جحيم DLL " , ولكن مع .NET تم تجاوز هذه المشاكل بتعريف مقياس جديد للمكونات في .NET
ذاتية الوصف Self Description
- إن ما يميز مجمعات .NET عن غيرها هو ذاتية الوصف ونقصد بهذا أن جميع المعلومات المتعلقة بالمجمعة موجودة ضمنها , وهذا يعني أن البرنامج أو النظام الذي سيستخدم المجمعة ليس بحاجة للحصول على أي معلومات من خارج المجمعة من مسجل النظام أو من أي مكان أخر لأن هذه المعلومات موجودة ضمن المجمعة (عند بناء DLL في C++ WIN32 كل ملف DLL يأتي معه ملف LIB وهو فهرس للتوابع و الإجراءات الموجودة بالمكتبة ولكن مع .NET تم تجاوز هذه المشكلة ) .
- تتعدى مسألة ذاتية الوصف أسماء المناهج (Methods) والكائنات وأنواع البارمترات فالمجمعات تتضمن معلومات عن إصدارات الكائنات كأن نقول مثلاً(Shapes 1.0 يليها Shapes 1.1 ثم Shapes 2.0 ) وهذا يجعل عملية تثبيت مكونات .NET أسهل بكثير من السابق , حتى أن عملية تحديث المكونات ليست إلا مجرد نسخ ملفات DLL إلى القرص الصلب فقط!.
مجمعات .NET ومكتبة أصناف .NET FrameWork
- طبعاً ومن البديهي إن أي برنامج مكتوب ب C# ,VB مثلاً حتماً سوف يستخدم مكتبة من مكتبات ال .NET , فنحن كلما استدعينا Method من فضاء الأسماء system فأن محرك زمن التنفيذ المشترك (CLR) سيضمن تحميل المجمعة ومعرفة التابع الذي قمت باستدعائه من المكتبة التي قمت بتحميلها (في أي namespace وفي أي Class هذا ال method ) وذلك من خلال البيانات الوصفية MetaData(وهذه الفكرة التي نهدف إلى إيصالها من خلال الدروس القادمة) ومن خلال البيانات الوصفية يمكنه معرفة المجمعات التي يمكن قمت باستخدامها مثلاً: لنفرض أنك قمت ببناء مجمعة(ملف EXE يمثل برنامجك) واستخدمت المكتبة (أو المجمعة ) System.Drawing.dll عندئذٍ سيقوم ال CLR بقراءة البيانات الوصفية الموجودة في برنامجك(الذي يمثل مجمعة) لمعرفة فيما إذا كان التطبيق يحتاج إلى مجمعات أخرى وبالتالي يمكن لتطبيق بسيط جداً يستحدم تعليمة using واحدة أن يستخدم عدة مجمعات مختلفة .
- ملاحظة : إن تعليمة using لا تقوم بإضافة مرجع للمجمعة وإنما تؤشر إلى فضاء أسماء (namespace) موجود ضمن المجمعة.
- ولإضافة مرجع إلى مجمعة من قائمة Project نختار Add reference ثم نحدد المجمعة التي نريدها .
التداخل بين لغات البرمجة
قبل البداية أود أن أطرح السؤال التالي : لماذا تقوم Microsoft بإنشاء لغات برمجة جديدة مع أنها جميعاً تترجم إلى Managed Code؟ في الحقيقة يوجد أكثر من سبب:
- إن العديد من المبرمجين حساسين جداً للغة التي يبرمجون بها فكل منهم يحب syntax خاص للغة معتاد عليه ولا ننسى الدور التسويقي لجذب جميع المبرمجين للعمل على .NET حيث يمكن لمبرمجي C++ ,C# ,VB ,Delphi وحتى يوجد محاولات لتحقيق التوافقية بين ال .NET وال JAVA وبالتالي يمكن أنتاج منتج بواسطة فريق عمل وكل شخص يعمل على لغة مختلفة عن الأخرى وبالتالي نكون قد أنتجنا المنتج بواسطة عدة لغات برمجة .
- الآن سنتكلم عن بعض المزايا الأساسية التي يوفرها .NET Framework التي تمكننا من التداخل بين لغات البرمجة:
- محرك زمن التنفيذ المشترك (CLR) والذي يدير تنفيذ جميع مجمعات .NET بغض النظر عن اللغة التي كتبت بها (CLR مثل ال JVM تماماً بال JAVA)
- لغة MSIL (لغة Microsoft المتوسطة) والتي تنتجها جميع مترجمات لغات .NET
- مواضفات اللغة المشتركة CLS حيث يمكن للمكونات المكتوبة بلغة C# مثلاً أن تستخدم في VB مع إمكانية الوراثة الكاملة بين الأصناف .
بنية المجمعات
تحوي المجمعة على شيفرة تنفيذية للبرنامج أو مكتبة الأصناف التي أُنشئت منها بالإضافة إلى بيانات وصفية "MetaData" إن البيانات الوصفية هي بيانات عن المجمعة بحد ذاتها وليست جزءاً من المجمعة ,يكون لمجمعة .NET الشكل التالي:
- تحوي كل مجمعة على بيان (manifest) يصف محتوى المجمعة يسمى أيضا (ِAssembley MetaData) باعتبار أن هذا البيان يصف المجمعة ومحتواها , وما هي الوحدات التي تحويها وما هي المجمعات التي تستخدمها ...الخ. سنتحدث عن بيان المجمعة لاحقاً والجدير بالذكر أن مكونات COM ليس لها بيان كهذا مبيت فيها .
-يستخدم CLR هذ البيان في مجمعة البرنامج عند تنفيذه وذلك لاستعادة المراجع للمجمعات الأخرى كما هو مكتوب في بيان المجمعة كاستعادة المكتبة System.Console التي تحتوي المنهج writeline() في تطبيقات Console مثلاً .
-يتبع بيان المجمعة ما يسمى بالبيانات الوصفية للأنواع تمثل هذه البيانات وصفاً للأصناف والمناهج والخصائص وكافة الأعضاء الموجودة داخل المجمعة بالإضافة إلى بارمترات المناهج وأنواعها و...., يتبع ذلك الشيفرة التنفيذية وأخيراً هناك قسم المصادر حيث تمثل المصادر الأجزاء غير التنفيذية مثل الصور والأيقونات وملفات الرسائل .
-يمكن فصل المجمعة إلى عدة ملفات ولكن عادة تكون ملف وحيد.
إنشاء المجمعات
1-ننشئ مشروع جديد من النوع Class Library ثم نضيف Add new Item ثم نختار ملف cs إذا كنا نعمل C# و vbإذا كنا نعمل VB.net الأن لدينا Class فارغ ضمن namespace .
2- يمكن أن تحوي المجمعة أكثر من namespace مثلاً: System.Data تحوي أكثر من namespace مثل System.Data.OLeDB و System.Data.SqlClientوفي كل namespace يمكن أن نضع Classes و delegates وEnum وأي بنى معطيات أخرى ثم نقوم ببناء المشروع (Shift+f6= build) فينتج لدينا ملف dll يمثل المجمعة يمكن أن يعطيه لأي شخص ليقوم بعمل Add Reference ليستعمله في أي لغة تحت منصة ال .NET
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
استعراض محتويات المجمعة
يمكن إستعراض محتويات المجمعة (ملف dll أو ملف EXE ) من خلال أداة تسمى ILDASM , تسمح هذه الأداة باستعراض محتويات المجمعة (شيفرة MSIL و ال MetaData الخاصة بالمجمعة) في الحقيقة غالباً وخلال تطوير التطبيقات لن نحتاج لاستخدام هذه الأداة – فقط للإطلاع-) الأداة موجودة في المسار التالي C:\programfiles\microsoft.net \frameworkSDK\bin ويمكن تشغيلها من ال Commad line الخاص بال visual studio حصراً لأن المتحول البيئي Path قد تم إعداده بشكل تلقائي عند تشغيله ,لذلك نكتب:
ildasm<
بيان المجمعة Mainfest
يصف البيان معلومات عن المجمعة والأهم من ذلك أنه يعرف أي مجمعات خارجية تستخدمها هذه المجمعة , يحوي البيان أيضاً رقم إصدارة المجمعة مما يجعل عملية تحديث التطبيق أمراً أسهل من ذي قبل .
صفات المجمعة
بالإضافة إلى المراجع (References) التي يحويها بيان المجمعة فأنه يحوي أيضاً معلومات تخص المجمعة نفسها أيضاً تسمى هذه المعلومات بصفات المجمعة.
الملف Assemblyinfo.cs
قد يتساءل أحدنا ما هي وظيفة الملف Assemblyinfo.cs الذي يتولد مع كل تطبيق يتم إنشاءه بواسطة Visual Studio يستخدم هذا الملف لضبط صفات المجمعة في بيانها (سنتحدث عن الصفات في الدرس القادم فلا تقلقوا !) تتضمن هذه الصفات اسم المجمعة وإصداراها أمور أخرى سنتكلم عنها في دروس قادمة .. لنلق نظرة على هذا الملف :
<pre>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Training")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Training")]
[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
<pre>
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
<pre>
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4baac969-4d1b-45c0-a680-b1fd6477cf66")]
<pre>
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
كل تعليمة موضوعة ضمن الأقواس المربعة "[]" مثل [assembly:AssemblyVersion("1.0.0.0")]
تمثل صفة Attribute -سنتحدث عن الصفات في درس لاحق – يكفي أن نعلم الآن أن كل تعليمة من هذه التعليمات تقوم بإعداد خاصية من خصائص المجمعة و تشيرالكلمةassembly
في بداية كل تعليمة أن الصفة موجهة للمجمعة نفسها وليس لأي صف class أو منهج method كما سنرى في درس لاحق .
يوفر visual studio هذا الملف كقالب جاهز يمكن ملأه بالقيم التي تريدها لمجمعتك ويمكن استعراض هذه الصفات من خلال الأداة ildasm من خلال القسم manifest (بيان المجمعة)
أرقام الإصدارات
كلنا قد تكلمنا سابقاً أن لكل مجمعة اسم ورقم إصدار ومعلومات أخرى وهي كلها متوفرة على شكل Attributes -هذه المعلومات لا تهمنا نحن كمطورين للبرامج وإنما في حال إصدار منتج وقمنا بترقية وتحديث مجمعاتنا سواء كانت dl l أو EXE فأننا نقوم بتوقيع المجمعة ب اسم فريد لضمان حقوق شركتك من السرقة وللسماح للبرامج من التأكد من أن هذه المجمعة موقعة (موضوع أمني بحت). للإصدار في مجمعة .NET أربعة أرقام هي : 1-إصدار رئيسي (Major Version ) 2-إصدار ثانوي (Minor Version) 3-رقم البناء (Build Number) 4-رقم الطبعة (Revision)
-الجزء الأول والثاني مثلاً : المجمعة Shape 1.0 الإصدار الرئيسي هو 1 والإصدار الثانوي هو 0 , الجزءان الأخيران يشكلان تفصيلاً أكبر فرقم البناء يشير إلى رقم بناء المجمعة وهو رقم فريد يتغير مع كل عملية بناء للمجمعة , أما رقم الطبعة فهو رقم يستخدم مع ترقيعات المجمعة وهذا يعني أن المجمعة هي تماماً كإصداراتها السابقة فيما عدا الجديدة تمثل تصحيحاً لخطأ واحد فقط .
التوافقية بين الإصدارات
يتفحص ال CLR أرقام الإصدارات عند تحميل المجمعات ويتحقق من التوافقية بين إصداراتها ولا تحدث عملية التحقق هذه إلا مع المجمعات المشتركة-الفقرة التالية -وهي المجمعات التي يتشارك عليها أكثر من تطبيق في آن واحد.
بالعودة إلى بيان المجمعة كنا قد رأينا أنه يحوي رقم إصدار المجمعة بالإضافة إلى مراجع لمجمعات خارجية التي تستخدمها , وعند تنفيذ هذه المجمعة (لنفرض أنها ملف EXE يمثل تطبيق يستخدم مجمعات من نوع ملفات dll) عندئذٍ سيقوم CLR بمقارنة رقم إصدارة المجمعة الخارجية (التي يستعملها ملف ال EXE والذي يمثل التطبيق) الموجود في بيان المجمعة (مجمعة تطبيقنا) مع رقم إصدارة المجمعة الخارجية (ملف ال DLL) في بيانها وذللك للتأكد من التوافقية بين الإصدارات.
إذا كان للمجمعة رقم إصدار رئيسي أو ثانوي مختلف عندئذٍ يوجد عدم توافق وبالتالي لن ُتحمّل المجمعة .مثلاً : إذا كان التطبيق يستخدم مكتبة الأصناف Shape1.1 فأنه لن يعمل مع مكتبة الأصناف Shape1.0 أو Shape1.2.
المجمعات الخاصة والمشتركة
المجمعات الخاصة
الوضع الافتراضي للمجمعة هو أن تكون خاصة وهذا يعني أنها خاصة بتطبيقك فقط ويجب على البرامج التي تستخدمها أن تضع هذه المجمعة في نفس مجلد التطبيق أو في المجلدات الفرعية .
المجمعات المشتركة
هي مجمعات متوفرة للاستخدام من قبل جميع البرامج على الجهاز فالبرنامج ليس بحاجة لمعرفة مكان المجمعة لأن جميع المجمعات مخزنة في مجلد .NET خاص يسمى ذاكرة المجمعات العامةGlobal Assembly Cache))أو اختصاراً GACيمثل المسار التالي C:\Windows\assembly , لأن هذه المجمعات متوفرة على مستوى النظام ككل فأن CLR يقوم بعدد منعمليات التفحص على المجمعات المشتركة للتأكد من إمكانية استخدامها من قبل البرامج التي تطلب ذلك .
الأمن والاسم المركز Security and Strong name
يجب أن توفر المجمعة إثباتاً أنها لم تستبدل بمجمعة أخرى لها نفس الاسم والإصدار أو قد تم تعديلها بطريقة ما عن طريق الفيروسات مثلاً , يتم ذلك عبر التحقق من أن المجمعة المشتركة موقعة بمفتاح مشفر قبل تحميلها في GAC , لا يساعد هذا المفتاح على حماية المجمعة من الطفيليات كالفيروسات وحسب وإنما يمنع تضارب المجمعات الناتج عن تشابه أسماء وأرقام إصداراتها , ويسمى هذا التركيب المؤلف من اسم المجمعة وإصداراتها ومفتاحها(العام والخاص) بالاسم المركز(ٍStrong name).
إنشاء المجمعات المشتركة
لكي نتمكن من إنشاء مجمعة مشتركة باسم ُمركّز ,علينا توليد زوج من المفاتيح العام والخاص وذلك للتعرف على المجمعة من خلاله عند استخدامها .تًستخدم أنظمة المفاتيح المشفرة المفاتيح العامة والخاصة مفتاحاً خاصاً معروفاً من قبل مرسل الرسالة المشفرة فقط ,أما المفتاح العام فهو متوفر للعالم ككل ,يستخدم CLR هذه المفاتيح للتأكد من تطابقها (المفتاح الموجود في بيان المجمعة (التطبيق)) يجب أن يطابق المفتاح الموجود في بيان المجمعة المشتركة التي يستخدمها التطبيق . يمكن توليد اسم مركز عن طريق سطر الأوامر الخاص ب Visual Studio وذلك باختيار Command Window من قائمة Other Windows من القائمة View نكتب الأمر التالي : Sn –k keyfile.snk سيؤدي هذا الأمر لإنشاء ملف المفتاح keyfile.snk ولتسجيل (توقيع ) المجمعة بهذا المفتاح فأننا سنعدل الصفة(Attribute) AssemblyKeyfile في أخر جزء من الملف Assemblyinfo.cs لمشروعك كما يلي : [assembly:AssemblyKeyFile("keyfile.snk ")] // يمكننا إضافة مسار المفتاح أيضاً
عادةً يكون ملف المفتاح موجود في المجلد debug أو release
ملاحظة : يمكننا أن نضع التعليمة السابقة في الملف المصدري للمجمعة في حال عدم وجود ملف Assemblyinfo.cs كما يلي :
- using System.Reflection
- using System.Runtime.CompilerServices
- using System.Runtime.InteropServices
[assembly:AssemblyKeyFile("keyfile.snk ")] // يمكننا إضافة مسار المفتاح أيضاً
الآن نعيد بناء المجمعة (shift+f6) فنحصل على المطلوب –مجمعة موقعة –وإذا تفحصنا بيان المجمعة سنجد المفتاح العام الذي تم توليده ووضعه الآن سنقوم بنسخ ملف ال dll الذي نتج لدينا إلى GAC وبذلك نحصل على المطلوب .
ملاحظة : أحياناً نشغل برنامج مثلاً يعتمد على مكتبات (مجمعات) عندها يقوم CLR بالبحث عن المجمعة في المجلد المحلي للبرنامج أولاً فإذا لم يجدها فأنه يبحث عنها في GAC في إذا لم يجدها (بيضرب Exception لمستوى نظام التشغيل).
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
قراءات يُنصح به
- كتاب Wrox.Press-Professional.C.Sharp.3rd.Edition-2004) مرجع ممتاز جداً جداً (chapter 13: Assemblies)
- C Sharp COM+ Programming 2001 للكاتب: Derek Beyer هذا الكتاب أكثر من ممتاز- وهو تخصصي جداً .