Comment mettre Ă  niveau un projet existant d'ASP.NET MVC vers ASP.NET Core. Guide pratique

Ce message est né de notre expérience de la migration d'un projet existant d'ASP.NET MVC vers ASP.NET Core. Nous avons essayé de rassembler l'ensemble du processus de migration sous une forme structurée et de décrire les divers goulots d'étranglement afin que les développeurs puissent continuer à s'appuyer sur ce matériel et suivre la feuille de route pour résoudre ces problèmes.

Quelques mots sur notre projet. Nous sommes une plate-forme de commerce électronique open source sur ASP.NET, qui, au moment du transfert, existait déjà avec succès depuis 9 ans. Nous avons fait la migration il y a 2 ans - mais nos mains ne sont venues l'écrire que maintenant. À cette époque, nous étions l'un des premiers grands projets à avoir décidé d'une telle démarche.

Pourquoi passer Ă  ASP.NET Core?


Avant de passer aux Ă©tapes de migration d'ASP.NET MVC vers ASP.NET Core, quelques mots sur les avantages de cette plateforme.



Avantages d'ASP.NET Core
Ainsi, ASP.NET Core est déjà un framework assez bien connu et développé, qui a déjà subi plusieurs mises à jour majeures, ce qui signifie qu'il est aujourd'hui assez stable, technologiquement avancé et résistant aux attaques XSRF / CSRF.

La multiplateforme est l'une des caractéristiques qui lui permettent de gagner de plus en plus en popularité. À partir de maintenant, votre application Web peut fonctionner dans les environnements Windows et Unix.

Modularité - ASP.NET Core se présente entièrement sous la forme de packages NuGet, cela vous permet d'optimiser l'application, y compris les packages nécessaires sélectionnés. Cela améliore les performances de la solution et réduit le temps nécessaire à la mise à niveau des pièces individuelles. Il s'agit de la deuxième fonctionnalité importante qui permet aux développeurs d'intégrer de manière plus flexible de nouvelles fonctionnalités dans leur solution.

Les performances sont une autre étape vers la création d'une application hautes performances, ASP.NET Core traite 2300% de requêtes en plus par seconde qu'ASP.NET 4.6, et 800% de requêtes en plus par seconde que node.js. Vous pouvez examiner vous-même les tests de performances détaillés ici ou ici .



Le middleware est le nouveau pipeline modulaire léger et hautes performances pour les requêtes in-app. Chaque élément de middleware traite une demande HTTP, puis décide de renvoyer le résultat ou transmet le morceau de middleware suivant. Cette approche donne au développeur un contrôle total sur le pipeline HTTP et contribue au développement de modules simples pour l'application, ce qui est important pour un projet open source en pleine croissance.

ASP.NET Core MVC fournit des fonctionnalités qui simplifient le développement Web. NopCommerce utilisait déjà des fonctionnalités telles que le modèle Model-View-Controller, la syntaxe Razor, la liaison et la validation de modèle, mais de nouveaux outils sont apparus:

  • Tag Helpers. Il s'agit d'un code cĂ´tĂ© serveur pour contribuer Ă  la crĂ©ation et au rendu des Ă©lĂ©ments HTML dans les fichiers Razor.
  • Afficher les composants. Il s'agit d'un nouvel outil, similaire aux vues partielles, mais beaucoup plus puissant. nopCommerce utilise des composants de vue lorsque la rĂ©utilisation de la logique de rendu est requise et lorsque la tâche est trop complexe pour une vue partielle.
  • Le point de vue de DI. Bien que la plupart des donnĂ©es affichĂ©es dans les vues proviennent du contrĂ´leur, nopCommerce a des vues dans lesquelles l'injection de dĂ©pendance est plus pratique.

Bien sûr, ASP.NET Core a beaucoup plus de fonctionnalités, mais nous venons d'examiner les plus intéressantes.

Parlons maintenant de ce que vous devez considérer lors du portage de votre application vers une nouvelle plateforme.

La migration


Le texte contiendra un grand nombre de liens vers la documentation officielle d'ASP.NET Core pour vous aider à obtenir des informations plus détaillées sur le sujet. Particulièrement pertinent pour les développeurs confrontés à une tâche similaire pour la première fois.

Étape 1. Préparation des outils


La première chose que vous devez faire est de mettre à niveau Visual Studio 2017 vers la version 15.3 ou supérieure. Et installez la dernière version du SDK .NET Core.

Avant de commencer la migration, il est recommandé d'utiliser l'outil d'analyse de portabilité .NET .Net Portability Analyzer . C'est un bon point de départ pour comprendre à quel point la transition d'une plate-forme à une autre sera laborieuse. Mais, bien sûr, cet outil ne résout pas tous les problèmes et, dans le processus, il y aura de nombreux pièges. Ensuite, les principales étapes qui devront être franchies seront décrites et les solutions utilisées dans notre projet seront présentées.

La toute première chose dont vous avez besoin est de mettre à jour les liens vers les bibliothèques utilisées dans le projet qui prendraient en charge .NET Standard.

Étape 2. Analyse de compatibilité des packages NuGet pour prendre en charge la norme .Net


Si vous utilisez des packages NuGet dans votre projet, vous devez vérifier s'ils sont compatibles avec .NET Core. Pour cela, vous pouvez utiliser l'outil NuGetPackageExplorer .

Étape 3. .NET Core utilise le nouveau format de fichier csproj


Il est important d'utiliser la nouvelle approche pour ajouter des liens tiers introduits dans .NET Core: lorsqu'une nouvelle bibliothèque de classes est ajoutée à la solution, vous devez ouvrir le fichier de projet principal et remplacer son contenu par ce qui suit:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.6" /> ... </ItemGroup> ... </Project> 

Les liens des bibliothèques connectées seront téléchargés automatiquement. Plus d'informations sur le mappage entre les propriétés project.json et CSPROJ peuvent être trouvées dans la documentation officielle ici et ici .

Étape 4. Mise à jour de l'espace de noms


Vous devez supprimer toutes les utilisations de System.Web et les remplacer par Microsoft.AspNetCore.

Étape 5. Vous devez configurer le fichier Startup.cs. au lieu d'utiliser global.asax


ASP.NET Core dispose d'un nouveau mécanisme de chargement de l'application. Le point d'entrée de l'application devient Startup et la dépendance au fichier Global.asax disparaît. Startup enregistre la suite middleware dans l'application. Startup doit inclure la méthode Configure . Dans Configure ajoutez le middleware requis au pipeline.

Problèmes Startup.cs

  1. Configuration du middleware pour les requĂŞtes MVC et WebAPI
  2. Paramètres de configuration pour:


 //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?}"); }); 

Dans le même temps, le dossier portant le nom Area, dans lequel se trouve le dossier Admin, doit être placé à la racine de l'application. Désormais, l'attribut [Area("Admin")] [Route("admin")] sera utilisé pour connecter le contrôleur à cette zone.
Il ne reste plus qu'à créer des vues pour toutes les actions décrites dans le contrôleur.


 [Area("Admin")] [Route("admin")] public class AdminController : Controller { public IActionResult Index() { return View(); } } 

Validation

Maintenant, vous n'avez pas besoin de transmettre IFormCollection aux contrôleurs, car dans ce cas, la validation du serveur asp.net est désactivée - MVC supprime toute validation supplémentaire si IFormCollection n'est pas nul. La solution au problème peut être d'ajouter cette propriété au modèle, cela nous évitera de passer directement à la méthode du contrôleur. Cette règle n'est valide que si un modèle est présent, mais s'il n'y a pas de modèle, alors il n'y aura pas de validation.

Les propriétés enfants ne sont plus automatiquement validées. Il doit être spécifié manuellement.

Étape 6. Transfert des gestionnaires HTTP et des modules HTTP vers le middleware


Les gestionnaires HTTP et les modules HTTP sont essentiellement très similaires au concept de middleware dans ASP.NET Core , mais contrairement aux modules, l'ordre des middlewares est basé sur l'ordre dans lequel ils sont insérés dans le pipeline de demande. L'ordre des modules, pour la plupart, est basé sur les événements du cycle de vie de l'application . L'ordre du middleware pour les réponses est l'inverse de l'ordre des requêtes, et l'ordre des modules pour les requêtes et les réponses est le même. Sur cette base, vous pouvez procéder à la mise à niveau.

Alors, ce qui reste Ă  mettre Ă  jour:

  • Migration de modules pour Middleware (AuthenticationMiddleware, CultureMiddleware, etc.)
  • Gestionnaires du middleware
  • Utilisation d'un nouveau middleware

L'authentification dans notre projet n'utilise pas le système d'informations d'identification intégré; à ces fins, le middleware AuthenticationMiddleware est utilisé, développé conformément à la nouvelle structure 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 fournit de nombreux middleware intégrés que vous pouvez utiliser dans votre application, mais notez que le développeur a la possibilité de créer son propre middleware et de l'ajouter au pipeline de requêtes HTTP. Pour simplifier ce mécanisme, nous avons ajouté une interface spéciale, et maintenant il suffit de créer une classe qui l'implémente.

 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; } } 

Ici, vous pouvez ajouter et configurer votre middleware:

 /// <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 } 

Étape 7. Utilisation de DI intégré


L' injection de dépendances est l'une des fonctionnalités clés du processus de conception d'application dans ASP.NET Core. Il vous permet de créer des applications à couplage lâche qui sont plus testables, modulaires et, par conséquent, maintenables. Cela a été rendu possible en suivant le principe de l'inversion de dépendance. Pour installer les dépendances, des conteneurs IoC (Inversion of Control) sont utilisés. Dans ASP.NET Core, un tel conteneur est représenté par l'interface IServiceProvider. Les services sont installés dans l'application dans la méthode Startup.ConfigureServices() .

Tout service enregistré peut être configuré avec trois étendues:

  • transitoire
  • portĂ©e
  • singleton

 services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddSingleton<Isingleton,MySingleton>(); 

Étape 8. Utilisation de shells de compatibilité de projet WebAPI (Shim)


Pour simplifier la migration d'une implémentation d'API Web existante, il est recommandé d'utiliser le package NuGet Microsoft.AspNetCore.Mvc.WebApiCompatShim . Les fonctions compatibles suivantes sont prises en charge:

  • Ajoute le type ApiController
  • Active la liaison de modèle de style API Web
  • Étend la liaison de modèle afin que les actions du contrĂ´leur puissent accepter des paramètres de type HttpRequestMessage.
  • Ajoute des formateurs de messages qui permettent aux actions de renvoyer des rĂ©sultats de type HttpResponseMessage

 services.AddMvc().AddWebApiConventions(); routes.MapWebApiRoute(name: "DefaultApi", template: "api/{controller}/{id?}" ); 

Étape 9. Transfert de la configuration de l'application


Auparavant, certains paramètres étaient enregistrés dans le fichier web.config. Nous adoptons maintenant une nouvelle approche basée sur des paires clé-valeur établies par les fournisseurs de configuration . Il s'agit du mécanisme recommandé dans ASP.NET Core et nous utilisons le fichier appsettings.json.

Vous pouvez également utiliser le package NuGet System.Configuration.ConfigurationManager si, pour une raison quelconque, vous souhaitez continuer à utiliser * .config. Dans ce cas, vous devrez abandonner la possibilité d'exécuter l'application sur les plates-formes Unix et de l'exécuter uniquement sous IIS.

Si vous souhaitez utiliser le fournisseur de configuration Azure Key Vault , vous devez vous référer au contenu Content Migration to Azure Key Valut . Dans notre projet, ce n'était pas la tâche.

Étape 10. Transfert de contenu statique vers wwwroot


Pour diffuser du contenu statique, vous devez indiquer à l'hôte Web la racine du contenu du répertoire en cours. La valeur par défaut est wwwroot. Vous pouvez personnaliser votre répertoire pour stocker des fichiers statiques en configurant un middleware.



Étape 11. Portage d'EntityFramework vers EF Core


Si le projet utilise des fonctionnalités spécifiques d'Entity Framework 6 qui ne sont pas prises en charge dans EF Core , il est logique d'exécuter l'application sur NET Framework . Dans ce cas, cependant, vous devez sacrifier la multiplateforme. L'application ne fonctionnera que sous Windows et sous IIS.

Jetons un coup d'Ĺ“il aux principaux changements Ă  prendre en compte:

  • Espace de noms System.Data.Entity remplacĂ© par Microsoft.EntityFrameworkCore
  • La signature du constructeur DbContext a Ă©tĂ© modifiĂ©e. Vous devez maintenant injecter DbContextOptions
  • MĂ©thode HasDatabaseGeneratedOption (DatabaseGeneratedOption.None) remplacĂ©e par ValueGeneratedNever ()
  • WillCascadeOnDelete (false), mĂ©thode remplacĂ©e par OnDelete (DeleteBehavior.Restrict)
  • MĂ©thode OnModelCreating (DbModelBuilder modelBuilder) remplacĂ©e par la mĂ©thode OnModelCreating (ModelBuilder modelBuilder)
  • La mĂ©thode HasOptional n'est plus disponible
  • la configuration des objets est modifiĂ©e, vous devez maintenant utiliser OnModelCreating, car EntityTypeConfiguration n'est plus disponible
  • L'attribut ComplexType n'est plus disponible
  • Remplacement de l'interface IDbSet par DbSet
  • ComplexType - la prise en charge des types complexes est apparue dans EF Core 2 avec le type EntitĂ© dĂ©tenue ( https://docs.microsoft.com/en-us/ef/core/modeling/ownedentities ) et les tables sans clĂ© primaire avec QueryType dans EF Core 2.1 ( https://docs.microsoft.com/en-us/ef/core/modeling/query-types )
  • les clĂ©s Ă©trangères dans EF Core gĂ©nèrent des propriĂ©tĂ©s d'ombre en utilisant le modèle Id [Entity], contrairement Ă  EF6, qui utilise le modèle _Id [Entity]. Par consĂ©quent, ajoutez d'abord des clĂ©s Ă©trangères en tant que propriĂ©tĂ© rĂ©gulière Ă  l'entitĂ©.
  • Pour prendre en charge DI pour DbContext, configurez votre DbContex dans 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); } 

Utilisez l'outil de comparaison SQL pour vérifier que EF Core génère un schéma de base de données similaire à Entity Framework lors de la migration .

Étape 12. Suppression de toutes les références HttpContext, remplacement des classes obsolètes et modification de l'espace de noms


Lors de la migration de votre projet, vous constaterez qu'un nombre suffisamment important de classes ont été renommées ou déplacées, et vous devez maintenant tout mettre en conformité avec les nouvelles exigences. Voici une liste des principales transitions que vous pouvez rencontrer:

  • HttpPostedFileBase -> IFormFile
  • L'accès pour accĂ©der Ă  HttpContext se fait maintenant via IHttpContextAccessor
  • HtmlHelper -> IHtmlHelper
  • ActionResult -> IActionResult
  • HttpUtility -> WebUtility
  • Au lieu de HttpSessionStateBase - ISession, est accessible Ă  partir de HttpContext.Session. de Microsoft.AspNetCore.Http
  • Request.Cookies renvoie IRequestCookieCollection: IEnumerable <KeyValuePair <chaĂ®ne, chaĂ®ne >>, donc au lieu de HttpCookie, KeyValuePair <chaĂ®ne, chaĂ®ne> de Microsoft.AspNetCore.Http

Remplacement de l'espace de noms:

  • SelectList -> Microsoft.AspNetCore.Mvc.Rendering
  • UrlHelper -> WebUtitlity
  • MimeMapping -> FileExtensionContentTypeProvider
  • MvcHtmlString -> IHtmlString et HtmlString
  • ModelState, ModelStateDictionary, ModelError -> Microsoft.AspNetCore.Mvc.ModelBinding
  • FormCollection -> IFormCollection
  • Request.Url.Scheme -> this.Url.ActionContext.HttpContext.Request.Scheme

Autre:

  • MvcHtmlString.IsNullOrEmpty (IHtmlString) -> String.IsNullOrEmpty (variable.ToHtmlString ())
  • [ValidateInput (false)] - ce n'est gĂ©nĂ©ralement plus et n'est pas nĂ©cessaire
  • HttpUnauthorizedResult -> UnauthorizedResult
  • [AllowHtml] - il n'y a plus de directive et ce n'est pas nĂ©cessaire
  • La mĂ©thode TagBuilder.SetInnerText a Ă©tĂ© remplacĂ©e - c'est maintenant InnerHtml.AppendHtml
  • JsonRequestBehavior.AllowGet lorsque le retour de Json n'est plus nĂ©cessaire
  • HttpUtility.JavaScriptStringEncode. -> JavaScriptEncoder.Default.Encode
  • Request.RawUrl. Il est nĂ©cessaire de connecter sĂ©parĂ©ment Request.Path + Request.QueryString
  • AllowHtmlAttribute - plus de classe
  • XmlDownloadResult - maintenant vous pouvez utiliser simplement renvoyer File (Encoding.UTF8.GetBytes (xml), "application / xml", "filename.xml");
  • [ValidateInput (false)] - il n'y a plus de directive et ce n'est pas nĂ©cessaire

Étape 13. Mise à jour de l'authentification et de l'autorisation


J'ai déjà écrit ci-dessus que dans notre projet, l'authentification n'est pas implémentée à l'aide du système d'identité intégré, mais est supprimée dans une couche distincte de middleware. Cependant, ASP.NET Core possède son propre mécanisme pour fournir des informations d'identification. Plus de détails peuvent être trouvés dans la documentation ici .

Quant à la protection des données - nous n'utilisons plus MachineKey . Au lieu de cela, nous utilisons la fonction de protection des données intégrée. Par défaut, les clés sont générées au démarrage de l'application. L'entrepôt de données peut être:

  • Système de fichiers - fichier de clĂ©s basĂ© sur le système de fichiers
  • Azure Storage - ClĂ©s de protection des donnĂ©es dans Azure Blob Storage
  • Redis - ClĂ©s de protection des donnĂ©es dans le cache Redis
  • Registre - doit ĂŞtre utilisĂ© si l'application n'a pas accès au système de fichiers
  • EF Core - les clĂ©s sont stockĂ©es dans la base de donnĂ©es

Si les mécanismes intégrés ne conviennent pas, vous pouvez spécifier votre propre mécanisme de stockage de clés en fournissant un IXmlRepository personnalisé.

Étape 14. Mise à jour de JS / CSS


La façon de travailler avec les ressources statiques a changé: maintenant, toutes doivent être stockées dans le dossier racine du projet wwwroot , à moins, bien sûr, que d'autres paramètres ne soient spécifiés.

Lorsque vous utilisez des blocs en ligne javascript, il est recommandé de les déplacer à la fin de la page. Utilisez simplement l'attribut asp-location = "Footer" pour vos balises. La même règle s'applique aux fichiers js.

Utilisez l'extension BundlerMinifier en remplacement de System.Web.Optimization - cela vous permettra de lier et de minimiser JavaScript et CSS lors de la construction du projet. Lien vers la documentation.

Étape 15. Migration des vues


Les actions enfants ne sont plus utilisées. Au lieu de cela, ASP.NET Core propose un nouvel outil puissant - ViewComponents , qui est appelé de manière asynchrone.

Comment obtenir une chaîne de 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(); } } 

Il n'est plus nécessaire d'utiliser HtmlHelper - ASP.NET Core dispose d'un grand nombre de fonctions de balise d'assistance ( Tag Helpers ) intégrées. Lorsque l'application est en cours d'exécution, elles sont traitées par le moteur Razor côté serveur et sont finalement converties en éléments html standard. Cela simplifie considérablement le développement d'applications. Et, bien sûr, vous pouvez implémenter vos propres balises.

Nous avons commencé à utiliser l'injection de dépendances dans les vues au lieu d'autoriser les paramètres et les services à l'aide de EngineContext .

Donc, les principaux points sur la migration des vues:

  • Convertissez Views/web.config Views/_ViewImports.cshtml - utilisĂ© pour importer des espaces de noms et Views/web.config Views/_ViewImports.cshtml dĂ©pendances. Ce fichier ne prend pas en charge d'autres fonctions Razor , telles que les dĂ©finitions de fonctions et de sections.
  • Convertir namespaces.add en @using
  • TransfĂ©rez tous les paramètres dans la configuration principale de l'application
  • Scripts.Render et Styles.Render n'existe pas. Remplacez libman ou BundlerMinifier liens vers la sortie

En conclusion


Notre expérience nous a montré que le processus de migration d'une grande application Web est une tâche très chronophage qui peut difficilement être réalisée sans écueils. Nous avions prévu de passer à un nouveau framework dès la sortie de sa première version stable, mais nous n'avons pas pu le terminer tout de suite: il y avait certaines fonctions critiques qui n'avaient pas encore été transférées vers .NET Core, en particulier, liées à EntityFramework. Par conséquent, nous avons dû d'abord publier la prochaine version en utilisant une approche mixte - l'architecture .NET Core avec les dépendances .NET Framework.

Nous avons pu adapter complètement le projet après la sortie de .NET Core 2.1, ayant à l'époque une solution stable fonctionnant déjà sur la nouvelle architecture - il ne restait plus qu'à remplacer certains packages et réécrire le travail avec EF Core. Ainsi, la migration complète vers le nouveau framework a nécessité plusieurs mois de travail.

Vous pouvez en savoir plus sur notre projet dans notre référentiel sur GitHub .

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


All Articles