قائمة التحقّق قبل ترحيل .NET Framework إلى .NET
· آخر تحديث: · 小村 豪 · .NET, .NET Framework, C#, التحديث, تطوير Windows, الترحيل
سجل التعديلات (3 تحديثات، آخر تحديث 3 Sep، 2026)
سجل بالتغييرات التي أُجريت على هذا المقال. وحيثما حُفظت نسخة سابقة، تبقى متاحة للقراءة عبر رابط دائم يحمل معرّف DOI.
- أُضيفت روابط الاستشارة الموجودة في الأصل الياباني (consultation_services). ولم يتغيّر نصّ المقالة نفسه. قراءة النسخة السابقة لهذا التحديث (DOI: 10.5281/zenodo.22240841)
- أُعيدَت الترجمة العربية كترجمة كاملة عن النص الياباني الأصلي، وأُضيفَت خريطة المعرفة.
- أعيدت الترجمة كترجمة كاملة عن النص الياباني الأصلي. كانت النسخة العربية السابقة مختصراً يسقط أبواباً وجداول ورسوم Mermaid وتعليقات الأشكال وFAQ. أُعيدت هذه العناصر وفق الأصل الياباني، والادّعاءات التقنية مطابقة للنسخة اليابانية.
- النشر الأول
الاستشهاد بهذا المقال(DOI: 10.5281/zenodo.21621370)
هذا المقال محفوظ على Zenodo. يرد أدناه معرّف DOI الذي يشير دائمًا إلى أحدث نسخة، ومعرّف DOI المثبَّت على النسخة التي تقرؤها.
小村 豪 (2026). قائمة التحقّق قبل ترحيل .NET Framework إلى .NET. شركة كومورا سوفت ذ.م.م.. https://doi.org/10.5281/zenodo.21621370 https://comcomponent.com/ar/blog/2026/03/15/003-dotnet-framework-to-dotnet-premigration-checklist/
- DOI (أحدث نسخة)
- 10.5281/zenodo.21621370
- DOI (هذه النسخة)
- 10.5281/zenodo.22279785
تنزيل قائمة التحقّق بصيغة Excel مع أوراق باليابانيّة والإنجليزيّة
يتكوّن الملفّ من ورقتين Checklist-ja و Checklist-en، ويُسقِط قائمة التحقّق قبل البدء في 13 فصلاً إلى 34 بنداً في 7 فئات: السياسة / تجهيز جانب .NET Framework الحالي / نوع التطبيق واختيار التقنية / التقنيات غير المدعومة وواجهات برمجيّة تستحق الحذر / الاعتماد الحصريّ على Windows / المكتبة المشتركة والوصول إلى البيانات / التشغيل والبناء. عمودا Status و Notes فارغان، فيصلح الجدول كما هو لجرد كلّ قضيّة. إن تصفّحته قبل قراءة المقال سيسهل التقاط تدفّق الفصول حتّى الفصل 13.
تغيّر TargetFramework في .csproj إلى net10.0، وتحدّث بضع حزم NuGet، وينجح البناء فينتهي الأمر.
…إن كان الترحيل كذلك، فهو هادئ جدّاً. في الواقع، الغلبة لخلاف ذلك.
في مواقع .NET Framework تنام فرضيّات قلّما تُلاحَظ في الأيّام العاديّة: System.Web، و WCF، و Web Forms، و packages.config القديمة، و web.config.install.xdt، و DLL أصليّة، و COM / ActiveX، وعناصر تحكّم طرف ثالث لا تعمل إلا وقت التصميم، وفرضيّة x86 ضمنيّة، و ResX المعتمد على المصمّم، ومُسلسِلات قديمة.
لذلك، الأهمّ في ترحيل .NET Framework إلى .NET هو الجرد قبل التنفيذ. إن فكّكتَ النقاط قبل البدء، لم يعد الترحيل «رهاناً كبيراً» بل «عملاً تُصفَّى فيه النقاط بالترتيب».
flowchart TB
accTitle: الجرد يغيّر طابع الترحيل
accDescr: مخطّط يبيّن أنّ الجرد قبل التنفيذ وتفكيك النقاط يجعل الترحيل عملاً تُصفَّى فيه النقاط بالترتيب لا رهاناً كبيراً.
hid1["فرضيّات ضمنيّة نائمة"] --> inv1["الجرد قبل البدء يفكّك النقاط"]
inv1 --> tsk1["يصير عملاً تُصفَّى فيه النقاط بالترتيب"]
hid1 -.->|"إن تُرك الجرد"| bet1["يصير الترحيل رهاناً كبيراً"]
الشكل 1: قدرة تفكيك النقاط قبل البدء هي التي تجعل الترحيل رهاناً أو عملاً.
يلخّص هذا المقال ما ينبغي التحقّق منه قبل ترحيل تطبيقات أعمال قائمة على .NET Framework 4.x إلى .NET الحالي. الأهداف الرئيسيّة تقريباً:
- مكتبات الأصناف
- تطبيقات وحدة التحكّم
- خدمات Windows
- WinForms / WPF
- ASP.NET Framework (MVC / Web API / Web Forms)
- التطبيقات التي تستخدم WCF
- التطبيقات التي تستخدم EF6
وقت الكتابة 2026-03-15. مدد الدعم وتوصيات الأدوات الرسميّة تتغيّر، فإن قرأتَ المقال بعد مدّة فتحقّق أيضاً من المعلومات الرسميّة.
1. الخلاصة أوّلاً
نضع أوّلاً النتائج التي يصعب تجاوزها.
- ترتيب جانب .NET Framework قبل الترحيل يأتي أوّلاً. دليل Microsoft الرسميّ يوصي أيضاً، قبل النقل، بالرفع إلى .NET Framework 4.7.2 فما فوق، والتحويل إلى
PackageReference، وأسلوب SDK، وتحديث التبعيّات. - الصعوبة تُحدَّد بـ نموذج التطبيق أكثر من حجم الشيفرة. مكتبات الأصناف ووحدة التحكّم أخفّ نسبيّاً، وASP.NET Framework و Web Forms وخادم WCF و WF (Workflow Foundation) أثقل غالباً.
- WinForms / WPF يبقيان حصريَّين لـ Windows حتّى بعد الترحيل إلى .NET. إن أخطأتَ هذا التوقّع وطئتَ لغماً شائعاً: رحّلتَ ثمّ لم تستطع وضعه في حاوية Linux.
- ASP.NET Framework → ASP.NET Core ترحيل معماريّ في جوهره. قد تنتقل التطبيقات الصغيرة دفعة واحدة، أمّا أنظمة الإنتاج الكبيرة فأأمن أن تُخطَّط بترحيل تدريجيّ.
- WCF و EF6 يمكن أحياناً فصلهما عن ترحيل الـ runtime. لعميل WCF حزم مدعومة لـ .NET، ويمكن الإبقاء على EF6 بعد الانتقال إلى modern .NET ثمّ ترحيل EF Core مشروعاً منفصلاً.
- بالمقابل، إنشاء AppDomain، و .NET Remoting، و CAS (Code Access Security، أمن وصول الشيفرة)، و COM+، و Workflow Foundation، واعتماد BinaryFormatter إشارات حمراء. إن لم تُكتشَف مبكّراً انفجر الجهد لاحقاً.
packages.config/install.ps1/XDT(XML Document Transform، آليّة تحويلweb.configونحوه) / أصولcontent/ DLL أصليّة / COM / ActiveX / فرضيّة x86 تسقط بسهولة وقت التشغيل أو وقت التصميم رغم نجاح البناء، فاغسلها قبل البدء.- في آذار/مارس 2026 .NET 10 هو LTS. لنقطة هبوط ترحيل جديد، الطبيعيّ اتّخاذ LTS الحالي أساساً.
- ترحيل بلا اختبارات وقياس وخطّة تراجع خطر. الترحيل أقلّ كونه عمل تنفيذ وأكثر كونه إظهار الشروط المسبقة واحداً واحداً.
في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 30، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle
2. نقرّر أوّلاً: هل ينبغي الترحيل الآن؟
ما نريد تقريره أوّلاً ليس «كيف نرحّل» بل هل ينبغي فعلاً ترحيل هذا التطبيق الآن.
إن بقي هذا غامضاً، مال الحكم إمّا إلى ترحيل صحيح تقنيّاً وأثقل من طاقة العمل، أو بالعكس إلى تأجيل مفرط لتطبيق كان أوضح أن يُرحَّل.
flowchart TB
accTitle: السؤال الذي يُقرَّر أوّلاً
accDescr: مخطّط يبيّن أنّه ينبغي تقرير هل ينبغي فعلاً ترحيل هذا التطبيق الآن قبل كيفيّة الترحيل، وأنّ الغموض هنا يميل إلى ترحيل أثقل من طاقة العمل أو إلى تأجيل مفرط.
q1["هل ينبغي الترحيل الآن فعلاً"] -->|"يُقرَّر أوّلاً"| how1["كيف نرحّل"]
q1 -.->|"المضيّ والغموض قائم"| bad1["ترحيل أثقل من اللازم أو تأجيل مفرط"]
الشكل 2: إن لم تقرّر «هل نرحّل الآن» قبل «كيف نرحّل»، مال الحكم إلى أحد الطرفين.
2.1 البقاء على .NET Framework قرار وارد
يبقى .NET Framework 4.8.1 مدعوماً ما دام يعمل على إصدار Windows مدعوم. أي أنّ المسألة ليست ببساطة: إن لم تنتقل كلّ شيء فوراً إلى modern .NET فأنت في خطر فوريّ.
لكن للبقاء قيوداً واضحة.
- لا تخرج من حصرية Windows
- تواصل حمل ASP.NET Web Forms ومكدّس خوادم قديم
- يصعب جني تحسينات الأداء وميزات اللغة والنظام البيئيّ في .NET الجديد
- يسهل الانحراف عن فرضيّات السحابة والحاويات و CI/CD الحاليّة
بالمقابل، إن كان الاعتماد من النوع التالي قويّاً، فمن المعقول الاقتراب مؤقّتاً من .NET Framework 4.8.1 للتشغيل المستقرّ ووضع خطّة استبدال على مسار آخر.
flowchart TB
accTitle: البقاء اختيار معقول
accDescr: مخطّط يبيّن أنّه إن وُجد اعتماد تراثيّ قويّ مثل Web Forms أو توافق خادم WCF أو COM+، فمن المعقول الاقتراب مؤقّتاً من .NET Framework 4.8.1 للتشغيل المستقرّ ووضع خطّة استبدال على مسار آخر.
dep1["يوجد اعتماد تراثيّ قويّ"] --> stay1["الاقتراب مؤقّتاً من 4.8.1 للتشغيل المستقرّ"]
stay1 --> plan1["خطّة استبدال على مسار آخر"]
stay1 -.-> lim1["تبقى قيود مثل حصرية Windows"]
الشكل 3: إن كان الاعتماد عميقاً، يصير مساران واقعيَّين: تشغيل مستقرّ على 4.8.1 وخطّة استبدال.
- كمّ كبير من شاشات Web Forms
- حاجة صارمة لتوافق خادم WCF
- اعتماد عميق على Workflow Foundation أو COM+
- مكوّنات تصميم طرف ثالث غير مدعومة في modern .NET
- العمل لا يسمح بتغيير مواصفات كبير
2.2 ماذا يتغيّر حسب الخيار
| الخيار | ماذا يتحسّن | ماذا يبقى / يُفقَد | الحالة المناسبة |
|---|---|---|---|
| البقاء على .NET Framework 4.8.1 | تشغيل مستقرّ دون كسر الأصول القائمة | حصرية Windows، نموذج تطبيق قديم، حدود التحديث | اعتماد تراثيّ قويّ، والأولويّة الآن تشغيل مستقرّ للعمل |
| الترحيل إلى modern .NET مع البقاء على Windows | يمكن تحديث الـ runtime وسلسلة الأدوات. فوائد الأداء وتجربة التطوير وأسلوب SDK كبيرة | يبقى اعتماد Windows API. لا يصير عابر المنصّات | تطبيقات أعمال تستخدم WinForms / WPF و Windows Service و Windows API |
| الترحيل إلى modern .NET مع النظر مستقبلاً إلى Linux / الحاويات / السحابة | حرّيّة جهة النشر ترتفع. يسهل تجديد نموذج التشغيل | يلزم نزع واجهات Windows الحصريّة ونموذج التطبيق أوّلاً | تريد تقريب جانب الخادم من السحابة، وتجديد البنية أيضاً |
المهمّ ليس هل تريد الترحيل بل تقرير أين تريد الهبوط بعد الترحيل أوّلاً.
flowchart TB
accTitle: ما يُقرَّر هو نقطة الهبوط
accDescr: مخطّط يبيّن أنّ المهمّ ليس هل تريد الترحيل بل تقرير أين تريد الهبوط بعد الترحيل أوّلاً.
ask1["هل تريد الترحيل"] -.->|"السؤال غير كافٍ"| dec1["ما يُقرَّر أوّلاً"]
land1["أين تهبط بعد الترحيل"] -->|"هذا ما يُقرَّر"| dec1
dec1 --> path1["تتحدّد الخيارات والنقاط التي تُنظَر"]
الشكل 4: إن تحوّل السؤال من «هل تريد الترحيل» إلى «أين تهبط»، تحدّدت الخيارات.
3. أربع سياسات تُقرَّر مسبقاً
3.1 إصدار .NET لنقطة الهبوط
وقت الكتابة، حسب سياسة دعم Microsoft، .NET 10 هو LTS. من جهة أخرى، .NET 8 LTS و .NET 9 STS كلاهما مقرَّر انتهاء الدعم في 2026-11-10. سبب تساوي تاريخ STS مع LTS أنّ مدّة دعم STS مُدِّدت من 18 شهراً إلى 24. إن حسبتَ بفرضيّة قديمة «STS ثمانية عشر شهراً» بدا أنّ .NET 9 ينتهي في 2026-05-12، لذا حين تعتمد على التاريخ تحقّق من معلومات دورة الحياة الرسميّة.
لذلك، إن كنتَ تبدأ ترحيلاً جديداً من .NET Framework، فالطبيعيّ، ما لم تكن ظروف استثنائيّة، اتّخاذ LTS الحالي نقطة هبوط.
التفكير العمليّ هنا بسيط.
- ترحيل صغير تريد إنهاءه سريعاً: اهبط مباشرة على LTS الحالي
- نظام أساسيّ يُشغَّل طويلاً: اتّخذ أيضاً LTS الحالي أساساً
- «نريد LTS السابق بسبب مكتبة قائمة» ظرف وارد، لكن احكم حتّى متى يُصان بالنظر إلى التاريخ
flowchart TB
accTitle: التفكير في إصدار الهبوط
accDescr: مخطّط يبيّن أنّ الأساس LTS الحالي في الترحيل الصغير والنظام الأساسيّ على حدّ سواء، وأنّ اختيار LTS السابق بسبب مكتبة قائمة يُحكَم فيه بتاريخ نهاية الصيانة.
tgt1["اختيار .NET لنقطة الهبوط"] -->|"الأساس"| lts1["الهبوط على LTS الحالي"]
tgt1 -->|"بسبب مكتبة قائمة"| old1["النظر أيضاً في LTS السابق"]
old1 --> dt1["الحكم بتاريخ نهاية الصيانة"]
الشكل 5: نقطة الهبوط أساسها LTS الحالي، وإن اخترتَ LTS أقدم فاجعل تاريخ نهاية الصيانة حجّتك.
3.2 البقاء حصريّاً على Windows، أم استهداف عابر المنصّات مستقبلاً؟
هذا الحكم يغيّر كثيراً النقاط التي ينبغي النظر إليها.
- إن بقيت حصريّاً على Windows أمكن اتّخاذ مسار واقعيّ: تحديث الـ runtime أوّلاً بـ WPF / WinForms أو حزمة التوافق مع Windows.
- إن استهدفت Linux / الحاويات مستقبلاً لزم جرد واجهات Windows في مرحلة مبكّرة:
System.Drawing.Common، والسجلّ، و WMI، و EventLog، و Windows Service، و COM، و Office Interop.
إن بدأتَ الترحيل دون تقرير هذا، التوى النقاش في المنتصف: «كان يكفي التثبيت على Windows» ثمّ «لا، كنّا نريد وضعه في حاوية».
flowchart TB
accTitle: تفرّع حصرية Windows مقابل عابر المنصّات
accDescr: مخطّط يبيّن أنّ البقاء حصريّاً على Windows يسمح بمسار واقعيّ لتحديث الـ runtime بحزمة التوافق، وأنّ استهداف Linux أو الحاويات مستقبلاً يلزم جرد واجهات Windows في مرحلة مبكّرة.
aim1["أيّهما نستهدف"] -->|"البقاء حصريّاً على Windows"| wn1["تحديث الـ runtime بحزمة التوافق"]
aim1 -->|"الحاويات مستقبلاً أيضاً"| xp1["جرد واجهات Windows مبكّراً"]
aim1 -.->|"البدء دون قرار"| twist1["يلتوي النقاش في المنتصف"]
الشكل 6: إن لم تقرّر هذا التفرّع أوّلاً، لم تتحدّد النقاط التي تُنظَر والتوى الأمر في المنتصف.
3.3 دفعة واحدة أم ترحيل تدريجيّ؟
أشكال الترحيل ثلاثة كبيرة.
- ترحيل دفعة واحدة أقرب إلى in-place
- ترحيل side-by-side يضع القديم والجديد جنباً إلى جنب
- ترحيل تدريجيّ يقترب قليلاً قليلاً بوحدة المسار / المكتبة
لتطبيقات ASP.NET Framework خصوصاً، دليل Microsoft يوجّه بوضوح إلى incremental migration. إن كنت لا تريد إيقاف الإنتاج، وكثرت الوظائف، وكثرت التبعيّات المحيطة، فأقلّ تكلّفاً أن تُصمَّم من البداية بفرضيّة الترحيل التدريجيّ.
flowchart TB
accTitle: ثلاثة أشكال للترحيل
accDescr: مخطّط يبيّن ثلاثة أشكال: ترحيل دفعة واحدة أقرب إلى in-place، وترحيل side-by-side يضع القديم والجديد جنباً إلى جنب، وترحيل تدريجيّ بوحدة المسار أو المكتبة، وأنّ شرط عدم إيقاف الإنتاج يجعل الترحيل التدريجيّ فرضيّة أقلّ تكلّفاً.
typ1["اختيار شكل الترحيل"] --> t1["ترحيل دفعة واحدة (أقرب إلى in-place)"]
typ1 --> t2["قديم وجديد متوازيان side-by-side"]
typ1 --> t3["ترحيل تدريجيّ بوحدة المسار / المكتبة"]
t3 -.-> fit1["إن لم ترد إيقاف الإنتاج فهذه الفرضيّة"]
الشكل 7: الأشكال ثلاثة، وأنظمة الإنتاج الكثيرة الوظائف التي لا تُوقَف تُوضَع على فرضيّة الترحيل التدريجيّ.
3.4 ماذا يُستبعَد من نطاق هذا الترحيل
فشل الترحيل غالباً من حشو ما يُفعَل أكثر من اللازم.
مثلاً، الجمع بين التالي يثقل الأمر غالباً.
- .NET Framework → .NET
- ASP.NET Framework → ASP.NET Core
- EF6 → EF Core
- خادم Windows → حاوية Linux
- تغيير أساس المصادقة
- تغيير أساس السجلّ / المراقبة
- ترحيل قاعدة البيانات
قد تحتاج إلى كلّ ذلك يوماً ما. لكن هل يجب فعله في الوقت نفسه مسألة أخرى.
في الواقع ينجح الأمر أكثر بالفصل كالتالي.
- حدّث أوّلاً الـ runtime وبنية المشروع
- انقل فوق ذلك نموذج التطبيق
- أخيراً حدّث ORM والمصادقة والسحابة والمراقبة
flowchart TB
accTitle: ترتيب الفصل دون حشو زائد
accDescr: مخطّط يبيّن ترتيب الفصل: تحديث الـ runtime وبنية المشروع أوّلاً، ثمّ نقل نموذج التطبيق، وأخيراً تحديث ORM والمصادقة والسحابة والمراقبة.
d1["تحديث الـ runtime والبنية"] --> d2["نقل نموذج التطبيق"]
d2 --> d3["تحديث ORM والمصادقة والسحابة والمراقبة"]
d1 -.->|"الحشو المتزامن"| hv1["يثقل الترحيل ويسهّل فشله"]
الشكل 8: لا تفعل الكلّ معاً؛ افصل بالترتيب runtime ثمّ نموذج التطبيق ثمّ المحيط فلا يثقل الأمر.
4. الأساس الذي يُجهَّز قبل البدء
دليل النقل قبل الترحيل من Microsoft عمليّ جدّاً. الخلاصة: قرّب مشروع .NET Framework الحالي، قبل الترحيل، إلى مدخل حديث.
4.1 الرفع إلى .NET Framework 4.7.2 فما فوق
الدليل الرسميّ يوصي باستهداف .NET Framework 4.7.2 فما فوق قبل النقل. السبب أنّه، حين لا يحمل .NET Standard واجهة قائمة كما هي، يسهل الاقتراب من بدائل API أحدث.
عمليّاً أوضح أن تتّخذ 4.8.1 أساساً إن أمكن.
- مستقيم من جهة الدعم
- سهل المعاملة كنقطة استقرار أخيرة لجانب .NET Framework
- يسهّل وضع سياسة «نرتّب أوّلاً جانب Framework الحالي»
ماذا يتغيّر إن فعلتَ هذا أوّلاً
- تستقرّ معاملة مكتبة مشتركة بـ
.NET Standard 2.0بسهولة أكبر - ينخفض ضجيج الـ runtime القديم مسبقاً
- يسهل فصل سبب مشكلة التوافق: أهو قِدَم Framework أم التحويل إلى modern .NET
4.2 الاقتراب من PackageReference
دليل النقل قبل الترحيل يوصي بتقريب المراجع إلى شكل PackageReference.
إن فعلتَ هذا أوّلاً، تحسّنت رؤية إدارة التبعيّات كثيراً.
ماذا يتغيّر مع PackageReference
- تتجمّع مراجع الحزم في
csproj - تصير التبعيّات الانتقاليّة أوضح
- تتوافق فرضيّات الاستعادة (restore) مع جانب modern .NET
- يتحسّن التوافق مع CLI / CI
لكن هنا ألغام.
ألغام نموذجيّة
وثائق NuGet الرسميّة تنصّ على القيود التالية عند الترحيل من packages.config إلى PackageReference.
- الترحيل المضمَّن في Visual Studio لا يُستخدم في مشاريع ASP.NET
- الحزم المعتمدة على
install.ps1/uninstall.ps1قد لا تعمل كما يُتوقَّع - أصول مجلّد
contentقد تُتجاهَل - تحويلات XDT مثل
web.config.install.xdtلا تُطبَّق - الحزم ذات بنية تجميعات قديمة مباشرة تحت
libقد لا تُحَلّ جيداً
أي لا تحسب الأمر مجرّد تغيير شكل الحزم.
ASP.NET الكلاسيكيّ خصوصاً كان كثير الاعتماد على إعادة كتابة web.config عند تثبيت حزمة NuGet، فتظهر الفرضيّات الضمنيّة بسهولة عند الترحيل.
flowchart TB
accTitle: فرضيّات ضمنيّة تظهر عند التحويل إلى PackageReference
accDescr: مخطّط يبيّن أنّ الترحيل من packages.config إلى PackageReference قد لا يطبّق install.ps1 ولا تحويلات XDT وقد يتجاهل أصول مجلّد content، فتظهر الفرضيّات الضمنيّة التي كانت تعيد كتابة web.config عند التثبيت.
cv1["التحويل إلى PackageReference"] --> np1["قد لا يعمل install.ps1"]
cv1 --> nx1["تحويلات XDT لا تُطبَّق"]
cv1 --> nc1["قد تُتجاهَل أصول content"]
np1 --> exp1["تظهر الفرضيّات الضمنيّة"]
nx1 --> exp1
nc1 --> exp1
الشكل 9: حتّى إن حسبتَ الأمر تحويل شكل فقط، تظهر دفعة واحدة الفرضيّات التي اعتمدت على حيل التثبيت.
بماذا نحوّل
ليس العمل اليدويّ وحده. لكن نطاق كلّ أداة يختلف.
| الأداة | ما تستطيعه | الفرضيّات والتنبيهات |
|---|---|---|
| وظيفة التحويل في Visual Studio | في مستكشف الحلول انقر يميناً على «المراجع» أو packages.config واختر Migrate packages.config to PackageReference... فيتمّ التحويل |
Visual Studio 2017 15.7 فما فوق. لا تُستخدم في مشاريع ASP.NET و C++. إن لم يظهر العنصر في القائمة، افتح استعادة NuGet أو مدير الحزم مرّة ثمّ انقر يميناً من جديد |
| .NET Upgrade Assistant | يُجري تحليل المشروع والترقية معاً | في الوثائق الرسميّة غير مستحسَن، والتوجيه نحو تحديث GitHub Copilot |
| تحديث GitHub Copilot | يدعم التقييم والتخطيط وتصحيح الشيفرة والتحقّق. محور التوجيه الرسميّ الحالي | كما في 4.5، الفرضيّة Visual Studio و Copilot وشيفرة C# |
| التحويل اليدويّ إلى أسلوب SDK | تنشئ csproj جديداً وتنقل البنود اللازمة فقط |
في المشاريع قليلة الملفّات قد يكون هذا الأسرع |
وظيفة التحويل في Visual Studio تصنع نسخة احتياطيّة للمشروع قبل التنفيذ، ثمّ تخرج في النهاية تقرير تحويل (تبعيّات المستوى الأعلى، تبعيّات انتقاليّة، مشكلات توافق مكتشفة). للرجوع، الوثائق تصف إعادة كتابة csproj و packages.config من مجلّد النسخة الاحتياطيّة ثمّ تنفيذ update-package -reinstall في وحدة تحكّم مدير الحزم.
أي أنّك تستطيع التجربة بشكل قابل للإعادة. في تقدير ما قبل البدء، الأسرع تحويل مشروع واحد أوّلاً وقراءة التقرير.
flowchart TB
accTitle: تجربة التحويل بشكل قابل للإعادة
accDescr: مخطّط يبيّن أنّ وظيفة التحويل في Visual Studio تصنع نسخة احتياطيّة ثمّ تحوّل وتخرج تقريراً، فيمكن تحويل مشروع واحد أوّلاً وقراءة التقرير والرجوع من النسخة الاحتياطيّة إن لزم.
bk1["تُصنَع نسخة احتياطيّة"] --> cv2["تحويل مشروع واحد فقط"]
cv2 --> rp1["قراءة تقرير التحويل"]
rp1 -->|"إن وُجدت مشكلات"| rv1["الرجوع وإعادة التثبيت"]
rp1 -->|"إن لم توجد مشكلات"| go1["التوسيع إلى مشاريع أخرى"]
الشكل 10: التحويل قابل للتجربة مع نسخة احتياطيّة وتقرير، فاختبر أوّلاً على حالة واحدة.
4.3 الاقتراب من أسلوب SDK
دليل النقل قبل الترحيل يوصي أيضاً بالتحويل إلى شكل مشروع أسلوب SDK.
هذا مؤثّر جدّاً.
ماذا يتغيّر مع أسلوب SDK
- يصير
csprojأبسط بكثير - يتوافق جيداً مع
PackageReference - يسهل الاستهداف المتعدّد (multi-targeting)
- يسهل الاقتراب من CI/CD يتمحور حول
dotnet build/dotnet test/dotnet publish - يقترب التكوين من جانب modern .NET فينخفض الفرق لاحقاً
بالمقابل: القفز فجأة إلى modern .NET مع csproj قديم وإدارة NuGet قديمة يجعل الفرق أكبر ممّا يُطاق.
flowchart TB
accTitle: تقليل الفرق بأسلوب SDK
accDescr: مخطّط يبيّن أنّ القفز فجأة إلى modern .NET مع csproj قديم وإدارة NuGet قديمة يجعل الفرق أكبر ممّا يُطاق، لذا يُقرَّب أوّلاً إلى أسلوب SDK ليقترب التكوين من جانب modern .NET وينخفض الفرق لاحقاً.
oldp["csproj قديم + إدارة NuGet قديمة"] -.->|"قفز مفاجئ"| big1["الفرق أكبر ممّا يُطاق"]
oldp -->|"أسلوب SDK أوّلاً"| sdk1["يقترب التكوين من الجانب الحديث"]
sdk1 --> small1["ينخفض الفرق لاحقاً"]
الشكل 11: إن توسّط أسلوب SDK، صار فرق القفز إلى modern .NET أصغر بدرجة.
4.4 تحديث التبعيّات أوّلاً
هذا أيضاً وفق الدليل الرسميّ: قرّب التبعيّات إلى أحدث إصدار متاح، وإن أمكن إلى إصدار يدعم .NET Standard.
معنى فعل هذا أوّلاً
- يتّضح مبكّراً «هل تعمل هذه الحزمة على modern .NET»
- يُمنَع أن تصير التبعيّات القديمة ضجيجاً
- يسهل تحويل المكتبة المشتركة إلى
netstandard2.0 - يسهل تركيز عمل الترحيل اللاحق على «نقل الشيفرة»
flowchart TB
accTitle: معنى تحديث التبعيّات أوّلاً
accDescr: مخطّط يبيّن أنّ تحديث التبعيّات نحو الأحدث أوّلاً يكشف مبكّراً توافق modern .NET ويقلّل ضجيج التبعيّات القديمة ويسمح بتركيز عمل الترحيل اللاحق على نقل الشيفرة.
upd1["التبعيّات إلى الأحدث أوّلاً"] --> know1["يتّضح توافق modern .NET مبكّراً"]
upd1 --> noise1["ينخفض ضجيج التبعيّات القديمة"]
know1 --> foc1["لاحقاً يُركَّز على نقل الشيفرة"]
noise1 --> foc1
الشكل 12: كلّما أُنجز تحديث التبعيّات أوّلاً، تركّز عمل الترحيل نفسه على النقل.
4.5 تحقّق أيضاً من فرضيّات الأدوات الرسميّة
في آذار/مارس 2026 انتقل مركز توجيه Microsoft إلى جانب تحديث GitHub Copilot. أوفق للعمل أن تراه تدفّقاً متّصلاً يشمل التقييم والتخطيط وتصحيح الشيفرة والتحقّق، لا أن تفترض أدوات الترحيل التقليديّة وحدها.
لكن الوثائق الحاليّة تفترض Visual Studio 2026 أو سلسلة Visual Studio 2022 المدعومة، و GitHub Copilot، و شيفرة C#.
سبب الحاجة إلى هذا التحقّق
- يتغيّر ما يمكنك توقّعه من الأدوات الرسميّة
- يمكن مواءمة فرضيّات بيئة IDE / عامل البناء / الإضافات في الفريق
- يمكن الحكم بأنّه في حلول VB.NET لا تُفرِط في توقّع الأتمتة
اختلاط VB.NET في المواقع ليس نادراً. لذلك يستحقّ التحقّق أوّلاً من «إلى أيّ حدّ تساعدك أحدث الأدوات الرسميّة».
flowchart TB
accTitle: موقع الأدوات الرسميّة الحالي وفرضيّاتها
accDescr: مخطّط يبيّن أنّ .NET Upgrade Assistant صار غير مستحسَن وانتقل مركز التوجيه إلى تحديث GitHub Copilot، لكن الفرضيّة Visual Studio و Copilot وشيفرة C#، لذا يلزم حكم بعدم الإفراط في توقّع الأتمتة في حلول VB.NET.
ua1[".NET Upgrade Assistant"] -->|"غير مستحسَن وجهة التوجيه"| cp1["تحديث GitHub Copilot"]
cp1 --> pre1["الفرضيّة: Visual Studio + Copilot + C#"]
pre1 -.->|"إن اختلط VB.NET"| vb1["لا تُفرِط في توقّع الأتمتة"]
الشكل 13: انتقل مركز الأدوات إلى تحديث Copilot، والمواقع التي لا توافق فرضيّته تحتاج علاجاً.
5. تقدير الصعوبة حسب نوع المشروع
يُحكى الترحيل غالباً جملة واحدة «من .NET Framework إلى .NET»، لكن في الواقع كلّ نوع مشروع لعبة مختلفة.
5.1 إحساس تقريبيّ بالصعوبة
| النوع | إحساس الصعوبة | النقاط الرئيسيّة |
|---|---|---|
| مكتبة أصناف | منخفض إلى متوسط | توافق API، التبعيّات، تقسيم الأهداف |
| وحدة تحكّم / دفعات / بعض خدمات Windows | منخفض إلى متوسط | أسلوب التوزيع، الاعتماد الأصليّ، الإعداد |
| WinForms / WPF | متوسط | يبقى حصريّاً لـ Windows، المصمّم، واجهة طرف ثالث، محيط BinaryFormatter |
| ASP.NET MVC / Web API | متوسط إلى مرتفع | ترحيل نموذج التطبيق إلى ASP.NET Core، المصادقة، الجلسة، الإعداد، DI |
| ASP.NET Web Forms | مرتفع | فرق نموذج الشاشة كبير، فرضيّة استبدال طبقة الواجهة |
| عميل WCF | متوسط | استبدال الحزم، العقود، التكوين |
| خادم WCF | مرتفع | CoreWCF أم إعادة تصميم gRPC / HTTP API |
| تنفيذ EF6 → EF Core في الوقت نفسه | مرتفع | ORM شيء آخر، فروق السلوك، تاريخ الترحيل |
5.2 مكتبة الأصناف: المفتاح كيف تقطع «الحدود المشتركة»
مكتبات الأصناف أسهل ترحيلاً نسبيّاً. لكن ذلك فقط حين تكون المكتبة مفصولة فعلاً كما ينبغي لمكتبة.
الصعوبة ترتفع إن وُجد اعتماد مثل:
- لمس
System.Web - النظر مباشرة إلى
HttpContext.Current - إدراج أنواع WPF / WinForms في واجهة عامّة
- الميل الزائد إلى واجهات Windows مثل السجلّ و WMI و EventLog
- الاعتماد على
AppDomainأو Remoting
يسهل الفهم إن رأيتَ الأمر: خفيف إن أمكن عزل منطق العمل وحده، ثقيل إن حمل نموذج التطبيق أيضاً.
flowchart TB
accTitle: كيف تُرى ثقل مكتبة الأصناف
accDescr: مخطّط يبيّن أنّ مكتبة الأصناف التي يمكن عزل منطق العمل منها وحدها خفيفة الترحيل، وأنّها تثقل إن حملت نموذج التطبيق أيضاً مثل System.Web وأنواع الواجهة وواجهات Windows و AppDomain.
lib1["النظر إلى مكتبة الأصناف"] -->|"يمكن عزل المنطق وحده"| lt1["الترحيل خفيف"]
lib1 -->|"تحمل نموذج التطبيق"| hv2["الترحيل ثقيل"]
hv2 -.-> sm1["اعتماد System.Web وأنواع الواجهة وواجهات Windows وغيرها"]
الشكل 14: صعوبة المكتبة لا تُحدَّد بعدد الأسطر بل بكمّ نموذج التطبيق الذي تحمله.
5.3 WinForms / WPF أسهل ترحيلاً، لكنّهما يبقيان حصريَّين لـ Windows
WinForms و WPF قابلان للترحيل إلى .NET. لكن كليهما يبقيان إطارَي عمل حصريَّين لـ Windows.
إن أخطأتَ التوقّع هنا فهذا خطر.
- ما يتحسّن
- تركب runtime وميزات اللغة وأسلوب SDK في modern .NET
- يسهل تقريب CI/CD وإدارة الحزم إلى ما هو سائد اليوم
- يسهل جني بعض تحسينات الأداء وقابلية الصيانة
- ما لا يتغيّر
- الحصرية لـ Windows
- بقاء مشكلات توافق عناصر الواجهة ومكوّنات وقت التصميم
- عدم اختفاء مشكلات ActiveX / COM / DLL الأصليّة
كذلك، WinForms / WPF قد يحتاجان تحقّقاً من أثر BinaryFormatter. خصوصاً إن دخل نوع مخصّص في clipboard و drag & drop و ResX وتسلسل وقت التصميم، سهل أن يظهر الأمر عند رفع الهدف إلى .NET 9 فما فوق.
flowchart TB
accTitle: توقّعات ترحيل WinForms / WPF
accDescr: مخطّط يبيّن أنّ WinForms و WPF قابلان للترحيل إلى .NET ويركبون runtime وميزات اللغة وأسلوب SDK في modern .NET، لكن الحصرية لـ Windows لا تتغيّر، وقد يلزم التحقّق من أثر BinaryFormatter.
ui1["ترحيل WinForms / WPF"] --> gain1["يركبون فوائد modern .NET"]
ui1 --> keep1["يبقيان حصريَّين لـ Windows"]
ui1 -.-> bfc1["يلزم التحقّق من BinaryFormatter"]
الشكل 15: واجهة سطح المكتب قابلة للترحيل، لكن طابع الحصرية لـ Windows يُحمَل كما هو.
5.4 ASP.NET Framework ليس «ترحيل runtime» بل «ترحيل نموذج تطبيق»
ترحيل ASP.NET Framework إلى ASP.NET Core، حتّى في دليل Microsoft، موصوف صراحة بأنّه non-trivial. ليس لأنّ أسماء الواجهات تتغيّر فحسب، بل لأنّ الهندسة المعماريّة المفترضة مختلفة.
الفروق تظهر بسهولة في محيط:
- Hosting model
- Middleware pipeline
- Request processing model
- Session / Cache
- Authentication / Authorization
- Configuration
- Dependency Injection
- Logging / Monitoring
في تطبيقات ASP.NET Framework ما تريد التحقّق منه أوّلاً تقريباً:
- من أيّ مسار / نقطة نهاية يمكن النقل أوّلاً
- هل يمكن نزع اعتماد
System.Webمن المكتبة المشتركة - كيف توحّد المصادقة / الجلسة / معالجة الاستثناءات / السجلّ
- هل ترحّل تدريجيّاً دون إيقاف الإنتاج
التطبيقات الكبيرة خصوصاً أوفق للواقع أن تُفكَّر من البداية بفرضيّة incremental migration.
flowchart TB
accTitle: ترحيل ASP.NET ترحيل نموذج تطبيق
accDescr: مخطّط يبيّن أنّ الترحيل من ASP.NET Framework إلى ASP.NET Core ليس استبدال أسماء واجهات بل ترحيل نموذج تطبيق تتغيّر فيه الهندسة المفترضة مثل الاستضافة والوسيط والمصادقة والتكوين و DI، وأنّ التطبيقات الكبيرة أوفق بفرضيّة الترحيل التدريجيّ.
an1["ASP.NET Framework → Core"] --> am1["تتغيّر الهندسة المفترضة"]
am1 --> pts1["الاستضافة والوسيط والمصادقة والتكوين و DI"]
am1 -->|"تطبيق كبير"| inc1["التخطيط بفرضيّة incremental migration"]
الشكل 16: ترحيل ASP.NET ليس ترحيل runtime بل ترحيل نموذج تطبيق، وكلّما كبر الحجم صارت الفرضيّة تدريجيّة.
5.5 Web Forms ليس «ترحيل أصول» بل ابدأ من «تفكيك المسؤوليّات»
Web Forms ليس نفس نموذج تطبيق ASP.NET Core. لذلك، في التقدير، أأمن ألّا تفترض أنّ أصول الشاشات تُحمَل كما هي.
عمليّاً يبدأ الأمر غالباً من هذا التفكيك.
- فصل منطق الشاشة عن منطق العمل
- تفكيك المسؤوليّات المدفونة في
Page/UserControl/ViewState - تهريب منطق العمل والوصول إلى البيانات إلى مكتبة مشتركة
- إعادة تكوين الواجهة بنموذج آخر مثل Razor Pages / MVC / Blazor
أي أنّ قضايا Web Forms يهمّ فيها وجود خطّة تفكيك مسؤوليّات قبل ترحيل الـ runtime.
flowchart TB
accTitle: Web Forms يبدأ من تفكيك المسؤوليّات
accDescr: مخطّط يبيّن أنّ Web Forms ليس نفس نموذج تطبيق ASP.NET Core، لذا يُبدأ بتفكيك المسؤوليّات: فصل منطق الشاشة عن منطق العمل، وتهريب المنطق إلى مكتبة مشتركة، وإعادة تكوين الواجهة بنموذج آخر.
wf1["أصول شاشات Web Forms"] --> sep1["فصل منطق الشاشة عن منطق العمل"]
sep1 --> mv1["تهريب المنطق إلى مكتبة مشتركة"]
mv1 --> re1["إعادة تكوين الواجهة بنموذج آخر"]
wf1 -.->|"فرضيّة الحمل كما هو"| ngw1["ينهار التقدير"]
الشكل 17: Web Forms ليس ترحيل أصول؛ يُرى بفرضيّة تفكيك المسؤوليّات ثمّ إعادة التركيب بنموذج آخر.
5.6 افصل تقييم عميل WCF عن خادم WCF
هنا لا تخلط الاثنين معاً.
عميل WCF
لعميل WCF حزم NuGet مدعومة موجَّهة إلى modern .NET. لذلك، إن كنت جهة الاستدعاء فقط، فقد لا يكون الأمر ثقيلاً كما يبدو.
خادم WCF
بالمقابل، جهة استضافة خدمة WCF أمر آخر. دليل Microsoft يوجّه إلى مسارين كبيرين للتحديث:
- اتّجاه الإبقاء على توافق العملاء القائمين بـ CoreWCF
- اتّجاه الاقتراب من RPC / HTTP حديث مثل gRPC
لكن CoreWCF لا يحمل WCF كلّه كما هو، بل مجموعة فرعيّة. يناسب الحفاظ على توافق العملاء القائمين، لكن تغيير الشيفرة والاختبار فرضيّة.
flowchart TB
accTitle: WCF يُقيَّم منفصلاً بين العميل والخادم
accDescr: مخطّط يبيّن أنّ عميل WCF له حزم مدعومة لـ modern .NET وقد لا يكون ثقيلاً كما يبدو، بينما جانب الخادم يلزم اختيار الإبقاء على التوافق عبر CoreWCF أو إعادة التصميم إلى gRPC ونحوه.
wcf1["في أيّ جانب يُستخدم WCF"] -->|"عميل"| cl1["الترحيل بحزم مدعومة"]
wcf1 -->|"خادم"| sv1["اختيار المسار"]
sv1 -->|"الحفاظ على التوافق"| cw1["CoreWCF (مجموعة فرعيّة)"]
sv1 -->|"إعادة تصميم"| gr1["gRPC / HTTP API"]
الشكل 18: جهة الاستدعاء وجهة الاستضافة تختلفان صعوبة وخيارات، فلا تقدّرهما جملة واحدة.
6. اغسل التقنيات التي لا تعمل على .NET أو تعلق كما هي
هذا موضع تريد فعله قطعاً قبل البدء. لدى Microsoft قائمة بـ تقنيات عملت على .NET Framework ولا تعمل على .NET 6+.
6.1 تقنيات يسهل أن تصير إشارة حمراء
| التقنية | الحالة على .NET | كيف ينبغي التفكير |
|---|---|---|
إنشاء AppDomain مثل AppDomain.CreateDomain |
غير مدعوم | فكّر في العزل بعمليّة أخرى / حاوية / AssemblyLoadContext |
| .NET Remoting | غير مدعوم | أعد التصميم إلى IPC أو HTTP أو gRPC أو Socket أو Pipe |
| CAS / Security Transparency | غير مدعوم كحدود أمن | فكّر في نظام التشغيل / الحاوية / فصل الصلاحيّات |
System.EnterpriseServices (COM+) |
غير مدعوم | افصل التصميم المفترض على COM+ واستبدله |
| Workflow Foundation | غير مدعوم | فكّر في تقدير منفصل يشمل بدائل مثل CoreWF |
| خادم WCF | ليس كما هو مضمَّناً | اختر CoreWCF أو gRPC |
| BinaryFormatter | من .NET 9 فما فوق التنفيذ يرمي استثناء دائماً | ترحيل المُسلسِل، وتدقيق ResX / clipboard / drag & drop |
6.2 AppDomain: بقاء بعض الواجهات مسألة، والإنشاء مسألة أخرى
محيط AppDomain معقّد قليلاً.
حتّى على .NET يبقى بعض سطح الواجهة، لكن استخدام إنشاء AppDomain جديد للعزل غير مدعوم.
لذلك يلزم إعادة تصميم إن كنت تستخدم AppDomain للأغراض التالية.
- عزل الإضافات
- التخلّص من التحميل الديناميكيّ
- عزل شيفرة ثقة جزئيّة
- فصل بيئة تنفيذ مؤقّتة
ما ينبغي النظر إليه قبل الترحيل ليس فقط هل تظهر كلمة AppDomain، بل لماذا كنت تستخدم AppDomain.
flowchart TB
accTitle: الحكم يتغيّر حسب طريقة استخدام AppDomain
accDescr: مخطّط يبيّن أنّ AppDomain حتّى مع بقاء بعض الواجهات لا يدعم إنشاء AppDomain جديد للعزل، لذا ميّز استخدام النوع فقط عن غرض العزل، وأعد التصميم بعمليّة أخرى أو AssemblyLoadContext إن كان الغرض العزل.
ad1["ظهر AppDomain"] -->|"مرجع نوع أو معلومات فقط"| okc1["غالباً يمكن المضيّ كما هو"]
ad1 -->|"كان يُنشأ للعزل"| rd1["تلزم إعادة تصميم"]
rd1 --> alt1["عمليّة أخرى / حاوية / AssemblyLoadContext"]
الشكل 19: ليس وجود الكلمة بل «لماذا استُخدم» هو الذي يفصل الحاجة إلى إعادة التصميم.
6.3 Remoting أعمق ممّا يبدو
Remoting طبعاً، لكن نطاق الأثر قد يشمل أيضاً مفوَّضات غير متزامنة مثل استدعاء BeginInvoke() / EndInvoke() على مفوَّض. هذا ليس Remoting نفسه، لكنّه غير مدعوم في modern .NET، فيلزم غسله قبل الترحيل.
لذلك عند البحث انظر أيضاً إلى هذا المحيط معاً فهو أأمن.
System.Runtime.RemotingMarshalByRefObjectRealProxyBeginInvoke(/EndInvoke(
6.4 BinaryFormatter يبرز فجأة حسب إصدار الهدف
BinaryFormatter، كلّما قدُم أساس الشيفرة، وُجد «استخدام بلا وعي».
- بيانات مستديمة
- ذاكرة مؤقّتة
- حفظ الجلسة
- حالة إضافة
- clipboard / drag & drop
- ResX
- محيط مصمّم WinForms / WPF
من .NET 9 فما فوق لا يتضمّن الـ runtime تنفيذاً لـ BinaryFormatter، والواجهة ترمي دائماً PlatformNotSupportedException.
أي أنّ هذا ليس «نفكّر فيه لاحقاً» بل نقطة تُدقَّق أوّلاً لحظة تقرير إصدار الهدف.
flowchart TB
accTitle: مسار بروز BinaryFormatter
accDescr: مخطّط يبيّن أنّ BinaryFormatter يُستخدم غالباً بلا وعي في بيانات مستديمة و ResX و clipboard، وأنّ الواجهة من .NET 9 فما فوق ترمي استثناء دائماً، لذا ينبغي تدقيقه أوّلاً لحظة تقرير إصدار الهدف.
hid2["استخدام بلا وعي (ResX و clipboard وغيرهما)"] --> tg1["تقرير الهدف .NET 9 فما فوق"]
tg1 --> ex1["الواجهة ترمي استثناء دائماً"]
ex1 --> aud1["التدقيق أوّلاً لحظة التقرير"]
الشكل 20: BinaryFormatter يفعل فعله لحظة تقرير الهدف، فلا تؤجّله ودقّقه أوّلاً.
6.5 كلمات بحث تريد تنفيذ grep عليها أوّلاً
قبل البدء، مجرّد البحث بهذه الكلمات على الحلّ كلّه يغيّر المشهد كثيراً.
System.Web
HttpContext.Current
System.Runtime.Remoting
MarshalByRefObject
AppDomain
BinaryFormatter
ServiceHost
ChannelFactory
System.EnterpriseServices
Workflow
packages.config
web.config.install.xdt
install.ps1
DllImport
AxInterop
Microsoft.Office.Interop
هذا لا يعني أنّ العثور على واحدة منها إقصاء فوريّ. هو خريطة لمعرفة أين يمكن الترحيل بالمسار القياسيّ، وأين يصير مساراً منفصلاً.
أوامر البحث الفعليّة
الأداة rg (ripgrep) أو PowerShell، أيّهما شئت.
# PowerShell。ソリューション配下をまとめて検索する
Get-ChildItem -Recurse -Include *.cs,*.vb,*.config,*.csproj,*.vbproj |
Select-String -Pattern 'BinaryFormatter|System\.Runtime\.Remoting|MarshalByRefObject|AppDomain\.CreateDomain' |
Select-Object Path, LineNumber, Line
# ripgrep。まず件数で当たりを付けたいとき
rg -n --stats "BinaryFormatter|System\.Runtime\.Remoting|AppDomain\.CreateDomain" --glob "*.cs" --glob "*.vb"
ماذا تفعل بعد العثور
البحث مدخل، والحكم بعده هو العمل الحقيقيّ. لكلّ كلمة موضع تنظر إليه بعد ذلك.
| الكلمة المعثور عليها | ما تتحقّق منه بعد ذلك | موضع الهبوط |
|---|---|---|
System.Web / HttpContext.Current |
هل يمكن إخراجها من المكتبة المشتركة. هل يمكن للجهة المستدعية إعادة التعبئة في DTO | تُنزَع باستراتيجيّة 8.5 |
System.Runtime.Remoting / MarshalByRefObject / BeginInvoke |
لأيّ غرض كان الاستدعاء البعيد. بين عمليّات أم بين أجهزة أم مجرّد استدعاء غير متزامن | أعد التصميم إلى IPC أو HTTP أو gRPC أو أساس Task |
AppDomain |
استخدام اسم النوع فقط أم عزل بـ CreateDomain |
إن كان الغرض العزل فعمليّة أخرى أو AssemblyLoadContext (6.2) |
BinaryFormatter |
هل تحتاج قراءة بيانات كُتبت لاحقاً. هل يُستخدم على نحو غير مباشر عبر ResX أو clipboard | رحّل إلى مُسلسِل آخر وضع أيضاً خطّة قراءة البيانات القائمة (6.4) |
ServiceHost / ChannelFactory |
جهة الاستضافة أم جهة العميل | قيّم منفصلاً كما في 5.6 |
packages.config / install.ps1 / web.config.install.xdt |
ماذا كانت إعادة الكتابة عند التثبيت | ألغام 4.2. أعد حمل الإعداد صراحةً |
DllImport / AxInterop / Microsoft.Office.Interop |
فرضيّة عدد البتّات ومجموعة الملفّات اللازمة وقت التشغيل | إلى تحقّق bitness في 9.4 |
إن وصلت إلى هنا، لم يعد السؤال «هل يمكن الترحيل» بل قائمة «ما يسير بالمسار القياسيّ، وما يحتاج تقديراً منفصلاً». ما تريده قبل البدء هو بالضبط قائمة بهذا الشكل.
flowchart TB
accTitle: من البحث إلى القائمة
accDescr: مخطّط يبيّن أنّ البحث مدخل، وأنّ تتبّع موضع التحقّق التالي لكلّ كلمة معثور عليها يحوّل الأمر إلى قائمة بما يسير بالمسار القياسيّ وما يحتاج تقديراً منفصلاً.
grep1["غسل الحلّ بكلمات البحث"] --> nxt1["تتبّع موضع التحقّق التالي لكلّ كلمة"]
nxt1 --> map1["تصير قائمة مسار قياسيّ وتقدير منفصل"]
grep1 -.-> note2["العثور ليس إقصاء فوريّاً"]
الشكل 21: البحث نفسه مدخل؛ إن تقدّمت إلى الحكم صار الشكل قائمة تريدها قبل البدء.
7. قرّر إلى أيّ حدّ تقبل فرضيّة حصرية Windows
سوء فهم شائع في الترحيل: «إن انتقلت إلى .NET صرتَ عابر المنصّات». لا سحر كهذا. إن كان التطبيق مربوطاً بعمق بـ Windows، بقي بعد الترحيل حصريّاً لـ Windows كالعادة.
7.1 الترحيل مع البقاء حصريّاً على Windows واقعيّ تماماً
لدى Microsoft Windows Compatibility Pack، وهي وسيلة تجعل كثيراً من واجهات Windows مثل السجلّ و WMI و EventLog و Windows Service و Directory Services قابلة للاستخدام من modern .NET.
وجودها كبير في العمل.
- نريد الانتقال أوّلاً إلى modern .NET
- لكن لن نخرج من Windows مؤقّتاً
- لذلك نريد قبول اعتماد Windows API مؤقّتاً
في مثل هذه المواقع يصير خياراً قويّاً.
هدف الترحيل الأوّل ليس بالضرورة عبور المنصّات.
7.2 لكن واجهات Windows الحصريّة «دَين يفعل فعله لاحقاً» أيضاً
وجود حزمة التوافق مع Windows لا يعني الاطمئنان إلى كلّ شيء.
- تريد وضعه في حاوية Linux
- تريد تشغيله بفرضيّة Kubernetes
- تريد أن يشغّل مطوّرو macOS / Linux نفس البناء
- تريد مستقبلاً تقليل أجهزة Windows الافتراضيّة في السحابة
إن وُجدت أهداف كهذه، فأولى أن تُظهر اعتماد Windows API من الآن.
flowchart TB
accTitle: موضع استخدام حزمة التوافق والدَين
accDescr: مخطّط يبيّن أنّه إن لم تخرج من Windows مؤقّتاً أمكن الانتقال إلى modern .NET بقبول اعتماد Windows API مؤقّتاً عبر حزمة التوافق، لكن إن استهدفت الحاويات أو السحابة مستقبلاً فذلك الاعتماد دَين يفعل فعله لاحقاً وينبغي إظهاره من الآن.
now1["نريد الانتقال أوّلاً إلى modern .NET"] -->|"البقاء على Windows مؤقّتاً"| pack1["قبول الاعتماد مؤقّتاً بحزمة التوافق"]
pack1 -.->|"إن استهدفت الحاويات والسحابة مستقبلاً"| debt1["الاعتماد دَين يفعل فعله لاحقاً"]
debt1 --> vis1["أظهِره من الآن"]
الشكل 22: حزمة التوافق جسر واقعيّ، لكن ذلك الاعتماد قد يصير دَيناً حسب الهدف فأظهِره.
7.3 System.Drawing.Common خصوصاً سهل إساءة فهمه
System.Drawing.Common من .NET 6 فما فوق مكتبة حصريّة لـ Windows.
إن وُجدت شيفرة تستخدمها لمعالجة الصور أو رسم النصّ، قرّر أوّلاً أيّ المسارين تسلك.
- هل تشغّل على Windows كما هو
- أم تريد التشغيل لاحقاً على Linux / macOS أيضاً
الأوّل قد يكفي مؤقّتاً كما هو. الثاني يلزم إدراج الاستبدال بـ SkiaSharp أو ImageSharp في خطّة الترحيل من البداية.
flowchart TB
accTitle: تفرّع System.Drawing.Common
accDescr: مخطّط يبيّن أنّ System.Drawing.Common من .NET 6 فما فوق مكتبة حصريّة لـ Windows، فقد يكفي مؤقّتاً كما هو إن بقي التشغيل على Windows، ويلزم إدراج الاستبدال بـ SkiaSharp أو ImageSharp في الخطّة من البداية إن أردت التشغيل لاحقاً على Linux أو macOS أيضاً.
sd1["يُستخدم System.Drawing.Common"] -->|"التشغيل على Windows كما هو"| ok4["قد يكفي مؤقّتاً كما هو"]
sd1 -->|"نريد التشغيل على Linux / macOS أيضاً"| repl1["الاستبدال بـ SkiaSharp / ImageSharp"]
repl1 --> plan2["يُدرَج في خطّة الترحيل من البداية"]
الشكل 23: System.Drawing.Common حصريّ لـ Windows، فتنقسم معاملته من البداية حسب نقطة الهبوط.
7.4 روائح نموذجيّة تدلّ على التثبيت على Windows
إن وُجدت مراجع أو واجهات كالتي تلي، فأأمن أن تقدّر بفرضيّة «الترحيل أوّلاً مع البقاء حصريّاً على Windows».
Microsoft.Win32.RegistrySystem.ManagementSystem.Diagnostics.EventLogSystem.ServiceProcessSystem.DirectoryServicesSystem.DrawingDllImport/ P/Invoke- مراجع COM
AxInterop.*Microsoft.Office.Interop.*
8. طريقة عزل المكتبة المشتركة تغيّر الصعوبة
في الحلول الأكبر ليس مبالغة أن نقول: نجاح الترحيل يُحسَم بطريقة قطع المكتبة المشتركة.
8.1 صنّف أوّلاً
يسهل الترتيب إن قسّمت المكتبات إلى ثلاثة أنواع كبيرة.
- منطق عمل / منطق مجال خالص
- طبقة وسطى تعتمد قليلاً على نموذج التطبيق
- طبقة ملتصقة بالواجهة / الويب / واجهات Windows
ما ينبغي نقله أوّلاً من هذه هو 1.
- الحساب
- الحكم بالقواعد
- DTO / العقود
- خدمات المجال
- تحويل بيانات بسيط
إن أمكن إخراج هذا نظيفاً، انخفضت الصعوبة دفعة واحدة.
flowchart TB
accTitle: ثلاثة أصناف للمكتبات وترتيب النقل
accDescr: مخطّط يبيّن تقسيم المكتبات إلى ثلاثة أنواع: منطق عمل خالص، وطبقة وسطى تعتمد قليلاً على نموذج التطبيق، وطبقة ملتصقة بالواجهة أو واجهات Windows، وأنّ ما يُنقَل أوّلاً هو منطق العمل الخالص.
c1["منطق عمل خالص"] -->|"يُنقَل أوّلاً"| ez1["إن أخرج نظيفاً انخفضت الصعوبة"]
c2["طبقة وسطى أقرب إلى نموذج التطبيق"] -->|"بعد ذلك"| ez1
c3["طبقة ملتصقة بالواجهة وواجهات Windows"] -->|"أخيراً"| ez1
الشكل 24: صُنِّفت المكتبات ثلاث طبقات، وتُنقَذ منطق العمل الخالص بالترتيب.
8.2 netstandard2.0 جسر ما زال نافعاً
توجيه Microsoft يقول: إن كانت مكتبة مشتركة تحتاج التعايش أيضاً مع جانب .NET Framework، فالأساس التفكير أوّلاً في .NET Standard 2.0.
هنا نقطتان مهمّتان.
- .NET Framework لا يدعم
.NET Standard 2.1 - إن أردت أن تُرجَع المكتبة المشتركة من القديم والجديد كليهما، يسهل أن يصير 2.0 الحلّ الواقعيّ
flowchart TB
accTitle: جسر اسمه netstandard2.0
accDescr: مخطّط يبيّن أنّ .NET Framework لا يدعم .NET Standard 2.1، لذا إن أردت أن تُرجَع المكتبة المشتركة من القديم والجديد كليهما يسهل أن يصير .NET Standard 2.0 الحلّ الواقعيّ.
fw1["جانب .NET Framework"] -->|"يمكن الرجوع"| ns1["مكتبة مشتركة netstandard2.0"]
mn1["جانب modern .NET"] -->|"يمكن الرجوع"| ns1
ns21["netstandard2.1"] -.->|"Framework غير مدعوم"| fw1
الشكل 25: جسراً يُرجَع إليه من القديم والجديد، يصير 2.0 الحلّ الواقعيّ لا 2.1.
8.3 ماذا يتغيّر عند التحويل إلى netstandard2.0
| السياسة | ماذا يتغيّر | الحالة المناسبة | تنبيه |
|---|---|---|---|
التحويل إلى netstandard2.0 |
يسهل الرجوع من القديم والجديد | منطق عمل خالص، عقود مشتركة، أدوات مساعدة | لا تُحمَل واجهات خاصّة بنموذج التطبيق |
استهداف متعدّد (مثال: net48;net10.0) |
يمكن الإبقاء على شيفرة مشتركة مع فروق حسب البيئة | مكتبة فيها فرق بيئة قليل | تزيد التفاريع الشرطيّة وإدارة البناء |
التخصيص فجأة لـ net10.0 |
الأنظف مستقبلاً | طبقة جديدة لا تحتاج تعايش قديم / جديد | لا يمكن الرجوع إليها من .NET Framework |
8.4 وضع التوافق ليس عصا سحريّة
لـ .NET Standard 2.0 وضع توافق يرجع إلى مكتبات .NET Framework. لكن هذا ليس سحراً يعمل كلّ شيء بشفافيّة.
مثلاً، مكتبة تفترض واجهات خاصّة بنموذج تطبيق مثل WPF صعبة كالعادة. أي أنّ المهمّ، حتّى إن سُمِّيت مكتبة مشتركة، تضييقها إلى المسؤوليّات التي يمكن اشتراكها فعلاً.
8.5 مكتبات عائلة ASP.NET: الرهان هل يمكن نزع System.Web
عند الترحيل التدريجيّ لـ ASP.NET Framework، إن تعلّقت المكتبة المشتركة مباشرة بـ HttpContext.Current أو System.Web فالأمر شاقّ جدّاً.
الاستراتيجيّة الأساسيّة عندئذ واحدة ممّا يلي.
- ادفع اعتماد
System.Webإلى خارج الواجهة - غيّر الاستقبال بحيث تصل معلومات أصلها
HttpContextكـ DTO - استخدم محوّلاً (adapter) في فترة الانتقال
- إن تعذّر ذلك فانزع تدريجيّاً باستهداف متعدّد
8.6 ارفع المكتبات leaf-first
دليل incremental migration لـ ASP.NET ينصّ صراحة على رفع المكتبات الداعمة postorder depth-first، أي من الأوراق بالترتيب.
هذا نافذ جدّاً أيضاً في الحلول العامّة لا الويب وحده.
- التبعيّات مرفوعة أوّلاً فتصير رؤية الطبقة العليا أوضح
- يسهل حصر مشكلات التوافق موضعيّاً
- يسهل الاختبار بوحدة المكتبة
flowchart TB
accTitle: الرفع leaf-first
accDescr: مخطّط يبيّن أنّ رفع المكتبات الداعمة من أوراق التبعيّة بالترتيب يجعل التبعيّات منجَزة أوّلاً فتصير رؤية الطبقة العليا أوضح ويسهل حصر مشكلات التوافق والاختبار بوحدة المكتبة.
lf1["رفع مكتبات أوراق التبعيّة أوّلاً"] --> lf2["رفع الطبقة الوسطى بعد إنجاز التبعيّات"]
lf2 --> lf3["أخيراً طبقة التطبيق العليا"]
lf1 -.-> loc1["يمكن حصر المشكلة واختبارها"]
الشكل 26: إن رُفعت الأوراق بالترتيب، كانت الأرضيّة جاهزة حين تصل إلى الطبقة العليا.
9. اجرد NuGet والتبعيّات الخارجيّة ومكوّنات الطرف الثالث
إن عومل هذا باستخفاف، كان أشدّ الألم في النصف الثاني من الترحيل.
9.1 يسهل الترتيب إن قسّمت التبعيّات أربعة أنواع
- حزم NuGet عامّة
- حزمة خاصّة داخليّة / مكتبة داخليّة
- مرجع DLL محلّيّ
- COM / ActiveX / DLL أصليّ / SDK
النظر إلى 1 وحده لا يكفي. الخطر الحقيقيّ في 3 و 4.
flowchart TB
accTitle: أربعة أصناف للتبعيّات ودرجة الخطر
accDescr: مخطّط يبيّن تقسيم التبعيّات إلى أربعة أنواع: NuGet عامّ، وحزم داخليّة، ومرجع DLL محلّيّ، و COM أو ActiveX أو DLL أصليّ، وأنّ النظر إلى NuGet العامّ وحده لا يكفي وأنّ الخطر الحقيقيّ في DLL المحلّيّ وعائلة COM والأصليّ.
dp1["جرد التبعيّات"] --> k1["NuGet عامّ وحزم داخليّة"]
dp1 --> k3["مرجع DLL محلّيّ"]
dp1 --> k4["COM / ActiveX / DLL أصليّ"]
k3 --> dg1["الخطر الحقيقيّ في هذا الجانب"]
k4 --> dg1
الشكل 27: عدّ NuGet العامّ وحده لا يكفي؛ اغسل أوّلاً DLL المحلّيّ وعائلة COM والأصليّ.
9.2 ما تريد التحقّق منه لكلّ تبعيّة
لكلّ تبعيّة تحقّق على الأقلّ إلى هذا الحدّ.
- هل تستهدف modern .NET
- هل تدعم
PackageReference - هل لا مشكلة مع أسلوب SDK
- هل ثمّة قيد x86 / x64 / ARM64
- هل تعتمد على أدوات وقت التصميم أو إضافات Visual Studio
- هل تفترض سكربت تثبيت / تحويل إعداد
- هل الدعم مستمرّ
9.3 قدّر واجهة الطرف الثالث / التقارير / مكوّنات وقت التصميم إطاراً منفصلاً
في ترحيل WinForms / WPF / ASP.NET هذا مؤثّر جدّاً.
- شبكة
- محرّك تقارير
- مكوّن إخراج PDF
- مكوّن رسوم بيانيّة
- مكتبة واجهة مدمجة مع المصمّم
- غلاف ActiveX
هذه تتداخل مع دعم وقت التصميم لا الـ runtime وحده. إن نظرت في تقدير الترحيل إلى «هل تُترجَم» فقط، أخطأت كالعادة.
9.4 انظر حتماً إلى DLL الأصليّ و bitness
حتّى إن بدا في عصر .NET Framework أنّه يعمل بـ AnyCPU، قد يكون معتمداً على مثل:
- COM مثبت على
x86 - ActiveX حصريّ 32-bit
- إصدار معيّن من VC++ Runtime
- DLL أصليّ موقَّع
هذا ليس مشكلة نبتت فجأة بتحويل modern .NET، بل قيود كانت موجودة أصلاً وتظهر على السطح. لذلك يستحقّ إظهارها قبل الترحيل.
flowchart TB
accTitle: ظهور قيود bitness على السطح
accDescr: مخطّط يبيّن أنّه حتّى إن بدا العمل بـ AnyCPU فقد يكون الاعتماد على COM مثبت على x86 أو ActiveX حصريّ 32-bit أو إصدار معيّن من VC++ Runtime، وأنّ هذه قيود كانت موجودة أصلاً وتظهر بتحويل modern .NET.
any1["بدا أنّه يعمل بـ AnyCPU"] -.-> hid3["اعتماد على COM مثبت على x86 و ActiveX 32-bit وغيرهما"]
hid3 --> surf1["الترحيل يُظهر قيوداً كانت موجودة أصلاً"]
surf1 --> pre2["أظهِرها قبل الترحيل"]
الشكل 28: مشكلة bitness لا يخلقها الترحيل؛ تتّضح فقط قيود كانت موجودة أصلاً.
10. عَامِل EF6 والمُسلسِلات ومحيط البيانات كمشكلة منفصلة
ترحيل الـ runtime وإعادة تصميم الوصول إلى البيانات والتسلسل ينجحان أكثر إن عوملا قدر الإمكان كمشكلتين منفصلتين.
10.1 EF6 → EF Core ليس ترقية مباشرة
حتّى دليل EF من Microsoft يقول إنّ EF Core إعادة كتابة كاملة لـ EF6 ولا يوجد مسار ترقية مباشرة.
لذلك، في التطبيقات التي تستخدم EF6، الترتيب الواقعيّ كالتالي.
- انتقل أوّلاً إلى modern .NET
- إن لزم أبقِ EF6 وشغّل التطبيق
- بعد ذلك رحّل إلى EF Core مشروعاً منفصلاً
لا تجمع ترحيل الـ runtime وترحيل ORM. بهذا وحده تنخفض الصعوبة كثيراً.
flowchart TB
accTitle: ترحيل EF6 والـ runtime منفصلين
accDescr: مخطّط يبيّن أنّ EF Core إعادة كتابة كاملة لـ EF6 ولا يوجد مسار ترقية مباشرة، لذا الترتيب الواقعيّ الانتقال أوّلاً إلى modern .NET، والإبقاء على EF6 إن لزم وتشغيله، ثمّ الترحيل لاحقاً إلى EF Core مشروعاً منفصلاً.
e1["الانتقال أوّلاً إلى modern .NET"] --> e2["إن لزم التشغيل مع الإبقاء على EF6"]
e2 --> e3["لاحقاً الترحيل إلى EF Core مشروعاً منفصلاً"]
e1 -.->|"إن فُعلا معاً"| mix1["تختلط فروق سلوك ORM ويثقل الأمر"]
الشكل 29: لا تحرّك الـ runtime و ORM معاً؛ الواقعيّ نقل الـ runtime أوّلاً مع الإبقاء على EF6.
10.2 ماذا يتغيّر إن أبقيتَ EF6
- الجانب الحسن
- يمكن تأجيل فرق طبقة الوصول إلى البيانات
- يمكن التركيز على ترحيل منطق العمل ونموذج التطبيق
- لا تختلط «فروق سلوك EF Core»
- تنبيهات
- من جهة التطوير الجديد EF Core هو الرهان الأساسيّ
- أشكال استخدام EF6 Designer / EDMX لها قيود أخرى
10.3 EF6 القائم على EDMX يُنظَر إليه حتّى «وقت التصميم»
وثائق EF6 تقول إنّ EF Designer غير مدعوم مباشرة في مشاريع .NET / .NET Standard ومشاريع .NET Framework بأسلوب SDK.
في التطبيقات القائمة على EDMX يلزم التفكير في هذه الثلاث منفصلة.
- هل يعمل وقت التشغيل
- هل يمكن استخدام المصمّم
- كيف تُعامَل الشيفرة المولَّدة
إن كثر استخدام EDMX، فأأمن إدراج هذا في التقدير من البداية.
10.4 BinaryFormatter والتسلسل الخاصّ يسهل أن يصيرا «اعتماداً خفيّاً»
المُسلسِلات سهلة الإغفال إن اقتصرت على بحث الشيفرة.
- صيغة الاستدامة
- التراسل
- الذاكرة المؤقّتة
- عقود WCF / SOAP قديمة
- ResX
- الحافظة / drag & drop
هذا المحيط يتداخل أيضاً مع توافق البيانات. أي أنّ التحقّق لازم لا عند «هل نجح البناء» فحسب، بل حتّى هل يمكن قراءة البيانات القديمة.
11. أدرج التكوين والتوزيع والتشغيل و CI/CD في نطاق الترحيل
نطاق الترحيل ليس الشيفرة المصدريّة وحدها.
11.1 ملفّات الإعداد
في جانب .NET Framework قد يحمل app.config / web.config قدراً كبيراً.
- connection string
- قسم إعداد مخصّص
- إعداد نقطة نهاية WCF
- binding redirect
- diagnostics
- إعدادات ASP.NET المتنوّعة
- ناتج التحويل عند تثبيت الحزمة
في جانب modern .NET قد تتغيّر طريقة حمل التكوين ومسار القراءة. لذلك «ملفّات الإعداد لاحقاً» خطر.
ما يُفعَل أوّلاً هو جرد الإعداد.
- ماذا يوجد في ملفّ الإعداد
- أيّه لازم عند إقلاع التطبيق
- أيّه فرق بيئة
- أيّه كان يُحقَن تلقائيّاً عبر NuGet أو المثبّت
11.2 أسلوب التوزيع
انظر أيضاً إلى شكل التوزيع قبل البدء.
- تحت IIS؟
- Windows Service؟
- Scheduled Task؟
- ClickOnce / MSI / مثبّت خاصّ؟
- فرضيّة خادم في الموقع؟
- أيّهما أنسب: self-contained أم framework-dependent؟
حتّى إن انتقل متن التنفيذ، إن بقيت آليّة التوزيع والإقلاع على فرضيّة قديمة علقت في النهاية.
11.3 السجلّ والمراقبة وإجراءات التشغيل
محيط التشغيل أيضاً سهل الإغفال.
- فرضيّة Windows Event Log؟
- هل يُنظَر إلى Performance Counter؟
- مراقبة قائمة على WMI؟
- هل حساب الخدمة والصلاحيّات ثابتان؟
- هل جهة إخراج السجلّ فرضيّة ملفّ محلّيّ؟
وارد تماماً أن تعمل الشيفرة بعد الترحيل ولا يدور التشغيل.
11.4 CI/CD وعامل البناء
قبل الترحيل تحقّق أيضاً ممّا يلي.
- هل يدخل .NET SDK اللازم عامل البناء
- كيف تُعامَل أنابيب تفترض
nuget.exe/msbuild.exe - هل تُقرَّب إلى أساس
dotnetCLI - كيف تُحدَّث وظائف تنفيذ الاختبارات و coverage و publish
- هل القوالب الداخليّة والأنابيب القابلة لإعادة الاستخدام تفترض شكلاً قديماً
يعمل على بيئة المطوّر المحلّيّة ويموت CI أمر شائع في الترحيل.
flowchart TB
accTitle: نطاق الترحيل ليس الشيفرة وحدها
accDescr: مخطّط يبيّن أنّه حتّى إن انتقل متن التنفيذ، إن بقيت ملفّات الإعداد وأسلوب التوزيع والتشغيل مثل السجلّ والمراقبة و CI/CD وعامل البناء على فرضيّة قديمة علقت في النهاية، لذا تُدرَج هذه أيضاً في نطاق الترحيل.
code1["ترحيل الشيفرة المصدريّة"] --> also1["لا ينتهي عند ذلك"]
also1 --> cfg1["ملفّات الإعداد وأسلوب التوزيع"]
also1 --> ops1["السجلّ والمراقبة وإجراءات التشغيل"]
also1 --> ci1["CI/CD وعامل البناء"]
ci1 -.-> gotcha1["يعمل محلّيّاً ويموت CI"]
الشكل 30: لا يُعَدّ نطاق الترحيل مكتملاً إلا بعد إدراج الإعداد والتوزيع والتشغيل و CI/CD.
12. طريقة تقدّم واقعيّة للترحيل
إن وُضعت النقاط حتّى هنا، سقطت طريقة التقدّم الواقعيّة تقريباً إلى الشكل التالي.
12.1 رتّب أوّلاً جانب Framework الحالي
- قرّب إلى .NET Framework 4.7.2 فما فوق، ويفضَّل 4.8.1
- ارفع التبعيّات
- راجع
packages.config - قرّب قدر الإمكان إلى
PackageReferenceوأسلوب SDK - تأكّد أنّ التطبيق الحالي يعمل في هذه الحالة
بهذا وحده ينخفض الفرق لاحقاً كثيراً.
12.2 أنقذ المكتبة المشتركة أوّلاً
بعد ذلك قرّب منطق العمل والعقود المشتركة إلى netstandard2.0 أو استهداف متعدّد.
ترتيب الرفع أساسه leaf-first.
12.3 غيّر استراتيجيّة متن التطبيق حسب نموذج التطبيق
- مكتبة أصناف / وحدة تحكّم / بعض الخدمات يسهل التقدّم على نحو مستقيم نسبيّاً
- WinForms / WPF حدّث مع البقاء حصريّاً على Windows
- ASP.NET MVC / Web API دفعة واحدة إن صغر، وتدريجيّ إن ثقل
- Web Forms بفرضيّة استبدال أصول الشاشات، هرّب المنطق المشترك أوّلاً
- خادم WCF قرّر أوّلاً الإبقاء عبر CoreWCF أم إعادة التصميم إلى gRPC
12.4 التزم «لا تفعل الكلّ دفعة واحدة»
ما ينبغي تجنّبه خصوصاً تركيبات كهذه.
- ترحيل runtime + استبدال ORM كاملاً
- ترحيل runtime + تغيير أساس المصادقة
- ترحيل runtime + ترحيل سحابة شامل
- ترحيل runtime + تغيير أساس المراقبة
- ترحيل runtime + تجديد إطار الواجهة
حتّى إن لزم الكلّ، ينجح الأمر في الغالب أكثر إن لم تُكدَّس في نفس السبرنت.
12.5 تحرّك بعد أخذ الاختبارات وخطّ الأساس
على الأقلّ تريد تجهيز هذا القدر قبل الحركة.
- اختبارات وحدة
- اختبارات تكامل لتدفّقات العمل الرئيسيّة
- تأكيد لقطيّ لشاشات / واجهات نموذجيّة
- خطّ أساس للأداء
- طريقة التحقّق من السجلّات الرئيسيّة
- إجراء التراجع
المضيّ في حالة لا تستطيع فيها تحديد «ماذا انكسر» بعد الترحيل خطر جدّاً.
flowchart TB
accTitle: ما يُجهَّز قبل الحركة
accDescr: مخطّط يبيّن أنّ تجهيز الاختبارات وخطّ أساس الأداء وطريقة التحقّق من السجلّ وإجراء التراجع قبل الحركة في الترحيل يسمح بتحديد ماذا انكسر بعد الترحيل، وأنّ المضيّ بلا تجهيز خطر.
prep1["تجهيز الاختبارات وخطّ الأساس"] --> mv2["ثمّ الحركة في الترحيل"]
mv2 --> det1["يمكن تحديد ماذا انكسر"]
non2["المضيّ بلا تجهيز"] -.-> risk1["خطر: الانكسار دون تحديد"]
الشكل 31: الترحيل يُحسَم بالتجهيز قبل الحركة، وخطّ الأساس وحده يسمح بتحديد موضع الانكسار.
13. قائمة التحقّق قبل البدء
نضعها بشكل يمكن لصقه كما هو في إدارة المشروع.
13.1 السياسة
- يمكن قول سبب الترحيل في جملة واحدة
- تقرّر هل نقطة هبوط هذه المرّة modern .NET حصريّ لـ Windows أم عبور المنصّات مستقبلاً
- تقرّر إصدار .NET المستهدَف
- تقرّر ما لا يُدرَج في نطاق هذه المرّة (تحويل EF Core، تجديد المصادقة، ترحيل سحابة شامل، إلخ)
13.2 تجهيز جانب .NET Framework الحالي
- قُرِّب إلى .NET Framework 4.7.2 فما فوق، ويفضَّل 4.8.1
- رُفعت التبعيّات نحو الأحدث
- غُسل وجود
packages.config - تُحقِّق من إمكان التحويل إلى
PackageReference - تُحقِّق من إمكان التحويل إلى أسلوب SDK
- التطبيق الحالي يُبنَى ويُقلَع ويُختبَر في هذه الحالة
13.3 نوع التطبيق واختيار التقنية
- فُصلت الصعوبة حسب النوع: مكتبة أصناف / سطح مكتب / ويب / WCF وغيرها
- مفهوم أنّ WinForms / WPF يبقيان حصريَّين لـ Windows
- مفهوم أنّ ASP.NET Framework ترحيل نموذج تطبيق إلى ASP.NET Core
- أُدرج استبدال طبقة واجهة Web Forms في التقدير
- قُيِّم WCF منفصلاً بين العميل والخادم
13.4 تقنيات غير مدعومة وواجهات تستحق الحذر
- غُسل اعتماد
AppDomain - غُسل Remoting /
MarshalByRefObject/BeginInvoke/EndInvoke - غُسل CAS / Security Transparency / COM+ / WF
- غُسل اعتماد BinaryFormatter
- غُسل اعتماد
System.Web
13.5 الاعتماد الحصريّ على Windows
- غُسل استخدام السجلّ و WMI و EventLog و Windows Service و Directory Services
- غُسل استخدام
System.Drawing.Common - غُسل COM / ActiveX / Office Interop / P/Invoke / DLL أصليّ
- تُحقِّق من قيود x86 / x64 / ARM64
13.6 المكتبة المشتركة والوصول إلى البيانات
- صُنِّفت المكتبة المشتركة إلى منطق عمل / طبقة ملتصقة بنموذج التطبيق
- غُسل ما يمكن تحويله إلى
netstandard2.0 - غُسلت المكتبات التي تحتاج استهدافاً متعدّداً
- حُكم هل يمكن نقل الـ runtime أوّلاً مع الإبقاء على EF6
- تُحقِّق من اعتماد EDMX / المصمّم
13.7 التشغيل والبناء
- جُردت ملفّات الإعداد
- تُحقِّق من أسلوب التوزيع (IIS / Service / MSI / ClickOnce وغيرها)
- تُحقِّق من فرضيّات السجلّ / المراقبة / الصلاحيّات / حساب التنفيذ
- تُحقِّق هل يلزم تحديث CI/CD وعامل البناء
- وُضع إجراء التراجع
14. الخلاصة
المهمّ في ترحيل .NET Framework إلى .NET ليس «بأيّ أمر ننقل» بقدر رؤية ما يسير كما هو وما هو مشكلة منفصلة، قبل البدء.
إن ضيّقنا النقاط فهذه الستّ.
- ترتيب جانب .NET Framework قبل الترحيل
- فصل الصعوبة حسب نموذج التطبيق
- غسل التقنيات غير القابلة للاستخدام أوّلاً
- تقرير إلى أيّ حدّ تُقبَل فرضيّة حصرية Windows
- تقرير كيف تُقطَع المكتبة المشتركة
- عدم حشو ORM والمصادقة وترحيل السحابة معاً أكثر من اللازم
في الترحيل تتغيّر دقّة التقدير كثيراً في الأسبوع الأوّل. بالمقابل، إن رُتِّبت النقاط في ذلك الأسبوع، أمكن تقريب النصف الثاني كثيراً إلى تطوير عاديّ.
flowchart TB
accTitle: كيف يُستخدم الأسبوع الأوّل
accDescr: مخطّط يبيّن أنّ ترتيب النقاط في الأسبوع الأوّل حول ما يسير كما هو وما هو مشكلة منفصلة يرفع دقّة التقدير ويسمح بتقريب النصف الثاني كثيراً إلى تطوير عاديّ.
wk1["ترتيب النقاط في الأسبوع الأوّل"] --> est1["ترتفع دقّة التقدير"]
est1 --> nor1["يُقرَّب النصف الثاني إلى تطوير عاديّ"]
wk1 -.-> pts2["فصل ما يسير كما هو عمّا هو مشكلة منفصلة"]
الشكل 32: إمكان استخدام الأسبوع الأوّل للجرد هو الذي يحسم دقّة الترحيل كلّه.
«لنغيّر أوّلاً إلى net10.0 ونرى» ليس سيّئاً كاستكشاف.
لكن كترحيل إنتاج، ثمّة ما ينبغي النظر إليه قبل ذلك. وهذا المقال رتّب بالضبط ذلك الموضع.
15. روابط مرجعية
- Microsoft Learn, Prerequisites for porting to .NET
- Microsoft Learn, Overview of porting from .NET Framework to .NET
- Microsoft Learn, .NET Framework technologies unavailable on .NET
- Microsoft Learn, What is GitHub Copilot app modernization
- Microsoft Learn, Install GitHub Copilot app modernization
- Microsoft Learn, Overview of the .NET Upgrade Assistant. غير مستحسَن حالياً، والتوجيه نحو تحديث GitHub Copilot.
- Microsoft, Official .NET support policy
- Microsoft Learn, Microsoft .NET and .NET Core lifecycle. قائمة تواريخ بدء الدعم وانتهائه لكلّ إصدار.
- Microsoft, .NET Framework official support policy
- Microsoft Learn, Migrate from ASP.NET to ASP.NET Core using tools
- Microsoft Learn, Migrate from ASP.NET to ASP.NET Core
- Microsoft Learn, Get started with incremental ASP.NET to ASP.NET Core migration
- Microsoft Learn, Use the Windows Compatibility Pack to port code to .NET
- Microsoft Learn, .NET Standard
- Microsoft Learn, Cross-platform targeting for .NET libraries
- Microsoft Learn, Migrating from packages.config to PackageReference
- Microsoft Learn, PackageReference in project files
- Microsoft Learn, BinaryFormatter migration guide
- Microsoft Learn, Windows Forms BinaryFormatter migration guide
- Microsoft, WCF Client Support Policy
- Microsoft, CoreWCF Support Policy
- Microsoft Learn, Why migrate WCF to ASP.NET Core gRPC
- Microsoft Learn, Port from EF6 to EF Core
- Microsoft Learn, What’s new in EF6
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
إدارة إصدارات مخطّط قاعدة بيانات تطبيقات الأعمال ── ممارسات الترحيل لمنع «اختلاف قاعدة البيانات من عميل لآخر»
دليل عمليّ لإدارة إصدارات مخطّط قاعدة بيانات تطبيقات الأعمال الموزَّعة على عملاء متعدّدين. نشرح PRAGMA user_version وتنفيذ الترحيل الأمام...
إلى متى ستستمر تطبيقات VB6 في العمل ── وضع دعم بيئة التشغيل والمسار العملي للترحيل إلى .NET
إلى متى تستمر تطبيقات VB6 في العمل؟ نرتّب وضع بيئة التشغيل المشمولة حتى في Windows 11 وانتهاء دعم بيئة التطوير، وجدول القرار بين إعادة ال...
لماذا تتعطّل الوسائط ── قواعد وسائط سطر أوامر Windows
في Windows لا توجد مصفوفة وسائط؛ يصل إلى CreateProcess سلسلة واحدة ويتولّى الطرف المستقبل تقسيمها. نشرح قواعد CommandLineToArgvW وCRT و.N...
استخدام WMI/CIM من C# وPowerShell ── دليل عمليّ لاسترجاع معلومات العتاد ومراقبة العمليّات والاستعلام عن بُعد
الإجابة الكلاسيكيّة للحصول على الرقم التسلسليّ للحاسوب، ومراقبة المساحة الحرّة على القرص، وكشف بدء عمليّة هي WMI/CIM. يشرح المقال أوامر C...
CI/CD عمليّ لتطبيقات WinForms / WPF ── أتمتة البناء والتوقيع والتوزيع عبر GitHub Actions
دليل عمليّ لبناء CI/CD لتطبيقات WinForms / WPF عبر GitHub Actions. يشمل YAML الأدنى للبناء والاختبار على windows-latest، وترقيم الإصدار ا...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
دعم إعادة استخدام الأصول القديمة وترحيلها
لأنه ترتيب لأصول قائمة تتشابك فيها .NET Framework وWeb Forms وWCF وCOM / ActiveX وأسلوب قديم في إدارة NuGet، فهو محتوى يتناسب مع موضوع استشارة ترحيل الأصول القديمة.
الاستشارات التقنية ومراجعة التصميم
إذا أردتم قبل البدء ترتيب نطاق الترحيل، وكيفيّة تقسيم مراحله، والمدى المسموح به لافتراض الاعتماد على Windows وحده، فهو موضوع يسهل التقدّم فيه ضمن الاستشارة التقنيّة ومراجعة التصميم.
الأسئلة الشائعة
أسئلة شائعة حول موضوع هذه المقالة.
- ما الذي ينبغي فعله أوّلاً قبل ترحيل .NET Framework إلى .NET؟
- قبل التنفيذ، رتّب جانب .NET Framework أوّلاً. دليل Microsoft الرسميّ يوصي أيضاً، قبل النقل، بالرفع إلى .NET Framework 4.7.2 فما فوق (عمليّاً 4.8.1 إن أمكن)، وتحويل packages.config إلى PackageReference، والاقتراب من أسلوب SDK، وتحديث التبعيّات نحو الأحدث. إن أنجزتَ هذا أوّلاً، انخفض فرق تحويل modern .NET لاحقاً كثيراً، وسهل فصل سبب مشكلة التوافق: أهو قِدَم Framework أم التحويل إلى .NET. ومع ذلك اجرد التقنيات غير المدعومة مثل AppDomain و Remoting و BinaryFormatter قبل البدء.
- هل يمكن أن يكون البقاء على .NET Framework قراراً صحيحاً؟
- نعم، وهذا وارد. يبقى .NET Framework 4.8.1 مدعوماً ما دام يعمل على إصدار Windows مدعوم، فالمسألة ليست أنّ إبقاء كلّ شيء خارج modern .NET خطر فوريّ. إن كان لديك كمّ كبير من شاشات Web Forms، أو حاجة صارمة لتوافق خادم WCF، أو اعتماد عميق على Workflow Foundation أو COM+، أو مكوّنات تصميم طرف ثالث غير مدعومة، فمن المعقول الاقتراب مؤقّتاً من 4.8.1 للتشغيل المستقرّ ووضع خطّة استبدال على مسار آخر. لكن تبقى قيود: لا تخرج من حصرية Windows، ويصعب جني أداء .NET الجديد وميزات اللغة.
- ما التقنيات التي لا تنتقل إلى .NET، أو تعلق بسهولة؟
- إنشاء AppDomain، و .NET Remoting، و CAS (أمن وصول الشيفرة)، و COM+ (System.EnterpriseServices)، و Workflow Foundation غير مدعومة في modern .NET، وهي إشارات حمراء تتطلّب إعادة تصميم. خادم WCF لا يعمل كما هو مضمَّناً، فتختار CoreWCF أو إعادة تصميم إلى gRPC / HTTP API. BinaryFormatter من .NET 9 فما فوق لا يتضمّن تنفيذاً ويرمي استثناء دائماً، فيلزم تدقيق يشمل البيانات المستديمة و ResX و clipboard / drag & drop. كذلك install.ps1 / تحويلات XDT في packages.config، و DLL الأصليّة، و COM / ActiveX، وفرضيّة x86 نقاط تستحق الحذر: قد يسقط التشغيل أو وقت التصميم رغم نجاح البناء.
- إن رحّلتُ تطبيق WinForms أو WPF إلى .NET، هل يصير عابر المنصّات؟
- لا. WinForms / WPF يبقيان إطارَي عمل حصريَّين لـ Windows حتّى بعد الترحيل إلى .NET. ما تكسبه هو فوائد runtime وميزات اللغة وأسلوب SDK وتوافق CI/CD في modern .NET، لا القدرة على العمل في حاويات Linux. إن استهدفت Linux / الحاويات مستقبلاً، اجرد في مرحلة مبكّرة واجهات Windows مثل System.Drawing.Common والسجلّ و WMI و EventLog و Windows Service و COM و Office Interop. بالمقابل، إن بقيت حصريّاً على Windows، يمكن اتّخاذ مسار واقعيّ: تحديث الـ runtime أوّلاً بحزمة التوافق مع Windows.
الملف الشخصي للمؤلف
صفحة الملف الشخصي لمؤلف المقالة.
غو كومورا
مؤسّس شركة كومورا سوفت ذ.م.م.
يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.