paint-brush
Una guía paso a paso para migrar un proyecto de ASP.NET MVC a ASP.NET Corepor@nopcommerce
61,238 lecturas
61,238 lecturas

Una guía paso a paso para migrar un proyecto de ASP.NET MVC a ASP.NET Core

por nopCommerce17m2019/09/19
Read on Terminal Reader
Read this story w/o Javascript

Demasiado Largo; Para Leer

Una guía paso a paso para migrar un proyecto de ASP.NET MVC a .NET Core ya es un marco bastante conocido y desarrollado con varias actualizaciones importantes que lo hacen bastante estable, tecnológicamente avanzado y resistente a los ataques XSRF/CSRF. ASP.net Core maneja un 2.300 % más de solicitudes por segundo que ASP.NET 4.6 y un 800 % más que. nodo.js. La guía explica los pasos principales y las soluciones utilizadas en el proyecto nopCommerce.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Una guía paso a paso para migrar un proyecto de ASP.NET MVC a ASP.NET Core
nopCommerce HackerNoon profile picture

Guía paso por paso

Aquí hay una guía práctica sobre cómo migrar un proyecto del marco ASP.NET MVC a ASP.NET Core. Las instrucciones paso a paso escritas por el equipo del proyecto de código abierto nopCommerce se pueden aplicar fácilmente a cualquier proyecto ASP.NET MVC.

También describe por qué es posible que deba actualizar y por qué los proyectos que aún no siguen el ritmo deberían considerarlo.

¿Por qué migrar a ASP.NET Core?

Antes de continuar con los pasos para migrar de ASP.NET MVC a ASP.NET Core (usando nopCommerce como ejemplo), veamos una descripción general rápida de las ventajas de este marco.

ASP.NET Core ya es un marco bastante conocido y desarrollado con varias actualizaciones importantes que lo hacen bastante estable, tecnológicamente avanzado y resistente a los ataques XSRF/CSRF.

La multiplataforma es una de las características distintivas que la hacen cada vez más popular. A partir de ahora, su aplicación web puede ejecutarse tanto en entornos Windows como Unix.

Arquitectura modular: ASP.NET Core viene completamente en forma de paquetes NuGet, permite optimizar la aplicación, incluidos los paquetes necesarios seleccionados. Esto mejora el rendimiento de la solución y reduce el tiempo que lleva actualizar partes separadas.

Esta es la segunda característica importante que permite a los desarrolladores integrar nuevas funciones en su solución de manera más flexible.

El rendimiento es otro paso hacia la creación de una aplicación de alto rendimiento. ASP.NET Core maneja un 2.300 % más de solicitudes por segundo que ASP.NET 4.6 y un 800 % más de solicitudes por segundo que node.js.

Puede consultar las pruebas de rendimiento detalladas usted mismo aquí o aquí .

Las mejores respuestas de texto sin formato por segundo, entorno de prueba

Middleware es una nueva canalización modular ligera y rápida para solicitudes dentro de la aplicación. Cada parte del middleware procesa una solicitud HTTP y luego decide devolver el resultado o pasa la siguiente parte del middleware.

Este enfoque brinda al desarrollador control total sobre la canalización HTTP y contribuye al desarrollo de módulos simples para la aplicación, lo cual es importante para un proyecto de código abierto en crecimiento.

Además, ASP.NET Core MVC proporciona funciones que simplifican el desarrollo web. nopCommerce ya usó algunos de ellos, como la plantilla Model-View-Controller, la sintaxis de Razor, el enlace de modelos y la validación. Entre las nuevas características se encuentran:

  • Ayudantes de etiquetas. Código de parte del servidor para participar en la creación y representación de elementos HTML en archivos Razor.
  • Ver componentes. Una nueva herramienta, similar a las vistas parciales, pero de mucho mayor rendimiento. nopCommerce usa componentes de vista cuando se requiere reutilizar la lógica de representación y la tarea es demasiado compleja para una vista parcial.
  • DI en vistas. Aunque la mayoría de los datos que se muestran en las vistas provienen del controlador, nopCommerce también tiene vistas donde la inyección de dependencia es más conveniente.

Por supuesto, ASP.NET Core tiene muchas más funciones, solo vimos las más interesantes.

Ahora, consideremos los puntos a tener en cuenta al migrar su aplicación a un nuevo marco.


Migración

Las siguientes descripciones contienen una gran cantidad de enlaces a la documentación oficial de ASP.NET Core para brindar información más detallada sobre el tema y guiar a los desarrolladores que se enfrentan a esta tarea por primera vez.

Paso 1. Preparar un conjunto de herramientas

Lo primero que necesita es actualizar Visual Studio 2017 a la versión 15.3 o posterior e instalar la última versión de .NET Core SDK.

Antes de portar, recomendamos utilizar .Net Portability Analyzer . Este puede ser un buen punto de partida para comprender cuán laboriosa será la migración de una plataforma a otra. Sin embargo, esta herramienta no cubre todos los problemas, este proceso tiene muchos escollos que deben resolverse a medida que surgen.

A continuación, describiremos los pasos principales y las soluciones utilizadas en el proyecto nopCommerce.

Lo primero y más fácil de hacer es actualizar los enlaces a las bibliotecas utilizadas en el proyecto para que sean compatibles con .NET Standard.

Paso 2. Análisis de compatibilidad de paquetes NuGet para admitir el estándar .Net

Si usa paquetes NuGet en su proyecto, verifique si son compatibles con .NET Core. Una forma de hacerlo es usar la herramienta NuGetPackageExplorer .

Paso 3. El nuevo formato de archivo csproj en .NET Core

Se introdujo un nuevo enfoque para agregar referencias a paquetes de terceros en .NET Core. Al agregar una nueva biblioteca de clases, debe abrir el archivo del proyecto principal y reemplazar su contenido de la siguiente manera:

 < Project Sdk = "Microsoft.NET.Sdk" > < PropertyGroup > < TargetFramework > netcoreapp2.2 </ TargetFramework > </ PropertyGroup > < ItemGroup > < PackageReference Include = "Microsoft.AspNetCore.App" Version = "2.2.6" /> ... </ ItemGroup > ... </ Project >

Las referencias a las bibliotecas conectadas se cargarán automáticamente.

Para obtener más información sobre cómo comparar las propiedades de project.json y CSPROJ, lea la documentación oficial aquí y aquí.

Paso 4. Actualización del espacio de nombres

Elimine todos los usos de System.Web y reemplácelos con Microsoft.AspNetCore.

Paso 5. Configure el archivo Startup.cs en lugar de usar global.asax

ASP.NET Core tiene una nueva forma de cargar la aplicación. El punto de entrada de la aplicación es

 Startup
, y no hay dependencia en el archivo Global.asax.
 Startup
registra los middlewares en la aplicación.
 Startup
debe incluir la
 Configure
método. El middleware requerido debe agregarse a la canalización en
 Configure
.

Problemas a resolver en Startup.cs:

  1. Configuración de middleware para solicitudes MVC y WebAPI
  2. Configurando para:
  • Manejo de excepciones . Inevitablemente enfrentará varias colisiones durante la migración, por lo tanto, prepárese y configure el manejo de excepciones en el entorno de desarrollo. Con UseDeveloperExceptionPage , agregamos middleware para detectar excepciones.
  • Enrutamiento MVC . También se ha modificado el registro de nuevas rutas . IRouteBuilder ahora se usa en lugar de RouteCollection, como una nueva forma de registrar restricciones (IActionConstraint)
  • Filtros MVC/WebAPI. Los filtros deben actualizarse de acuerdo con la nueva implementación de ASP.NET Core .
  • Formateadores MVC/ WebAPI
  • Encuadernación de modelos
  •  //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 ; } }
  • áreas Para incluir Area en una aplicación ASP.NET Core, agregue una ruta normal al archivo Startup.cs. Por ejemplo, así buscará configurar Admin/ area
  •  app.UseMvc(routes => { routes.MapRoute( "areaRoute" , "{area:exists}/{controller=Admin}/{action=Index}/{id?}" ); routes.MapRoute( name: "default" , template: "{controller=Home}/{action=Index}/{id?}" ); });

    Al hacerlo, la carpeta con el nombre Area con la carpeta Admin dentro, debe estar en la raíz de la aplicación. Ahora el atributo

     [Area("Admin")] [Route("admin")].
    se utilizará para conectar el controlador con esta área.

    Solo queda crear vistas para todas las acciones descritas en el controlador.

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

    Validación

    IFormCollection no debe pasarse a los controladores ya que, en este caso, la validación del servidor asp.net está deshabilitada: MVC está suprimiendo la validación adicional si se encuentra que IFormCollection no es nulo. Para resolver el problema, esta propiedad podría agregarse al modelo, esto evitará que pasemos directamente al método del controlador.

    Esta regla funciona solo si hay un modelo disponible, si no hay modelo, no habrá validación.

    Las propiedades secundarias ya no se validan automáticamente y deben especificarse manualmente.

    Paso 6. Migrar controladores HTTP y HttpModules a Middleware

    Los controladores HTTP y los módulos HTTP son, de hecho, muy similares al concepto de Middleware en ASP.NET Core , pero a diferencia de los módulos, el orden del middleware se basa en el orden en que se insertan en la canalización de solicitudes. El orden de los módulos se basa principalmente en los eventos del ciclo de vida de la aplicación. El orden del middleware para las respuestas es opuesto al orden de las solicitudes, mientras que el orden de los módulos para las solicitudes y las respuestas es el mismo. Sabiendo esto, puede continuar con la actualización.

    Lo que debe actualizarse:

    • Migración de módulos para Middleware (AuthenticationMiddleware, CultureMiddleware, etc.)
    • Manejadores a Middleware
    • Uso de nuevo middleware

    La autenticación en nopCommerce no utiliza un sistema de autenticación integrado; para ello se utiliza AuthenticationMiddleware desarrollado de acuerdo con la nueva estructura 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 proporciona una gran cantidad de middleware integrado que puede usar en su aplicación, pero el desarrollador también puede crear su propio middleware y agregarlo a la canalización de solicitudes HTTP.

    Para simplificar este proceso, agregamos una interfaz especial a nopCommerce, y ahora basta con crear una clase que la implemente.

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

    Aquí puede agregar y configurar su 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 }

    Paso 7. Usando DI incorporado

    La inyección de dependencia es una de las características clave al diseñar una aplicación en ASP.NET Core. Puede desarrollar aplicaciones débilmente acopladas que sean más comprobables, modulares y, como resultado, más fáciles de mantener. Esto fue posible siguiendo el principio de inversión de dependencia.

    Para inyectar dependencias, usamos contenedores IoC (Inversion of Control). En ASP.NET Core, dicho contenedor está representado por la interfaz IServiceProvider. Los servicios se instalan en la aplicación en el método Startup.ConfigureServices().

    Cualquier servicio registrado se puede configurar con tres alcances:

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

    Paso 8. Uso de shells de compatibilidad de proyectos WebAPI (Shim)

    Para simplificar la migración de una API web existente, recomendamos usar el paquete NuGet Microsoft.AspNetCore.Mvc.WebApiCompatShim . Es compatible con las siguientes funciones compatibles :

    • Agregando el tipo ApiController;
    • Habilitación del enlace de modelo de estilo API web;
    • Ampliación del enlace de modelos para que las acciones del controlador puedan aceptar parámetros de tipo HttpRequestMessage;
    • Adición de formateadores de mensajes que permiten que las acciones devuelvan resultados del tipo HttpResponseMessage.
     services.AddMvc().AddWebApiConventions(); routes.MapWebApiRoute(name: "DefaultApi" , template: "api/{controller}/{id?}" );

    Paso 9. Configuración de la aplicación de portabilidad

    Algunas configuraciones se guardaron previamente en el archivo web.config. Ahora usamos un nuevo enfoque basado en los pares clave-valor establecidos por los proveedores de configuración . Este es el método recomendado en ASP.NET Core y usamos el archivo appsettings.json.

    También puede usar el paquete NuGet

     System.Configuration.ConfigurationManager
    si por alguna razón desea continuar usando *.config. En este caso, la aplicación no puede ejecutarse en plataformas Unix, sino solo en IIS.

    Si desea usar el proveedor de configuración de almacenamiento de claves de Azure, debe consultar Migración de contenido a Azure Key Vault . Nuestro proyecto no contenía tal tarea.

    Paso 10. Portar contenido estático a wwwroot

    Para servir contenido estático , especifique para hospedar web la raíz de contenido del directorio actual. El valor predeterminado es wwwroot. Puede configurar su carpeta para almacenar archivos estáticos configurando un middleware.

    Paso 11. Portar EntityFramework a EF Core

    Si el proyecto usa algunas características específicas de Entity Framework 6 , que no son compatibles con EF Core, tiene sentido ejecutar la aplicación en NET Framework. Aunque en este caso, tendremos que rechazar la función multiplataforma y la aplicación se ejecutará solo en Windows e IIS.

    A continuación se detallan los principales cambios a tener en cuenta:

    • El espacio de nombres System.Data.Entity se reemplaza por Microsoft.EntityFrameworkCore;
    • Se ha cambiado la firma del constructor DbContext. Ahora debe inyectar DbContextOptions;
    • El método HasDatabaseGeneratedOption(DatabaseGeneratedOption.None) se reemplaza por ValueGeneratedNever();
    • El método WillCascadeOnDelete(false) se reemplaza por OnDelete (DeleteBehavior.Restrict);
    • El método OnModelCreating(DbModelBuilder modelBuilder) se reemplaza por OnModelCreating(ModelBuilder modelBuilder);
    • El método HasOptional ya no está disponible;
    • Se cambió la configuración del objeto, ahora se usa OnModelCreating ya que EntityTypeConfiguration ya no está disponible;
    • El atributo ComplexType ya no está disponible;
    • La interfaz IDbSet se reemplaza por DbSet;
    • ComplexType: la compatibilidad con tipos complejos apareció en EF Core 2 con el tipo de entidad propia y tablas sin clave principal con QueryType en EF Core 2.1;
    • Las claves externas en EF Core generan propiedades ocultas usando la plantilla [Entity]Id, a diferencia de EF6, que usa la plantilla [Entity]_Id. Por lo tanto, primero agregue claves externas como una propiedad regular a la entidad;
    • Para admitir DI para DbContext, configure su DbContex en 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); }

    Para verificar que EF Core genera una estructura de base de datos similar a la de Entity Framework al migrar , use la herramienta SQL Compare .


    Paso 12. Eliminar todas las referencias de HttpContext y reemplazar las clases obsoletas y cambiar el espacio de nombres

    Durante la migración del proyecto, encontrará que se ha cambiado el nombre o movido una cantidad suficientemente grande de clases, y ahora debe cumplir con los nuevos requisitos. Aquí hay una lista de los principales cambios que puede encontrar:

    • HttpPostedFileBase 🡪 FormFile
    • Ahora se puede acceder a Access HttpContext a través de IHttpContextAccessor
    • HtmlHelper 🡪HtmlHelper
    • Resultado de la acción 🡪 Resultado de la acción
    • HttpUtility 🡪 WebUtility
    • ISession en lugar de HttpSessionStateBase accesible desde HttpContext.Session. de Microsoft.AspNetCore.Http
    • Request.Cookies devuelve IRequestCookieCollection: IEnumerable <KeyValuePair<cadena, cadena> >, luego, en lugar de HttpCookie, usamos KeyValuePair <cadena, cadena> de Microsoft.AspNetCore.Http

    Reemplazo del espacio de nombres:

    • Lista de selección 🡪 Microsoft.AspNetCore.Mvc.Rendering
    • UrlHelper 🡪 WebUtility
    • MimeMapping 🡪 FileExtensionContentTypeProvider
    • MvcHtmlString 🡪 IHtmlString y HtmlString
    • ModelState, ModelStateDictionary, ModelError 🡪 Microsoft.AspNetCore.Mvc.ModelBinding
    • FormCollection 🡪 IFormCollection
    • Request.Url.Scheme 🡪 this.Url.ActionContext.HttpContext.Request.Scheme

    Otro:

    • MvcHtmlString.IsNullOrEmpty(IHtmlString) 🡪 String.IsNullOrEmpty(variable.ToHtmlString())
    • [ValidateInput (falso)] - ya no existe y ya no es necesario
    • HttpResultado no autorizado 🡪 Resultado no autorizado
    • [AllowHtml] - la directiva ya no existe y ya no es necesaria
    • El método TagBuilder.SetInnerText se reemplaza por InnerHtml.AppendHtml
    • JsonRequestBehavior.AllowGet cuando ya no se necesita devolver Json
    • HttpUtility.JavaScriptStringEncode. JavaScriptEncoder.Default.Encode
    • Solicitud.RawUrl. Request.Path + Request.QueryString deben conectarse por separado
    • AllowHtmlAttribute: la clase ya no existe
    • XmlDownloadResult: ahora puede usar simplemente devolver Archivo (Codificación.UTF8.GetBytes (xml), "aplicación / xml", "nombre de archivo.xml");
    • [ValidateInput(false)] - la directiva ya no existe y ya no es necesaria

    Paso 13. Actualización de autenticación y autorización

    Como ya se mencionó anteriormente, el proyecto nopCommerce no involucra el sistema de autenticación incorporado, se implementa en una capa de middleware separada.

    Sin embargo, ASP.NET Core tiene su propio sistema para proporcionar credenciales. Puede ver la documentación para conocerlos en detalle.

    En cuanto a la protección de datos, ya no usamos MachineKey . En su lugar, utilizamos la función de protección de datos integrada. De forma predeterminada, las claves se generan cuando se inicia la aplicación. Como el almacenamiento de datos puede ser:

    • Sistema de archivos: almacén de claves basado en el sistema de archivos
    • Azure Storage: claves de protección de datos en Azure BLOB object storage
    • Redis: claves de protección de datos en la memoria caché de Redis
    • Registro: se utiliza si la aplicación no tiene acceso al sistema de archivos
    • EF Core: las claves se almacenan en la base de datos

    Si los proveedores integrados no son adecuados, puede especificar su propio proveedor de almacenamiento de claves creando un IXmlRepository personalizado.

    Paso 14. Actualización de JS/CSS

    La forma de usar los recursos estáticos ha cambiado, ahora todos deben almacenarse en la carpeta raíz del proyecto wwwroot , a menos que se realicen otras configuraciones.

    Cuando utilice bloques integrados de javascript, le recomendamos moverlos al final de la página. Simplemente use el atributo asp-ubicación = "Pie de página" para sus etiquetas <script>. La misma regla se aplica a los archivos js.

    Use la extensión BundlerMinifier como reemplazo de System.Web.Optimization; esto permitirá la agrupación y la minificación. JavaScript y CSS durante la construcción del proyecto ( ver la documentación ).

    Paso 15. Portabilidad de vistas

    En primer lugar, las acciones secundarias ya no se usan; en su lugar, ASP.NET Core sugiere usar una nueva herramienta de alto rendimiento: ViewComponents llamados de forma asíncrona.

    Cómo obtener una cadena 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(); } }

    Tenga en cuenta que ya no es necesario usar HtmlHelper, ASP.NET Core incluye muchos asistentes auxiliares de etiquetas incorporados. Cuando la aplicación se está ejecutando, el motor de Razor los maneja en el servidor y, en última instancia, los convierte en elementos html estándar.

    Esto hace que el desarrollo de aplicaciones sea mucho más fácil. Y, por supuesto, puede implementar sus propios asistentes de etiquetas.

    Comenzamos a usar la inserción de dependencias en las vistas en lugar de habilitar la configuración y los servicios mediante EngineContext.

    Por lo tanto, los puntos principales sobre la portabilidad de vistas son los siguientes:

    • Convierta Views/web.config en Views/_ViewImports.cshtml: para importar espacios de nombres e inyectar dependencias. Este archivo no es compatible con otras funciones de Razor, como definiciones de funciones y secciones.
    • Convertir espacios de nombres.add a @using
    • Portar cualquier configuración a la configuración de la aplicación principal
    • Scripts.Render y Styles.Render no existen. Reemplace con enlaces a datos de salida de libman o BundlerMinifier

    Conclusión

    El proceso de migración de una aplicación web grande es una tarea que requiere mucho tiempo y que, por regla general, no puede llevarse a cabo sin las trampas. Planeamos migrar a un nuevo marco tan pronto como se lanzó su primera versión estable, pero no pudimos hacerlo de inmediato, ya que había algunas funciones críticas que no se habían transferido a .NET Core, en particular, aquellas relacionadas con EntityFramework. .

    Por lo tanto, primero tuvimos que hacer nuestro lanzamiento utilizando un enfoque mixto: la arquitectura .NET Core con las dependencias de .NET Framework, que en sí misma es una solución única.

    Ser el primero no es fácil, pero estamos seguros de haber tomado la decisión correcta y nuestra gran comunidad nos apoyó en esto.

    Pudimos adaptar completamente nuestro proyecto después del lanzamiento de .NET Core 2.1, y en ese momento teníamos una solución estable que ya funcionaba en la nueva arquitectura. Solo quedaba reemplazar algunos paquetes y reescribir el trabajo con EF Core.

    Por lo tanto, nos tomó varios meses y dos versiones publicadas para migrar completamente al nuevo marco.

    Podemos decir con confianza que somos el primer gran proyecto para llevar a cabo tal migración. En esta guía, intentamos reunir todo el proceso de migración de forma estructurada y describir varios cuellos de botella para que otros desarrolladores pudieran confiar en este material y seguir la hoja de ruta al resolver la misma tarea.