Cómo actualizar un proyecto existente de ASP.NET MVC a ASP.NET Core. Guía práctica

Esta publicación nació de nuestra experiencia al migrar un proyecto existente de ASP.NET MVC a ASP.NET Core. Intentamos reunir todo el proceso de migración en una forma estructurada y describir los diversos cuellos de botella para que los desarrolladores puedan seguir confiando en este material y seguir la hoja de ruta para resolver tales problemas.

Algunas palabras sobre nuestro proyecto. Somos una plataforma de comercio electrónico de código abierto en ASP.NET, que en el momento de la transferencia ya había existido con éxito durante 9 años. Hicimos la migración hace 2 años, pero nuestras manos llegaron a escribir sobre eso solo ahora. En ese momento, fuimos uno de los primeros proyectos importantes que decidieron tal paso.

¿Por qué cambiar a ASP.NET Core?


Antes de continuar con los pasos para migrar de ASP.NET MVC a ASP.NET Core, algunas palabras sobre los beneficios de esta plataforma.



Beneficios de ASP.NET Core
Entonces, ASP.NET Core ya es un marco bastante conocido y desarrollado, que ya ha sufrido varias actualizaciones importantes, lo que significa que hoy es bastante estable, tecnológicamente avanzado y resistente a los ataques XSRF / CSRF.

La multiplataforma es una de las características que le permiten ganar más y más popularidad. A partir de ahora, su aplicación web puede ejecutarse en entornos Windows y Unix.

Modularidad : ASP.NET Core viene completamente en forma de paquetes NuGet, esto le 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 las piezas individuales. Esta es la segunda característica importante que permite a los desarrolladores integrar de manera más flexible nuevas características en su solución.

El rendimiento es otro paso hacia la creación de una aplicación de alto rendimiento, ASP.NET Core procesa un 2300% más de solicitudes por segundo que ASP.NET 4.6, y un 800% más de solicitudes por segundo que node.js. Puede examinar pruebas de rendimiento detalladas usted mismo aquí o aquí .



Middleware es la nueva tubería modular ligera de alto rendimiento para solicitudes en la aplicación. Cada pieza de middleware procesa una solicitud HTTP y luego decide devolver el resultado o pasa la siguiente pieza de middleware. Este enfoque le da al desarrollador un control completo sobre la tubería 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.

ASP.NET Core MVC proporciona características que simplifican el desarrollo web. NopCommerce ya usaba características como la plantilla Modelo-Vista-Controlador, la sintaxis de Razor, el enlace y la validación del modelo, pero aparecieron nuevas herramientas:

  • Ayudantes de etiqueta. Este es un código del lado del servidor para contribuir a la creación y representación de elementos HTML en archivos Razor.
  • Ver componentes. Esta es una herramienta nueva, similar a las vistas parciales, pero mucho más poderosa. nopCommerce utiliza componentes de vista cuando se requiere reutilizar la lógica de representación y cuando la tarea es demasiado compleja para una vista parcial.
  • La opinión de DI. Aunque la mayoría de los datos que se muestran en las vistas pasan del controlador, nopCommerce tiene vistas en las que la inyección de dependencias es más conveniente.

Por supuesto, ASP.NET Core tiene muchas más funciones, pero acabamos de examinar las más interesantes.

Ahora hablemos sobre lo que debe considerar al portar su aplicación a una nueva plataforma.

La migracion


El texto contendrá una gran cantidad de enlaces a la documentación oficial de ASP.NET Core para ayudar a obtener información más detallada sobre el tema. Especialmente relevante para los desarrolladores que se enfrentan a una tarea similar por primera vez.

Paso 1. Preparación de herramientas.


Lo primero que debe hacer es actualizar Visual Studio 2017 a la versión 15.3 o superior. E instale la última versión del SDK de .NET Core.

Antes de comenzar la migración, se recomienda que utilice la herramienta de análisis de portabilidad .NET .Net Portability Analyzer . Este es un buen punto de partida para comprender cuán laboriosa será la transición de una plataforma a otra. Pero, por supuesto, esta herramienta no resuelve todos los problemas, y en el proceso habrá muchas trampas. A continuación, se describirán las etapas principales que deberán superarse y se mostrarán las soluciones utilizadas en nuestro proyecto.

Lo primero que necesita es actualizar los enlaces a las bibliotecas utilizadas en el proyecto que admitirían .NET Standard.

Paso 2. Análisis de compatibilidad de paquetes NuGet para soportar .Net Standard


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

Paso 3. .NET Core usa el nuevo formato de archivo csproj


Es importante utilizar el nuevo enfoque para agregar enlaces de terceros introducidos en .NET Core: cuando se agrega una nueva biblioteca de clases a la solución, debe abrir el archivo principal del proyecto y reemplazar su contenido con lo siguiente:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.6" /> ... </ItemGroup> ... </Project> 

Los enlaces de las bibliotecas conectadas se descargarán automáticamente. Puede encontrar más información sobre el mapeo entre las propiedades project.json y CSPROJ en la documentación oficial aquí y aquí .

Paso 4. Actualizando el espacio de nombres


Debe eliminar todos los usos de System.Web y reemplazarlos con Microsoft.AspNetCore.

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


ASP.NET Core tiene un nuevo mecanismo para cargar la aplicación. El punto de entrada a la aplicación se convierte en Startup y la dependencia del archivo Global.asax desaparece. Startup registra la suite de middleware en la aplicación. Startup debe incluir el método Configure . En Configure agregue el middleware requerido a la tubería.

Problemas de Startup.cs

  1. Configuración de middleware para solicitudes MVC y WebAPI
  2. Opciones de configuración para:


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

Al mismo tiempo, la carpeta con el nombre Área debe colocarse en la raíz de la aplicación, dentro de la cual se encuentra la carpeta Admin. 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

Ahora no necesita pasar IFormCollection 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 determina que IFormCollection no es nulo. La solución al problema puede ser agregar esta propiedad al modelo, esto evitará que pasemos directamente al método del controlador. Esta regla es válida solo si hay un modelo presente, pero si no hay modelo, entonces no habrá validación.

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

Paso 6. Transferencia de controladores HTTP y módulos HTTP a Middleware


Los controladores HTTP y los módulos HTTP son esencialmente 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, en su mayor parte, se basa en los eventos del ciclo de vida de la aplicación . El orden del middleware para las respuestas es el opuesto al orden de las solicitudes, y el orden de los módulos para las solicitudes y las respuestas es el mismo. De acuerdo con esto, puede continuar con la actualización.

Entonces, lo que queda por actualizar:

  • Migración de módulos para Middleware (AuthenticationMiddleware, CultureMiddleware, etc.)
  • Manejadores de Middleware
  • Usando New Middleware

La autenticación en nuestro proyecto no utiliza el sistema de credenciales incorporado; para estos fines, se utiliza AuthenticationMiddleware de middleware, 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 tenga en cuenta que el desarrollador tiene la capacidad de crear su propio middleware y agregarlo a la canalización de solicitudes HTTP. Para simplificar este mecanismo, agregamos una interfaz especial, y ahora es suficiente con crear una clase que lo 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 integrado


La inyección de dependencia es una de las características clave en el proceso de diseño de aplicaciones en ASP.NET Core. Le permite crear aplicaciones poco acopladas que son más comprobables, modulares y, como resultado, mantenibles. Esto fue posible siguiendo el principio de inversión de dependencia. Para instalar dependencias, se utilizan contenedores IoC (Inversión de 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 ámbitos:

  • transitoria
  • alcance
  • singleton

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

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


Para simplificar la migración de una implementación de API web existente, se recomienda utilizar el paquete Microsoft.AspNetCore.Mvc.WebApiCompatShim NuGet. Se admiten las siguientes funciones compatibles:

  • Agrega el tipo ApiController
  • Habilita el enlace del modelo de estilo de API web
  • Extiende el enlace del modelo para que las acciones del controlador puedan aceptar parámetros de tipo HttpRequestMessage.
  • Agrega formateadores de mensajes que permiten que las acciones devuelvan resultados de tipo HttpResponseMessage

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

Paso 9. Transfiera la configuración de la aplicación


Anteriormente, algunas configuraciones se guardaban en el archivo web.config. Ahora estamos adoptando un nuevo enfoque basado en pares clave-valor establecidos por los proveedores de configuración . Este es el mecanismo recomendado en ASP.NET Core, y utilizamos 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, deberá abandonar la capacidad de ejecutar la aplicación en plataformas Unix y ejecutarla solo bajo IIS.

Si desea usar el proveedor de configuración de Azure Key Vault , debe consultar la migración de contenido al contenido de Azure Key Valut . En nuestro proyecto, esta no era la tarea.

Paso 10. Transferencia de contenido estático a wwwroot


Para servir contenido estático, debe indicarle al host web la raíz del contenido del directorio actual. El valor predeterminado es wwwroot. Puede personalizar su directorio para almacenar archivos estáticos configurando 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 , entonces tiene sentido ejecutar la aplicación en NET Framework . En este caso, sin embargo, debes sacrificar la multiplataforma. La aplicación solo funcionará en Windows y bajo IIS.

Echemos un vistazo a los principales cambios a tener en cuenta:

  • System.Data.Entity namespace reemplazado por Microsoft.EntityFrameworkCore
  • La firma del constructor DbContext ha cambiado. Ahora necesita inyectar DbContextOptions
  • Método HasDatabaseGeneratedOption (DatabaseGeneratedOption.None) reemplazado por ValueGeneratedNever ()
  • Método WillCascadeOnDelete (falso) reemplazado por OnDelete (DeleteBehavior.Restrict)
  • Método OnModelCreating (DbModelBuilder modelBuilder) reemplazado por OnModelCreating (ModelBuilder modelBuilder)
  • El método HasOptional ya no está disponible
  • la configuración de los objetos ha cambiado, ahora necesita usar OnModelCreating, porque EntityTypeConfiguration ya no está disponible
  • El atributo ComplexType ya no está disponible
  • Reemplazos de la interfaz IDbSet con DbSet
  • ComplexType: la compatibilidad con tipos complejos apareció en EF Core 2 con el tipo de entidad propia ( https://docs.microsoft.com/en-us/ef/core/modeling/owned-entities ) y tablas sin una clave principal con QueryType en EF Core 2.1 ( https://docs.microsoft.com/en-us/ef/core/modeling/query-types )
  • Las claves foráneas en EF Core generan propiedades de sombra utilizando el patrón Id de [Entidad], a diferencia de EF6, que usa el patrón Id de [Entidad]. 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); } 

Use la herramienta SQL Compare para verificar que EF Core genera un esquema de base de datos similar al Entity Framework durante la migración .

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


Durante la migración de su proyecto, encontrará que se ha cambiado el nombre o se ha movido un número suficientemente grande de clases, y ahora debe alinear todo con los nuevos requisitos. Aquí hay una lista de las principales transiciones que puede encontrar:

  • HttpPostedFileBase -> IFormFile
  • El acceso para acceder a HttpContext ahora es a través de IHttpContextAccessor
  • HtmlHelper -> IHtmlHelper
  • ActionResult -> IActionResult
  • HttpUtility -> WebUtility
  • En lugar de HttpSessionStateBase - ISession, se puede acceder desde HttpContext.Session. de Microsoft.AspNetCore.Http
  • Request.Cookies devuelve IRequestCookieCollection: IEnumerable <KeyValuePair <string, string >>, por lo que en lugar de HttpCookie, KeyValuePair <string, string> de Microsoft.AspNetCore.Http

Reemplazo del espacio de nombres:

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

Otros:

  • MvcHtmlString.IsNullOrEmpty (IHtmlString) -> String.IsNullOrEmpty (variable.ToHtmlString ())
  • [ValidateInput (false)]: generalmente ya no existe y no es necesario
  • HttpUnauthorizedResult -> UnauthorizedResult
  • [AllowHtml]: no hay más directiva y no es necesaria
  • Se reemplazó el método TagBuilder.SetInnerText; ahora es InnerHtml.AppendHtml
  • JsonRequestBehavior.AllowGet cuando devolver Json ya no es necesario
  • HttpUtility.JavaScriptStringEncode. -> JavaScriptEncoder.Default.Encode
  • Request.RawUrl. Es necesario conectar por separado Request.Path + Request.QueryString
  • AllowHtmlAttribute: no más clases
  • XmlDownloadResult: ahora puede usar simplemente regresar File (Encoding.UTF8.GetBytes (xml), "application / xml", "filename.xml");
  • [ValidateInput (false)]: no hay más directiva y no es necesaria

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


Ya escribí anteriormente que en nuestro proyecto la autenticación no se implementa utilizando el sistema de identidad incorporado, sino que se extrae en una capa separada de middleware. Sin embargo, ASP.NET Core tiene su propio mecanismo para proporcionar credenciales. Se pueden encontrar más detalles en la documentación aquí .

En cuanto a la protección de datos, ya no usamos MachineKey . En cambio, utilizamos la función de protección de datos incorporada. Por defecto, las claves se generan cuando se inicia la aplicación. El almacén 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 Storage
  • Redis: claves de protección de datos en el caché de Redis
  • Registro: debe usarse si la aplicación no tiene acceso al sistema de archivos
  • EF Core: las claves se almacenan en la base de datos

Si los mecanismos integrados no son adecuados, puede especificar su propio mecanismo de almacenamiento de claves proporcionando un IXmlRepository personalizado.

Paso 14. Actualización de JS / CSS


La forma de trabajar con recursos estáticos ha cambiado: ahora todos deben almacenarse en la carpeta raíz del proyecto wwwroot , a menos que, por supuesto, se especifiquen otras configuraciones.

Cuando utilice bloques incorporados de JavaScript, se recomienda que los mueva al final de la página. Simplemente use el atributo asp-location = "Footer" para sus etiquetas. La misma regla se aplica a los archivos js.

Use la extensión BundlerMinifier como reemplazo de System.Web.Optimization: esto le permitirá vincular y minimizar JavaScript y CSS mientras construye el proyecto. Enlace a la documentación.

Paso 15. Migrar vistas


Las acciones secundarias ya no se usan. En cambio, ASP.NET Core ofrece una nueva herramienta poderosa: ViewComponents , que se llama de forma asincrónica.

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

Ya no es necesario usar HtmlHelper: ASP.NET Core tiene una gran cantidad de funciones de etiqueta de ayuda ( Tag Helpers ) integradas. Cuando la aplicación se está ejecutando, son procesados ​​por el motor Razor en el lado del servidor y finalmente se convierten en elementos html estándar. Esto simplifica enormemente el desarrollo de aplicaciones. Y, por supuesto, puede implementar sus propios tag-helpers.

Comenzamos a usar la inyección de dependencia en vistas en lugar de permitir configuraciones y servicios usando EngineContext .

Entonces, los puntos principales sobre la migración de puntos de vista:

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

En conclusión


Hemos visto por nuestra experiencia que el proceso de migrar una gran aplicación web es una tarea que requiere mucho tiempo y que difícilmente se puede llevar a cabo sin dificultades. Planeamos cambiar a un nuevo marco tan pronto como se lanzó su primera versión estable, pero no pudimos terminarlo de inmediato: había algunas funciones críticas que para ese momento aún no se habían transferido a .NET Core, en particular, relacionadas con EntityFramework. Por lo tanto, primero tuvimos que lanzar la próxima versión con un enfoque mixto: la arquitectura .NET Core con las dependencias de .NET Framework.

Pudimos adaptar completamente el proyecto después del lanzamiento de .NET Core 2.1, teniendo en ese momento una solución estable que ya funcionaba en la nueva arquitectura; todo lo que quedaba era reemplazar algunos paquetes y reescribir el trabajo con EF Core. Por lo tanto, la migración completa al nuevo marco tomó varios meses de trabajo.

Puede obtener más información sobre nuestro proyecto en nuestro repositorio en GitHub .

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


All Articles