وُلد هذا المنشور من تجربتنا في ترحيل مشروع موجود من ASP.NET MVC إلى ASP.NET Core. حاولنا تجميع عملية الترحيل بأكملها في شكل منظم ووصف الاختناقات المختلفة بحيث يمكن للمطورين الاستمرار في الاعتماد على هذه المواد واتباع خريطة الطريق في حل هذه المشاكل.
بضع كلمات عن مشروعنا. نحن عبارة عن منصة إلكترونية مفتوحة المصدر على ASP.NET ، والتي كانت موجودة بالفعل بحلول وقت النقل بنجاح لمدة 9 سنوات. لقد قمنا بالهجرة منذ عامين - لكن أيدينا جاءت لتكتب عنها الآن فقط. في ذلك الوقت ، كنا أحد المشاريع الكبرى الأولى التي قررت هذه الخطوة.
لماذا التبديل إلى ASP.NET Core؟
قبل متابعة خطوات الترحيل من ASP.NET MVC إلى ASP.NET Core ، بضع كلمات حول فوائد هذا النظام الأساسي.

فوائد ASP.NET الأساسيةلذلك ، يعد ASP.NET Core بالفعل إطارًا معروفًا ومطورًا إلى حد ما ، وقد خضع بالفعل للعديد من التحديثات الرئيسية ، مما يعني أنه اليوم مستقر تمامًا ومتقدم تقنيًا ومقاوم لهجمات XSRF / CSRF.
تعد Cross -
platform واحدة من السمات المميزة التي تسمح له باكتساب المزيد والمزيد من الشعبية. من الآن فصاعدًا ، يمكن تشغيل تطبيق الويب الخاص بك في بيئتي Windows و Unix.
Modularity - ASP.NET Core يأتي بالكامل في شكل حزم NuGet ، وهذا يتيح لك تحسين التطبيق ، بما في ذلك الحزم اللازمة المحددة. هذا يحسن أداء الحل ويقلل من الوقت الذي يستغرقه لترقية الأجزاء الفردية. هذه هي الميزة الثانية المهمة التي تتيح للمطورين دمج الميزات الجديدة بمرونة أكبر في حلهم.
الأداء هو خطوة أخرى نحو إنشاء تطبيق عالي الأداء ، حيث يقوم ASP.NET Core بمعالجة 2300٪ من الطلبات في الثانية الواحدة من ASP.NET 4.6 ، و 800٪ من الطلبات في الثانية الواحدة من node.js. يمكنك فحص اختبارات الأداء التفصيلية بنفسك
هنا أو
هنا .
Middleware هو خط أنابيب جديد عالي الأداء وخفيف الوزن للطلبات داخل التطبيق. كل جزء من البرامج الوسيطة يعالج طلب HTTP ، ثم يقرر إرجاع النتيجة ، أو يمر الجزء التالي من البرنامج الوسيط. هذا النهج يمنح المطور السيطرة الكاملة على خط أنابيب HTTP ويساهم في تطوير وحدات بسيطة للتطبيق ، وهو أمر مهم لمشروع مفتوح المصدر متزايد.
يوفر ASP.NET Core MVC ميزات تبسط تطوير الويب. تستخدم NopCommerce بالفعل ميزات مثل قالب Model-View-Controller ، بناء جملة Razor ، ربط النموذج والتحقق منه ، ولكن ظهرت أدوات جديدة:
- علامة المساعدين. هذا هو رمز جانب الخادم للمساهمة في إنشاء وتقديم عناصر HTML في ملفات Razor.
- عرض المكونات. هذه أداة جديدة ، تشبه طرق العرض الجزئية ، لكنها أكثر قوة. يستخدم nopCommerce مكونات العرض عند إعادة استخدام منطق التقديم وعندما تكون المهمة معقدة للغاية بالنسبة للعرض الجزئي.
- عرض دي. على الرغم من أن معظم البيانات المعروضة في المشاهدات يتم تمريرها من وحدة التحكم ، إلا أن nopCommerce لديها طرق عرض يكون فيها حقن التبعية أكثر ملاءمة.
بالطبع ، يحتوي ASP.NET Core على المزيد من الميزات ، لكننا درسنا أكثر الميزات إثارة للاهتمام.
الآن دعنا نتحدث عن ما يجب مراعاته عند نقل التطبيق الخاص بك إلى منصة جديدة.
الهجرة
سيحتوي النص على عدد كبير من الروابط إلى وثائق ASP.NET Core الرسمية للمساعدة في الحصول على مزيد من المعلومات المفصلة حول الموضوع. مناسب بشكل خاص للمطورين الذين يواجهون مهمة مماثلة لأول مرة.
الخطوة 1. إعداد الأدوات
أول شيء عليك القيام به هو ترقية Visual Studio 2017 إلى الإصدار 15.3 أو أعلى. وقم بتثبيت أحدث إصدار من .NET Core SDK.
قبل بدء الترحيل ، يوصى باستخدام أداة تحليل
إمكانية نقل .NET
.Net Portability Analyzer . هذه نقطة انطلاق جيدة لفهم مدى صعوبة الانتقال من منصة إلى أخرى. ولكن ، بالطبع ، هذه الأداة لا تحل جميع المشاكل ، وفي هذه العملية سيكون هناك العديد من المزالق. بعد ذلك ، سيتم توضيح المراحل الرئيسية التي ستحتاج إلى النجاح ، وسيتم عرض الحلول المستخدمة في مشروعنا.
أول ما تحتاج إليه هو تحديث الروابط إلى المكتبات المستخدمة في المشروع والتي تدعم .NET Standard.
الخطوة 2. تحليل التوافق لحزم NuGet لدعم .Net Standard
إذا كنت تستخدم حزم NuGet في مشروعك ، فأنت بحاجة إلى التحقق مما إذا كانت متوافقة مع .NET Core. طريقة واحدة للقيام بذلك هي استخدام أداة
NuGetPackageExplorer .
الخطوة 3. يستخدم .NET Core تنسيق ملف csproj الجديد
من المهم استخدام الطريقة الجديدة لإضافة ارتباطات الجهات الخارجية المقدمة في .NET Core: عند إضافة مكتبة فئة جديدة إلى الحل ، يجب عليك فتح ملف المشروع الرئيسي واستبدال محتوياته بما يلي:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.6" /> ... </ItemGroup> ... </Project>
سيتم تنزيل الروابط من المكتبات المتصلة تلقائيًا. يمكن العثور على مزيد من المعلومات حول التعيين بين خصائص project.json و CSPROJ في الوثائق الرسمية
هنا وهنا .
الخطوة 4. تحديث مساحة الاسم
يجب إزالة جميع استخدامات System.Web واستبدالها بـ Microsoft.AspNetCore.
الخطوة 5. يجب عليك تكوين ملف Startup.cs. بدلا من استخدام global.asax
يحتوي ASP.NET Core على آلية جديدة لتحميل التطبيق. تصبح نقطة إدخال التطبيق
Startup
، ويختفي التبعية على ملف
Global.asax .
Startup
يسجل مجموعة الوسيطة في التطبيق. يجب أن يتضمن
Startup
طريقة
Configure
. في
Configure
أضف الوسيطة المطلوبة إلى خط الأنابيب.
مشاكل بدء التشغيل- تكوين الوسيطة لطلبات MVC و WebAPI
- إعدادات التكوين لـ:
app.UseMvc(routes => { routes.MapRoute("areaRoute", "{area:exists}/{controller=Admin}/{action=Index}/{id?}"); routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
في الوقت نفسه ، يجب وضع المجلد الذي يحمل اسم المنطقة ، والذي يوجد داخله مجلد المسؤول ، في جذر التطبيق. الآن ، سيتم استخدام السمة
[Area("Admin")] [Route("admin")]
لتوصيل وحدة التحكم بهذه المنطقة.
يبقى فقط إنشاء طرق عرض لجميع الإجراءات الموضحة في وحدة التحكم.
[Area("Admin")] [Route("admin")] public class AdminController : Controller { public IActionResult Index() { return View(); } }
التحقق من صحةالآن لا تحتاج إلى تمرير IFormCollection إلى وحدات التحكم ، لأنه في هذه الحالة يتم تعطيل التحقق من صحة خادم asp.net - تقوم MVC بقمع مزيد من التحقق من الصحة إذا تم العثور على IFormCollection. يمكن أن يكون حل المشكلة هو إضافة هذه الخاصية إلى النموذج ، مما سيمنعنا من الانتقال مباشرة إلى طريقة التحكم. هذه القاعدة صالحة فقط في حالة وجود نموذج ، ولكن في حالة عدم وجود نموذج ، فلن يكون هناك أي تحقق.
لم يتم التحقق من صحة الخصائص الفرعية تلقائيًا. يجب أن يكون محددًا يدويًا.
الخطوة 6. نقل معالجات HTTP ووحدات HTTP إلى البرامج الوسيطة
تشبه معالجات HTTP ووحدات HTTP أساسًا مفهوم
الوسيطة في ASP.NET Core ، ولكن على عكس الوحدات النمطية ، يعتمد ترتيب الوسيطة على الترتيب الذي يتم به إدراجها في خط أنابيب الطلب. يعتمد ترتيب الوحدات ، في معظمه ، على أحداث
دورة حياة التطبيق . ترتيب البرامج الوسيطة للإجابات هو عكس ترتيب الطلبات ، وترتيب الوحدات النمطية للطلبات والإجابات هو نفسه ، وبناءً على ذلك ، يمكنك متابعة الترقية.
لذلك ، ما تبقى ليتم تحديثه:
- ترحيل وحدات البرامج الوسيطة (مصادقة البرامج الوسيطة ، Culture Middledleware ، وما إلى ذلك)
- معالجات الوسيطة
- باستخدام الوسيطة الجديدة
لا تستخدم المصادقة في مشروعنا نظام بيانات الاعتماد المدمج ؛ ولهذه الأغراض ، يتم استخدام AuthenticationMiddleware الوسيطة ، المطورة وفقًا لبنية ASP.NET Core الجديدة.
public class AuthenticationMiddleware { private readonly RequestDelegate _next; public AuthenticationMiddleware(IAuthenticationSchemeProvider schemes, RequestDelegate next) { Schemes = schemes ?? throw new ArgumentNullException(nameof(schemes)); _next = next ?? throw new ArgumentNullException(nameof(next)); } public IAuthenticationSchemeProvider Schemes { get; set; } public async Task Invoke(HttpContext context) { context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature { OriginalPath = context.Request.Path, OriginalPathBase = context.Request.PathBase }); var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>(); foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync()) { try { if (await handlers.GetHandlerAsync(context, scheme.Name) is IAuthenticationRequestHandler handler && await handler.HandleRequestAsync()) return; } catch {
يوفر ASP.NET الكثير من البرامج الوسيطة المضمنة التي يمكنك استخدامها في التطبيق الخاص بك ، ولكن لاحظ أن المطور لديه القدرة
على إنشاء البرامج الوسيطة الخاصة به وإضافتها إلى خط أنابيب طلب HTTP. لتبسيط هذه الآلية ، أضفنا واجهة خاصة ، والآن يكفي إنشاء فئة تنفذها.
public interface INopStartup {
هنا يمكنك إضافة وتكوين البرامج الوسيطة الخاصة بك:
الخطوة 7. استخدام DI المتكاملة
يعد حقن
التبعية أحد الميزات الرئيسية في عملية تصميم التطبيق في ASP.NET Core. يسمح لك بإنشاء تطبيقات مترابط فضفاضة تكون أكثر قابلية للاختبار ، وحدات ، وبالتالي يمكن صيانتها. وقد أصبح ذلك ممكنًا باتباع مبدأ انعكاس التبعية. لتثبيت التبعيات ، يتم استخدام حاويات IoC (Inversion of Control). في ASP.NET Core ، يتم تمثيل هذه الحاوية بواسطة واجهة IServiceProvider. يتم تثبيت الخدمات في التطبيق في أسلوب
Startup.ConfigureServices()
.
يمكن تكوين أي خدمة مسجلة بثلاثة نطاقات:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddSingleton<Isingleton,MySingleton>();
الخطوة 8. استخدام WebAPI Project Compatibility Shells (Shim)
لتبسيط ترحيل تطبيق ويب API حالي ، يوصى باستخدام حزمة
Microsoft.AspNetCore.Mvc.WebApiCompatShim NuGet.
الوظائف المتوافقة التالية مدعومة:
- يضيف ApiController النوع
- لتمكين ربط نمط واجهة برمجة تطبيقات الويب
- يمتد ربط النموذج بحيث يمكن أن تقبل إجراءات وحدة التحكم معلمات النوع HttpRequestMessage.
- لإضافة تنسيقات الرسائل التي تسمح بإجراءات لإرجاع نتائج النوع HttpResponseMessage
services.AddMvc().AddWebApiConventions(); routes.MapWebApiRoute(name: "DefaultApi", template: "api/{controller}/{id?}" );
الخطوة 9. نقل تكوين التطبيق
في السابق ، تم حفظ بعض الإعدادات في ملف web.config. نحن
نتبع الآن
مقاربة جديدة تعتمد على أزواج القيمة الرئيسية التي أنشأها
مزودو التكوين . هذه هي الآلية الموصى بها في ASP.NET Core ، ونحن نستخدم ملف appsettings.json.
يمكنك أيضًا استخدام حزمة NuGet
System.Configuration.ConfigurationManager
إذا كنت ترغب في الاستمرار في استخدام * .config لسبب ما. في هذه الحالة ، سيكون عليك التخلي عن القدرة على تشغيل التطبيق على الأنظمة الأساسية Unix وتشغيله فقط تحت IIS.
إذا كنت ترغب في استخدام موفر تكوين
Azure Key Vault ، يجب عليك الرجوع إلى محتوى
ترحيل المحتوى
إلى Azure Key Valut . في مشروعنا ، لم تكن هذه هي المهمة.
الخطوة 10. نقل المحتوى الثابت إلى wwwroot
لتقديم
محتوى ثابت ، يجب أن تخبر مضيف الويب جذر محتويات الدليل الحالي. الافتراضي هو wwwroot. يمكنك تخصيص الدليل لتخزين الملفات الثابتة عن طريق إعداد البرامج الوسيطة.
الخطوة 11. نقل EntityFramework إلى EF الأساسية
إذا كان المشروع يستخدم بعض
الميزات المحددة
في Entity Framework 6 غير المدعومة في
EF Core
، فمن المنطقي تشغيل التطبيق على
NET Framework
. في هذه الحالة ، ومع ذلك ، عليك التضحية متعددة. سيعمل التطبيق فقط على Windows وتحت IIS.
دعنا نلقي نظرة على التغييرات الرئيسية التي يجب مراعاتها:- مساحة الاسم System.Data.Entity استبداله Microsoft.EntityFrameworkCore
- تم تغيير توقيع مُنشئ DbContext. الآن تحتاج إلى حقن DbContextOptions
- طريقة HasDatabaseGeneratedOption (DatabaseGeneratedOption.None) تم استبدالها بواسطة ValueGeneratedNever ()
- تم استبدال طريقة WillCascadeOnDelete (false) بـ OnDelete (DeleteBehavior.Restrict)
- تم استبدال طريقة OnModelCreating (DbModelBuilder modelBuilder) بواسطة OnModelCreating (ModelBuilder modelBuilder)
- طريقة HasOptional لم تعد متوفرة
- يتم تغيير تكوين الكائنات ، والآن تحتاج إلى استخدام OnModelCreating ، لأنه لم يعد EntityTypeConfiguration متاحًا
- سمة ComplexType لم تعد متوفرة
- استبدال واجهة IDbSet مع DbSet
- ComplexType - ظهر دعم من النوع المركب في EF Core 2 بنوع الكيان المملوك ( https://docs.microsoft.com/en-us/ef/core/modeling/owned-entities ) ، وجداول بدون مفتاح أساسي مع QueryType في EF Core 2.1 ( https://docs.microsoft.com/en-us/ef/core/modeling/query-types )
- تقوم المفاتيح الخارجية في EF Core بإنشاء خصائص الظل باستخدام نمط معرف [Entity] ، على عكس EF6 ، الذي يستخدم نمط _Id [Entity]. لذلك ، قم أولاً بإضافة مفاتيح خارجية كخاصية عادية إلى الكيان.
- لدعم DI لـ DbContext ، قم بتكوين DbContex الخاص بك في
ConfigureServices
استخدم أداة
مقارنة SQL للتحقق من قيام
EF Core
بإنشاء مخطط قاعدة بيانات مماثل مثل
Entity Framework
أثناء
الترحيل .
الخطوة 12. إزالة جميع المراجع HttpContext ، واستبدال فئات عفا عليها الزمن ، وتغيير مساحة الاسم
أثناء ترحيل مشروعك ، ستجد أنه قد تمت إعادة تسمية أو نقل عدد كبير بما فيه الكفاية من الفصول الدراسية ، والآن تحتاج إلى جعل كل شيء متوافقًا مع المتطلبات الجديدة. فيما يلي قائمة بالتحولات الرئيسية التي قد تواجهها:
- HttpPostedFileBase -> IFormFile
- الوصول إلى HttpContext هو الآن من خلال IHttpContextAccessor
- HtmlHelper -> IHtmlHelper
- ActionResult -> IActionResult
- HttpUtility -> WebUtility
- بدلاً من HttpSessionStateBase - ISession ، يمكن الوصول إليها من HttpContext.Session. من Microsoft.AspNetCore.Http
- Request.Cookies بإرجاع IRequestCookieCollection: IEnumerable <KeyValuePair <string ، string >> ، لذا بدلاً من HttpCookie ، KeyValuePair <string ، string> من Microsoft.AspNetCore.Http
استبدال مساحة الاسم:
- حدد قائمة -> Microsoft.AspNetCore.Mvc.Rendering
- UrlHelper -> WebUtitlity
- MimeMapping -> FileExtensionContentTypeProvider
- MvcHtmlString -> IHtmlString و HtmlString
- ModelState ، ModelStateDictionary ، ModelError -> Microsoft.AspNetCore.Mvc.ModelBinding
- FormCollection -> IFormCollection
- Request.Url.Scheme -> this.Url.ActionContext.HttpContext.Request.Scheme
أخرى:
- MvcHtmlString.IsNullOrEmpty (IHtmlString) -> String.IsNullOrEmpty (variable.ToHtmlString ())
- [ValidateInput (false)] - بشكل عام ، لم تعد هناك حاجة إليها وغير مطلوبة
- HttpUnauthorizedResult -> UnauthorizedResult
- [AllowHtml] - لا يوجد المزيد من التوجيه وليس هناك حاجة
- تم استبدال طريقة TagBuilder.SetInnerText - الآن هذا هو InnerHtml.AppendHtml
- JsonRequestBehavior.AllowGet عند العودة لم تعد هناك حاجة إلى Json
- HttpUtility.JavaScriptStringEncode. -> JavaScriptEncoder.Default.Encode
- Request.RawUrl. من الضروري توصيل Request.Path + Request.QueryString بشكل منفصل
- AllowHtmlAttribute - لا مزيد من الصف
- XmlDownloadResult - الآن يمكنك استخدام مجرد إرجاع ملف (Encoding.UTF8.GetBytes (xml) ، "application / xml" ، "filename.xml") ؛
- [ValidateInput (false)] - لم يعد هناك أي توجيه وليس هناك حاجة إليه
الخطوة 13. تحديث المصادقة والترخيص
لقد سبق أن كتبت أعلاه أنه في تطبيقنا لم يتم تنفيذ مصادقة المشروع باستخدام نظام الهوية المدمج ، ولكن يتم إخراجه في طبقة منفصلة من البرامج الوسيطة. ومع ذلك ، فإن ASP.NET Core لديه آليته الخاصة لتوفير بيانات الاعتماد. يمكن الاطلاع على مزيد من التفاصيل في الوثائق
هنا .
بالنسبة لحماية البيانات - لم نعد نستخدم
MachineKey . بدلاً من ذلك ، نستخدم ميزة حماية البيانات المضمنة. افتراضيًا ، يتم إنشاء المفاتيح عند بدء تشغيل التطبيق. يمكن أن يكون مستودع البيانات:
- نظام الملفات - ملف قائم على نظام الملفات
- Azure Storage - مفاتيح حماية البيانات في Azure Blob Storage
- Redis - مفاتيح حماية البيانات في ذاكرة التخزين المؤقت Redis
- التسجيل - يجب أن يستخدم إذا كان التطبيق لا يملك حق الوصول إلى نظام الملفات
- EF الأساسية - يتم تخزين المفاتيح في قاعدة البيانات
إذا كانت الآليات المدمجة غير مناسبة ، يمكنك تحديد آلية تخزين المفاتيح الخاصة بك عن طريق توفير
IXmlRepository مخصص.
الخطوة 14. تحديث JS / CSS
لقد تغيرت طريقة التعامل مع الموارد الثابتة: والآن يجب تخزينها جميعًا في المجلد الجذر لمشروع
wwwroot ، ما لم يتم تحديد إعدادات أخرى بالطبع.
عند استخدام javascript المضمنة في الكتل ، يوصى بنقلها إلى نهاية الصفحة. ما عليك سوى استخدام سمة asp-location = "Footer" للعلامات. تنطبق نفس القاعدة على ملفات js.
استخدم ملحق
BundlerMinifier كبديل لنظام System.Web.Optimization - سيتيح لك ذلك ربط JavaScript و CSS
وتقليلهما أثناء بناء المشروع.
رابط إلى الوثائق.
الخطوة 15. ترحيل وجهات النظر
عمليات الطفل لم تعد تستخدم. بدلاً من ذلك ، يقدم ASP.NET Core أداة قوية جديدة -
ViewComponents ، والتي تسمى بشكل غير متزامن.
كيفية الحصول على سلسلة من ViewComponent:
لم تعد هناك حاجة لاستخدام HtmlHelper - ASP.NET Core لديه عدد كبير من وظائف علامة المساعدة (
Tag Tagers ) المضمنة. عند تشغيل التطبيق ، تتم معالجته بواسطة محرك Razor على جانب الخادم ويتم تحويله في النهاية إلى عناصر html قياسية. هذا يبسط إلى حد كبير تطوير التطبيق. وبالطبع ، يمكنك تنفيذ مساعديك الوسم.
بدأنا في استخدام حقن التبعية في طرق العرض بدلاً من السماح بالإعدادات والخدمات باستخدام
EngineContext
.
لذلك ، فإن النقاط الرئيسية في هجرة وجهات النظر:
- تحويل
Views/web.config Views/_ViewImports.cshtml
- يستخدم لاستيراد مساحات الأسماء Views/web.config Views/_ViewImports.cshtml
التبعيات. لا يدعم هذا الملف وظائف Razor
الأخرى ، مثل تعريفات الوظيفة والقسم. - تحويل
namespaces.add
إلى @using
- نقل أي إعدادات لتكوين التطبيق الرئيسي
Scripts.Render
و Styles.Render
غير موجود. استبدل libman
أو BundlerMinifier
بروابط للإخراج
في الختام
لقد رأينا من تجربتنا أن عملية ترحيل تطبيق ويب كبير هي مهمة تستغرق وقتًا طويلًا للغاية ولا يمكن تنفيذها بدون صعوبات. لقد خططنا للتبديل إلى إطار عمل جديد بمجرد إصدار أول إصدار ثابت له ، لكننا لم نتمكن من الانتهاء منه على الفور: كانت هناك بعض الوظائف الهامة التي لم يتم نقلها حتى الآن إلى .NET Core ، على وجه الخصوص ، المتعلقة بـ EntityFramework. لذلك ، كان علينا أولاً إصدار الإصدار التالي باستخدام نهج مختلط - بنية .NET Core مع تبعيات .NET Framework.
تمكنا من تكييف المشروع بالكامل بعد إصدار .NET Core 2.1 ، بعد أن كان هناك حل ثابت يعمل بالفعل على الهيكل الجديد - كل ما تبقى هو استبدال بعض الحزم وإعادة كتابة العمل مع EF Core. وهكذا ، فإن الهجرة الكاملة إلى الإطار الجديد استغرقت عدة أشهر من العمل.
يمكنك معرفة المزيد حول مشروعنا من
مستودعنا على جيثب .