كيفية ترقية مشروع موجود من ASP.NET MVC إلى ASP.NET Core. دليل عملي

وُلد هذا المنشور من تجربتنا في ترحيل مشروع موجود من 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 أضف الوسيطة المطلوبة إلى خط الأنابيب.

مشاكل بدء التشغيل

  1. تكوين الوسيطة لطلبات MVC و WebAPI
  2. إعدادات التكوين لـ:


 //add basic MVC feature var mvcBuilder = services.AddMvc(); //add custom model binder provider (to the top of the provider list) mvcBuilder.AddMvcOptions(options => options.ModelBinderProviders.Insert(0, new NopModelBinderProvider())); /// <summary> /// Represents model binder provider for the creating NopModelBinder /// </summary> public class NopModelBinderProvider : IModelBinderProvider { /// <summary> /// Creates a nop model binder based on passed context /// </summary> /// <param name="context">Model binder provider context</param> /// <returns>Model binder</returns> public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); var modelType = context.Metadata.ModelType; if (!typeof(BaseNopModel).IsAssignableFrom(modelType)) return null; //use NopModelBinder as a ComplexTypeModelBinder for BaseNopModel if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType) { //create binders for all model properties var propertyBinders = context.Metadata.Properties .ToDictionary(modelProperty => modelProperty, modelProperty => context.CreateBinder(modelProperty)); return new NopModelBinder(propertyBinders, EngineContext.Current.Resolve<ILoggerFactory>()); } //or return null to further search for a suitable binder return null; } } 



 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 { // ignored } } var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); if (defaultAuthenticate != null) { var result = await context.AuthenticateAsync(defaultAuthenticate.Name); if (result?.Principal != null) { context.User = result.Principal; } } await _next(context); } } 

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

 public interface INopStartup { /// <summary> /// Add and configure any of the middleware /// </summary> /// <param name="services">Collection of service descriptors</param> /// <param name="configuration">Configuration of the application</param> void ConfigureServices(IServiceCollection services, IConfiguration configuration); /// <summary> /// Configure the using of added middleware /// </summary> /// <param name="application">Builder for configuring an application's request pipeline</param> void Configure(IApplicationBuilder application); /// <summary> /// Gets order of this startup configuration implementation /// </summary> int Order { get; } } 

هنا يمكنك إضافة وتكوين البرامج الوسيطة الخاصة بك:

 /// <summary> /// Represents object for the configuring authentication middleware on application startup /// </summary> public class AuthenticationStartup : INopStartup { /// <summary> /// Add and configure any of the middleware /// </summary> /// <param name="services">Collection of service descriptors</param> /// <param name="configuration">Configuration of the application</param> public void ConfigureServices(IServiceCollection services, IConfiguration configuration) { //add data protection services.AddNopDataProtection(); //add authentication services.AddNopAuthentication(); } /// <summary> /// Configure the using of added middleware /// </summary> /// <param name="application">Builder for configuring an application's request pipeline</param> public void Configure(IApplicationBuilder application) { //configure authentication application.UseNopAuthentication(); } /// <summary> /// Gets order of this startup configuration implementation /// </summary> public int Order => 500; //authentication should be loaded before MVC } 

الخطوة 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

 /// <summary> /// Register base object context /// </summary> /// <param name="services">Collection of service descriptors</param> public static void AddNopObjectContext(this IServiceCollection services) { services.AddDbContextPool<NopObjectContext>(optionsBuilder => { optionsBuilder.UseSqlServerWithLazyLoading(services); }); } /// <summary> /// SQL Server specific extension method for Microsoft.EntityFrameworkCore.DbContextOptionsBuilder /// </summary> /// <param name="optionsBuilder">Database context options builder</param> /// <param name="services">Collection of service descriptors</param> public static void UseSqlServerWithLazyLoading(this DbContextOptionsBuilder optionsBuilder, IServiceCollection services) { var nopConfig = services.BuildServiceProvider().GetRequiredService<NopConfig>(); var dataSettings = DataSettingsManager.LoadSettings(); if (!dataSettings?.IsValid ?? true) return; var dbContextOptionsBuilder = optionsBuilder.UseLazyLoadingProxies(); if (nopConfig.UseRowNumberForPaging) dbContextOptionsBuilder.UseSqlServer(dataSettings.DataConnectionString, option => option.UseRowNumberForPaging()); else dbContextOptionsBuilder.UseSqlServer(dataSettings.DataConnectionString); } 

استخدم أداة مقارنة 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:

 /// <summary> /// Render component to string /// </summary> /// <param name="componentName">Component name</param> /// <param name="arguments">Arguments</param> /// <returns>Result</returns> protected virtual string RenderViewComponentToString(string componentName, object arguments = null) { if (string.IsNullOrEmpty(componentName)) throw new ArgumentNullException(nameof(componentName)); var actionContextAccessor = HttpContext.RequestServices.GetService(typeof(IActionContextAccessor)) as IActionContextAccessor; if (actionContextAccessor == null) throw new Exception("IActionContextAccessor cannot be resolved"); var context = actionContextAccessor.ActionContext; var viewComponentResult = ViewComponent(componentName, arguments); var viewData = ViewData; if (viewData == null) { throw new NotImplementedException(); } var tempData = TempData; if (tempData == null) { throw new NotImplementedException(); } using (var writer = new StringWriter()) { var viewContext = new ViewContext( context, NullView.Instance, viewData, tempData, writer, new HtmlHelperOptions()); // IViewComponentHelper is stateful, we want to make sure to retrieve it every time we need it. var viewComponentHelper = context.HttpContext.RequestServices.GetRequiredService<IViewComponentHelper>(); (viewComponentHelper as IViewContextAware)?.Contextualize(viewContext); var result = viewComponentResult.ViewComponentType == null ? viewComponentHelper.InvokeAsync(viewComponentResult.ViewComponentName, viewComponentResult.Arguments): viewComponentHelper.InvokeAsync(viewComponentResult.ViewComponentType, viewComponentResult.Arguments); result.Result.WriteTo(writer, HtmlEncoder.Default); return writer.ToString(); } } 

لم تعد هناك حاجة لاستخدام 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. وهكذا ، فإن الهجرة الكاملة إلى الإطار الجديد استغرقت عدة أشهر من العمل.

يمكنك معرفة المزيد حول مشروعنا من مستودعنا على جيثب .

Source: https://habr.com/ru/post/ar472738/


All Articles