أفضل الممارسات لتحميل تجميع
تناقش هذه المقالة طرق لتجنب مشكلات هوية النوع التي يمكن أن تؤدي إلى InvalidCastException ، MissingMethodException ، و أخطاء أخرى. تتناول المقالة التوصيات التالية:
فهم مزايا و عيوب سياقات التحميل
تجنب الربط على الأسماء الجزئية للتجميعات
تجنب تحميل تجميع إلى سياقات متعددة
تجنب تحميل إصدارات متعددة من تجميع في نفس السياق
خذ في الإعتبار التبديل إلى سياق التحميل الافتراضي
التوصية الأولى ، فهم مزايا و عيوب سياقات التحميل ، يوفر معلومات تشكل خلفية لتوصيات أخرى , لأن جميعها تعتمد على معرفة سياقات التحميل.
فهم مزايا و عيوب سياقات التحميل
ضمن مجال تطبيق , يمكن تحميل التجميعات إلى واحد من ثلاثة سياقات , أو يمكن تحميلها بدون سياق:
سياق التحميل الافتراضي يحوي التجميعات التي تم العثور عليها بواسطة سبر ذاكرة التخزين المؤقتة للتجميع العمومي , مخزن التجميع المضيف إذا تمت استضافة وقت التشغيل (على سبيل المثال، في خادم SQL ) ، و الـ ApplicationBase و PrivateBinPath من مجال التطبيق. معظم التحميلات الزائدة للأسلوب Load تحمل التجميعات في هذا السياق.
سياق التحميل من يحوي التجميعات التي تم تحميلها من المواقع التي لم يتم البحث فيها من قبل المُحَمِّل. على سبيل المثال، قد يتم تثبيت الوظائف الإضافية في دليل ليس ضمن مسار التطبيق. Assembly.LoadFrom ، و AppDomain.CreateInstanceFrom ، و AppDomain.ExecuteAssembly هي أمثلة للأساليب التي تحمل بواسطة المسار.
سياق الانعكاس فقط يحوي التجميعات التي تم تحميلها بواسطة الأساليب ReflectionOnlyLoad و ReflectionOnlyLoadFrom. التعليمات البرمجية في هذا السياق لا يمكن تنفيذها ، لذا لا يتم مناقشتها هنا. لمزيد من المعلومات، راجع كيفية: تحميل التجميعات في سياق انعكاس فقط.
إذا أنشئت تجميع حيوي إنتقالي باستخدام إرسال الانعكاس , التجميع ليس في أي سياق. بالإضافة إلى ذلك، معظم التجميعات التي تم تحميلها باستخدام الأسلوب LoadFile يتم تحميلها بدون سياق ، و التجميعات التي يتم تحميلها من مصفوفات البايت يتم تحميلها دون سياق ما لم تنشئ هويتها (بعد تطبيق النهج) أنها في ذاكرة التخزين المؤقتة للتجميع العمومي.
سياقات التنفيذ لها مزايا و عيوب , كما هو موضح في المقاطع التالية.
سياق التحميل الافتراضي
عند تحميل التجميعات إلى سياق التحميل الافتراضي , التبعيات الخاص بها يتم تحميلها تلقائياً. التبعيات التي يتم تحميلها في سياق التحميل الافتراضي يتم العثور عليها تلقائيًا للتجميعات في سياق التحميل الافتراضي أو سياق التحميل من. التحميل بواسطة هوية التجميع يزيد استقرار التطبيقات عن طريق التأكد من أن الإصدارات الغير معروفة لا يتم استخدمها (راجع المقطع تجنب الربط على الأسماء الجزئية للتجميع).
استخدام سياق التحميل الافتراضي له العيوب التالية:
التبعيات التي تم تحميلها في سياقات أخرى غير متوفرة.
لا يمكنك تحميل تجميعات من مواقع خارج مسار السبر إلى سياق التحميل الافتراضي.
سياق التحميل من
سياق التحميل من يتيح لك تحميل تجميع من مسار ليس ضمن مسار التطبيق و بالتالي ليس مُضمناً في السبر. إنها تُمكّن التبعيات أن يُحَدَد موقعها ثم تحميلها من ذلك المسار , لأن معلومات المسار يتم الحفاظ عليها بواسطة السياق. بالإضافة إلى ذلك، التجميعات في هذا السياق يمكنها استخدام التبيعات التي تم تحميلها في سياق التحميل الافتراضي.
تحميل التجميعات باستخدام الأسلوب Assembly.LoadFrom , أو أسلوب من الأساليب الأخرى التي تُحَمِل بواسطة المسار , له العيوب التالية:
في حالة وجود تجميع بنفس الهوية تم تحميله بالفعل ، LoadFrom ترجع التجميع المُحَمَل حتى إذا تم تحديد مسار آخر.
إذا تم تحميل تجميع بـ LoadFrom ، و لاحقاً يحاول تجميع في سياق التحميل الافتراضي تحميل التجميع نفسه باسم العرض , محاولة التحميل تفشل. هذا يُمكِن أن يحدث عندما يتم إلغاء تسلسل التجميع.
إذا تم تحميل تجميع بـ LoadFrom ، و يتضمن مسار السبر تجميع بنفس الهوية و لكن في موقع مختلف , InvalidCastException ، أو MissingMethodException ، أو يمكن أن يحدث سلوك آخر غير متوقع.
LoadFrom يتطلب FileIOPermissionAccess.Read وFileIOPermissionAccess.PathDiscovery, أوWebPermission ، في المسار المحدد.
إذا وُجِدت صورة أصلية للتجميع ، لا يتم استخدامها.
لا يمكن تحميل التجميع كمحايد للمجال.
في إصدارات .NET Framework 1.0 و 1.1 ، لا يتم تطبيق النهج.
لا يوجد سياق
التحميل دون سياق هو الخيار الوحيد للتجميعات الإنتقالية التي يتم توليدها بإرسال الانعكاس. التحميل دون سياق هو الطريقة الوحيدة لتحميل تجميعات متعددة التي لها نفس الهوية في مجال تطبيق واحد. يتم تجنب تكلفة السبر.
التجميعات التي يتم تحميلها من مصفوفات البايت يتم تحميلها دون سياق ما لم تكن هوية التجميع التي يتم تأسيسها عند تطبيق النهج , مطابقة لهوية تجميع في ذاكرة التخزين المؤقتة للتجميع العمومي; في هذه الحالة ، التجميع يتم تحميله من ذاكرة التخزين المؤقتة للتجميع العمومي.
تحميل التجميعات دون سياق له العيوب التالية:
التجميعات الأخرى لا يمكنها ربط تجميعات تم تحميلها دون سياق ، إلا إذا قمت بمعالجة الحدث AppDomain.AssemblyResolve .
التبعيات لا يتم تحميلها تلقائياً. يمكنك تحميلها مسبقاً دون سياق ، أو تحميلها مسبقاً إلى سياق التحميل الافتراضي أو تحميلها بواسطة معالجة الحدث AppDomain.AssemblyResolve.
تحميل تجميعات متعددة بنفس الهوية دون السياق قد يؤدي إلى حدوث مشكلات هوية النوع شبيهة بتلك المسببة بتحميل تجميعات بنفس الهوية إلى سياقات متعددة. راجع تجنب تحميل تجميع إلى سياقات متعددة.
إذا وُجِدت صورة أصلية للتجميع ، لا يتم استخدامها.
لا يمكن تحميل التجميع كمحايد للمجال.
في إصدارات .NET Framework 1.0 و 1.1 ، لا يتم تطبيق النهج.
تجنب الربط على الأسماء الجزئية للتجميعات
الربط باسم جزئي يحدث عندما تحدد جزء فقط من اسم عرض التجميع (FullName) عندما تحمل التجميع. على سبيل المثال، قد تستدعي الأسلوب Assembly.Load بالاسم البسيط للتجميع فقط , مُهمِلاً الإصدار , و الثقافة , و رمز المفتاح العام. أو قد تستدعي الأسلوب Assembly.LoadWithPartialName , و الذي يستدعي الأسلوب Assembly.Load أولاً , و إذا فشل في تحديد موقع التجميع ، يبحث في ذاكرة التخزين المؤقتة للتجميع العمومي , و يُحَمِل أحدث إصدار متوفر من التجميع.
الربط بالاسم الجزئي يمكن أن يؤدي إلى العديد من المشكلات , بما في ذلك ما يلي:
الأسلوب Assembly.LoadWithPartialName قد يحمل تجميع مختلف بنفس الاسم البسيط. على سبيل المثال، تطبيقين قد يثبتان تجميعين مختلفين تماماً كلاهما له نفس الاسم البسيط GraphicsLibrary في ذاكرة التخزين المؤقتة للتجميع العمومي.
التجميع المُحَمل بالفعل قد لا يكون متوافق مع الإصدارات السابقة. على سبيل المثال، عدم تحديد الإصدار قد يتسبب في تحميل نسخة بإصدار أحدث كثيراً من الإصدار الذي كُتِبَ برنامجك أصلاً لاستخدامه. التغييرات في الإصدار الأحدث قد تتسبب في حدوث أخطاء في التطبيق الخاص بك.
التجميع المُحَمل بالفعل قد لا يكون متوافق مع الإصدارات اللاحقة. على سبيل المثال، قد تكون بنيت و اختبرت التطبيق الخاص بك مع أحدث إصدار من تجميع , و لكن الربط الجزئي قد يحمل إصدار سابق للغاية قد يفتقر للميزات التي يستخدمها التطبيق الخاص بك.
تثبيت تطبيقات جديدة قد يُعَطِل التطبيقات الموجودة. تطبيق يستخدم الاسلوب LoadWithPartialName قد يتعطل بتثبيت إصدار أحدث و غير متوافق من تجميع مشترك.
تحميل تبعية غير متوقع قد يحدث. إذا حملت تجميعين يشتركان في تبعية , تحميلهما بالربط الجزئي قد يؤدي إلى تجميع واحد يستخدم مكون لم يتم بناءه أو اختباره به.
بسبب المشاكل التي يمكن أن يؤدي إليها ، الأسلوب LoadWithPartialName تم وضع علامة مهمل عليه. نوصي باستخدام الأسلوب Assembly.Load بدلاً منه ، و حدد أسماء العرض الكاملة للتجميع. راجع فهم فوائد و مساوئ سياقات التحميل و خذ في الإعتبار التبديل إلى سياق التحميل الافتراضي .
إذا كنت تريد استخدام الأسلوب LoadWithPartialName لأنه يجعل تحميل التجميع سهل ، خذ في الإعتبار أن جعل التطبيق الخاص يفشل مع رسالة خطأ تُعرّف التجميع المفقود غالباً سيوفر تجربة أفضل للمستخدم من إستخدام إصدار غير معروف من التجميع تلقائياً , و الذي قد يتسبب في سلوك غير متوقع و ثغرات أمان.
تجنب تحميل تجميع إلى سياقات متعددة
تحميل تجميع إلى سياقات متعددة يمكن أن يسبب مشاكل الهوية. إذا تم تحميل نفس النوع من نفس التجميع إلى سياقين مختلفين ، فهو كما لو أن نوعين مختلفين بنفس الاسم تم تحميلهما. InvalidCastException يتم طرحه إذا حاولت تحويل نوع إلى آخر, مع الرسالة المربكة أن النوع MyType لا يمكن تحويله للنوع MyType.
على سبيل المثال، افترض أن الواجهة ICommunicate تم إنشاءها في تجميع باسم Utility ، الذي يتم الإشارة إليه بواسطة البرنامج الخاص بك و أيضاً بواسطة التجميعات الأخرى التي يحملها البرنامج الخاص بك. هذه التجميعات الأخرى تحوي أنواع تقوم بتطبيق الواجهة ICommunicate , سامحة للبرنامج الخاص بك باستخدامها.
الآن خذ في الإعتبار ما يحدث عند تشغيل البرنامج الخاص بك. التجميعات التي يتم الرجوع إليها بواسطة البرنامج الخاص يتم تحميلها إلى سياق التحميل الافتراضي. إذا حملت تجميع مستهدف بواسطة هويته , باستخدام الأسلوب Load سيكون في سياق التحميل الافتراضي , و كذلك التبعيات الخاصة به. كلا من البرنامج الخاص بك و التجميع المستهدف سيستخدمان نفس التجميع Utility.
ومع ذلك، افترض أنك حملت التجميع المستهدف بواسطة المسار الخاص بملفه باستخدام الأسلوب LoadFile. التجميع يتم تحميل بدون أي سياق , لذا لا يتم تحميل التبعيات الخاصة به تلقائياً. قد يكون لديك معالج للحدث AppDomain.AssemblyResolve لتوفير التبعية , و قد تحمل التجميع Utility بدون سياق باستخدام الأسلوب LoadFile. الآن عندما تنشئ مثيل من نوع موجود في التجميع المستهدف و تحاول تعيينه إلى متغير من نوع ICommunicate ، InvalidCastException يتم طرحه لأن وقت التشغيل يعتبر الواجهات ICommunicate في نسختي التجميع Utility كنوعين مختلفين.
هناك العديد من السيناريوهات الأخرى التي صواب يمكن تحميله إلى سياقات متعددة. الأسلوب الأفضل لتجنب التعارضات عن طريق تغيير موقع التجميع المستهدف في مسار التطبيق الخاص بك باستخدام الأسلوب Load بأسم العرض الكامل. عندها يتم تحميل التجميع في سياق التحميل الافتراضي , و كلا التجميعين يستخدم نفس التجميع Utility.
إذا كان التجميع المستهدف يجب أن يظل خارج مسار التطبيق, يمكنك استخدام الأسلوب LoadFrom لتحميله إلى سياق التحميل من. إذا كان التجميع المستهدف تم تحويله برمجياً مع مرجع إلى تجميع التطبيق الخاص بك Utility ، فإنه سيستخدم التجميع Utility الذي حمله التطبيق الخاص بك إلى سياق التحميل الافتراضي. لاحظ أن المشاكل يمكن أن تحدث إذا كان التجميع المستهدف له تبعية في نسخة من التجميع Utility موجودة خارج مسار التطبيق الخاص بك. إذا تم تحميل ذلك التجميع إلى سياق التحميل من قبل أن يحمل التطبيق الخاص بك التجميع Utility ، تحميل التطبيق الخاص بك سيفشل.
المقطع خذ في الإعتبار التبديل إلى سياق التحميل الافتراضي يناقش بدائل استخدام التحميلات بمسار ملف مثل LoadFile و LoadFrom.
تجنب تحميل إصدارات متعددة من تجميع في نفس السياق
تحميل إصدارات متعددة من تجميع في سياق تحميل واحد يمكن أن يسبب مشاكل الهوية. إذا تم تحميل نفس النوع من إصدارين من نفس التجميع ، فهو كما لو أن نوعين مختلفين بنفس الاسم تم تحميلهما. InvalidCastException يتم طرحه إذا حاولت تحويل نوع إلى آخر, مع الرسالة المربكة أن النوع MyType لا يمكن تحويله للنوع MyType.
على سبيل المثال، قد يقوم البرنامج الخاص بك بتحميل إصدار واحد من التجميع Utility مباشرة , و لاحقاً قد يحمل تجميع آخر يقوم بدوره بتحميل إصدار مختلف من التجميع Utility. أو وجود خطأ في كتابة التعليمات البرمجية قد يتسبب في أن مساري تعليمات برمجية مختلفين في التطبيق الخاص بك قد يُحَمِلان إصدارين مختلفين من تجميع.
في سياق التحميل الافتراضي , قد تحدث هذه المشكلة عندما تستخدم الأسلوب Assembly.Load و تحدد أسماء العرض الكاملة للتجميع التي تتضمن أرقام إصدارات مختلفة. للتجميعات التي تم تحميلها دون سياق ، قد تُسَبْبَ المشكلة باستخدام الأسلوب Assembly.LoadFile لتحميل نفس التجميع من مسارات مختلفة. وقت التشغيل يعتبر التجميعين الذين تم تحميلها من مسارين مختلفين كتجميعين مختلفين , حتى إذا كانت هوياتهم هي نفسها.
بالإضافة إلى مشاكل هوية النوع ، إصدارات متعددة من تجميع قد تتسبب في MissingMethodException إذا كان نوع تم تحميله من إصدار ما من التجميع تم تمريره لتعليمات برمجية تتوقع هذا النوع من إصدار مختلف. على سبيل المثال، قد تتوقع التعليمة البرمجية أسلوب تمت إضافته إلى إصدار أحدث.
يمكن أن تحدث أخطاء خفية أكثر إذا تغير سلوك النوع بين الإصدارات. على سبيل المثال، قد يطرح أسلوب استثناء غير متوقع أو يرجع قيمة غير متوقعة.
راجع التعليمات البرمجية الخاصة بك بعناية للتأكد من إصدار واحد فقط من التجميع يتم تحميله. يمكنك استخدام الأسلوب AppDomain.GetAssemblies لتحديد أي تجميعات مُحَمَلة في وقت ما.
خذ في الإعتبار التبديل إلى سياق التحميل الافتراضي
اختبر تحميل التجميعات و نماذج النشر في التطبيق الخاص بك. هل يمكنك التخلص من التجميعات التي يتم تحميلها من مصفوفات بايت ؟ هل يمكنك نقل التجميعات إلى مسار السبر ؟ إذا كان التجميعات موجودة في ذاكرة التخزين المؤقتة للتجميع العمومي أو في مسار السبر الخاص بمجال التطبيق (أي، ApplicationBase و PrivateBinPath الخاصان به) ، يمكنك تحميل التجميع بواسطة هويته.
إذا لم يكن من الممكن وضع كافة التجميعات الخاصة بك في مسار السبر , خذ في الإعتبار البدائل مثل استخدام نموذج الوظيفة الإضافية في .NET Framework ، و وضع التجميعات في ذاكرة التخزين المؤقتة للتجميع العمومي أو إنشاء مجالات التطبيقات.
خذ في الإعتبار استخدام نموذج الوظيفة الإضافية في .NET Framework
إذا كنت تستخدم سياق التحميل من لتنفيذ الوظائف الإضافية، و التي هي عادةً لا تُثَبَت في قاعدة التطبيق ، استخدم نموذج الوظيفة الإضافية في .NET Framework . هذا النموذج يوفر العزل في مستوى مجال التطبيق أو العملية , دون مطالبتك بإدارة مجالات التطبيق بنفسك. للحصول على معلومات حول نموذج الوظيفة الإضافية , راجع الوظائف الإضافية ووحدات الامتداد.
خذ في الاعتبار استخدام ذاكرة التخزين المؤقتة للتجميع العمومي
ضع التجميعات في ذاكرة التخزين المؤقتة للتجميع العمومي لتحصل على فائدة مسار التجميع المشترك , خارج قاعدة التطبيق , دون فقدان ميزات سياق التحميل الافتراضي أو أخذ مساوئ السياقات الأخرى.
خذ في الاعتبار استخدام مجالات التطبيق
إذا حددت أن بعض التجميعات الخاصة بك لا يمكن نشرها في مسار السبر للتطبيق , خذ في الاعتبار إنشاء مجال تطبيق جديد لتلك التجميعات. استخدم AppDomainSetup لإنشاء مجال التطبيق الجديد و استخدم الخاصية AppDomainSetup.ApplicationBase لتحديد المسار الذي يحوي التجميعات التي تريد تحميلها. إذا كان لديك دلائل متعددة للسبر , يمكنك تعيين الـ ApplicationBase إلى الدليل الجذر و استخدم الخاصية AppDomainSetup.PrivateBinPath لتعريف الدلائل الفرعية للسبر. بدلاً من ذلك، يمكنك إنشاء مجالات تطبيقات متعددة و تعيين الـ ApplicationBase لكل مجال تطبيق إلى مسار مناسب للتجميعات الخاصة به.
لاحظ أنه يمكنك استخدام الأسلوب Assembly.LoadFrom لتحميل تلك التجميعات. نظراً لأنها الآن في مسار السبر , فسوف يتم تحميلها في سياق التحميل الافتراضي بدلاً من سياق التحميل من. على الرغم من ذلك، نوصي أن تقوم بالتبديل إلى الأسلوب Assembly.Load و تزوده بأسماء العرض الكاملة للتجميع للتأكد أن الإصدارات الصحيحة ستستخدم دائماً.