Dieser Beitrag wurde aus unserer Erfahrung mit der Migration eines vorhandenen Projekts von ASP.NET MVC auf ASP.NET Core erstellt. Wir haben versucht, den gesamten Migrationsprozess in strukturierter Form zusammenzustellen und die verschiedenen Engpässe zu beschreiben, damit sich Entwickler weiterhin auf dieses Material verlassen und die Roadmap zur Lösung solcher Probleme befolgen können.
Ein paar Worte zu unserem Projekt. Wir sind eine Open-Source-E-Commerce-Plattform auf ASP.NET, die zum Zeitpunkt der Übertragung bereits seit 9 Jahren erfolgreich besteht. Wir haben die Migration vor 2 Jahren durchgeführt - aber unsere Hände kamen erst jetzt, um darüber zu schreiben. Zu dieser Zeit waren wir eines der ersten großen Projekte, die sich für einen solchen Schritt entschieden haben.
Warum zu ASP.NET Core wechseln?
Bevor Sie mit den Schritten zur Migration von ASP.NET MVC zu ASP.NET Core fortfahren, einige Worte zu den Vorteilen dieser Plattform.

Vorteile von ASP.NET CoreDaher ist ASP.NET Core bereits ein ziemlich bekanntes und entwickeltes Framework, das bereits mehrere wichtige Aktualisierungen erfahren hat. Dies bedeutet, dass es heute recht stabil, technologisch fortschrittlich und resistent gegen XSRF / CSRF-Angriffe ist.
Plattformübergreifend ist eines der Markenzeichen, die es ihm ermöglichen, immer beliebter zu werden. Von nun an kann Ihre Webanwendung sowohl in Windows- als auch in Unix-Umgebungen ausgeführt werden.
Modularität - ASP.NET Core wird vollständig in Form von NuGet-Paketen geliefert. Auf diese Weise können Sie die Anwendung einschließlich der ausgewählten erforderlichen Pakete optimieren. Dies verbessert die Leistung der Lösung und reduziert den Zeitaufwand für das Upgrade einzelner Teile. Dies ist die zweite wichtige Funktion, mit der Entwickler neue Funktionen flexibler in ihre Lösung integrieren können.
Die Leistung ist ein weiterer Schritt zum Erstellen einer Hochleistungsanwendung. ASP.NET Core verarbeitet 2300% mehr Anforderungen pro Sekunde als ASP.NET 4.6 und 800% mehr Anforderungen pro Sekunde als node.js. Detaillierte Leistungstests können Sie
hier oder
hier selbst prüfen.
Middleware ist die neue leichte modulare Hochleistungs-Pipeline für In-App-Anfragen. Jede Middleware verarbeitet eine HTTP-Anforderung und entscheidet sich dann entweder für die Rückgabe des Ergebnisses oder übergibt die nächste Middleware. Dieser Ansatz gibt dem Entwickler die vollständige Kontrolle über die HTTP-Pipeline und trägt zur Entwicklung einfacher Module für die Anwendung bei, was für ein wachsendes Open Source-Projekt wichtig ist.
ASP.NET Core MVC bietet Funktionen, die die Webentwicklung vereinfachen. NopCommerce verwendete bereits Funktionen wie die Model-View-Controller-Vorlage, die Razor-Syntax, die Modellbindung und die Validierung. Es wurden jedoch neue Tools veröffentlicht:
- Tag Helfer. Dies ist serverseitiger Code, der zum Erstellen und Rendern von HTML-Elementen in Razor-Dateien beiträgt.
- Komponenten anzeigen. Dies ist ein neues Tool, ähnlich wie Teilansichten, aber viel leistungsfähiger. nopCommerce verwendet Ansichtskomponenten, wenn die Wiederverwendung der Renderlogik erforderlich ist und die Aufgabe für eine Teilansicht zu komplex ist.
- DIs Ansicht. Obwohl die meisten in den Ansichten angezeigten Daten vom Controller übergeben werden, verfügt nopCommerce über Ansichten, in denen die Abhängigkeitsinjektion bequemer ist.
Natürlich hat ASP.NET Core viel mehr Funktionen, aber wir haben gerade die interessantesten untersucht.
Lassen Sie uns nun darüber sprechen, was Sie beim Portieren Ihrer Anwendung auf eine neue Plattform beachten sollten.
Die Migration
Der Text enthält eine Vielzahl von Links zur offiziellen ASP.NET Core-Dokumentation, um detailliertere Informationen zum Thema zu erhalten. Besonders relevant für Entwickler, die zum ersten Mal vor einer ähnlichen Aufgabe stehen.
Schritt 1. Vorbereitung der Werkzeuge
Als erstes müssen Sie Visual Studio 2017 auf Version 15.3 oder höher aktualisieren. Installieren Sie die neueste Version des .NET Core SDK.
Bevor Sie mit der Migration beginnen, wird empfohlen, das Portability Analysis-Tool .NET
.Net Portability Analyzer zu verwenden. Dies ist ein guter Ausgangspunkt, um zu verstehen, wie mühsam der Übergang von einer Plattform zur anderen sein wird. Aber dieses Tool löst natürlich nicht alle Probleme, und dabei gibt es viele Fallstricke. Als nächstes werden die Hauptphasen beschrieben, die bestanden werden müssen, und die in unserem Projekt verwendeten Lösungen werden gezeigt.
Als erstes müssen Sie die Links zu den im Projekt verwendeten Bibliotheken aktualisieren, die .NET Standard unterstützen würden.
Schritt 2. Kompatibilitätsanalyse von NuGet-Paketen zur Unterstützung von .Net Standard
Wenn Sie NuGet-Pakete in Ihrem Projekt verwenden, müssen Sie überprüfen, ob sie mit .NET Core kompatibel sind. Eine Möglichkeit hierfür ist die Verwendung des
NuGetPackageExplorer- Tools.
Schritt 3. .NET Core verwendet das neue csproj-Dateiformat
Es ist wichtig, den neuen Ansatz zum Hinzufügen von in .NET Core eingeführten Links von Drittanbietern zu verwenden: Wenn der Lösung eine neue Klassenbibliothek hinzugefügt wird, sollten Sie die Hauptprojektdatei öffnen und deren Inhalt durch Folgendes ersetzen:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.6" /> ... </ItemGroup> ... </Project>
Links aus verbundenen Bibliotheken werden automatisch heruntergeladen. Weitere Informationen zur Zuordnung zwischen den Eigenschaften project.json und CSPROJ finden Sie in der offiziellen Dokumentation
hier und
hier .
Schritt 4. Aktualisieren des Namespace
Sie müssen alle Verwendungen von System.Web entfernen und durch Microsoft.AspNetCore ersetzen.
Schritt 5. Sie müssen die Datei Startup.cs konfigurieren. anstatt global.asax zu verwenden
ASP.NET Core verfügt über einen neuen Mechanismus zum Laden der Anwendung. Der Einstiegspunkt in die Anwendung wird zu
Startup
, und die Abhängigkeit von der Datei
Global.asax verschwindet.
Startup
die Middleware-Suite in der Anwendung registriert.
Startup
muss die
Configure
Methode enthalten.
Configure
die erforderliche Middleware zur Pipeline hinzu.
Probleme mit Startup.cs- Middleware für MVC- und WebAPI-Anforderungen konfigurieren
- Konfigurationseinstellungen für:
app.UseMvc(routes => { routes.MapRoute("areaRoute", "{area:exists}/{controller=Admin}/{action=Index}/{id?}"); routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
Gleichzeitig sollte der Ordner mit dem Namen Bereich, in dem sich der Admin-Ordner befindet, im Stammverzeichnis der Anwendung abgelegt werden. Jetzt wird das Attribut
[Area("Admin")] [Route("admin")]
verwendet, um den Controller mit diesem Bereich zu verbinden.
Es müssen nur noch Ansichten für alle in der Steuerung beschriebenen Aktionen erstellt werden.
[Area("Admin")] [Route("admin")] public class AdminController : Controller { public IActionResult Index() { return View(); } }
ValidierungJetzt müssen Sie IFormCollection nicht mehr an die Controller übergeben, da in diesem Fall die Servervalidierung von asp.net deaktiviert ist. MVC unterdrückt die weitere Validierung, wenn festgestellt wird, dass die IFormCollection nicht null ist. Die Lösung des Problems kann darin bestehen, diese Eigenschaft dem Modell hinzuzufügen. Dadurch wird verhindert, dass wir direkt an die Controller-Methode übergeben. Diese Regel ist nur gültig, wenn ein Modell vorhanden ist. Wenn jedoch kein Modell vorhanden ist, erfolgt keine Validierung.
Untergeordnete Eigenschaften werden nicht mehr automatisch überprüft. Es muss manuell angegeben werden.
Schritt 6. Übertragen von HTTP-Handlern und HTTP-Modulen auf Middleware
HTTP-Handler und HTTP-Module sind dem
Middleware- Konzept
in ASP.NET Core im Wesentlichen sehr ähnlich. Im Gegensatz zu Modulen basiert die Middleware-Reihenfolge jedoch auf der Reihenfolge, in der sie in die Anforderungspipeline eingefügt werden. Die Reihenfolge der Module basiert größtenteils auf
Anwendungslebenszyklusereignissen . Die Reihenfolge der Middleware für die Antworten ist das Gegenteil der Reihenfolge der Anforderungen, und die Reihenfolge der Module für die Anforderungen und Antworten ist dieselbe. Auf dieser Grundlage können Sie mit dem Upgrade fortfahren.
Also, was bleibt noch zu aktualisieren:
- Migration von Modulen für Middleware (AuthenticationMiddleware, CultureMiddleware usw.)
- Handler für Middleware
- Neue Middleware verwenden
Bei der Authentifizierung in unserem Projekt wird nicht das integrierte Anmeldeinformationssystem verwendet. Für diese Zwecke wird die Middleware AuthenticationMiddleware verwendet, die gemäß der neuen ASP.NET Core-Struktur entwickelt wurde.
public class AuthenticationMiddleware { private readonly RequestDelegate _next; public AuthenticationMiddleware(IAuthenticationSchemeProvider schemes, RequestDelegate next) { Schemes = schemes ?? throw new ArgumentNullException(nameof(schemes)); _next = next ?? throw new ArgumentNullException(nameof(next)); } public IAuthenticationSchemeProvider Schemes { get; set; } public async Task Invoke(HttpContext context) { context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature { OriginalPath = context.Request.Path, OriginalPathBase = context.Request.PathBase }); var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>(); foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync()) { try { if (await handlers.GetHandlerAsync(context, scheme.Name) is IAuthenticationRequestHandler handler && await handler.HandleRequestAsync()) return; } catch {
ASP.NET bietet viele eingebettete Middleware, die Sie in Ihrer Anwendung verwenden können. Beachten Sie jedoch, dass der Entwickler
seine eigene Middleware erstellen und zur HTTP-Anforderungspipeline hinzufügen kann. Um diesen Mechanismus zu vereinfachen, haben wir eine spezielle Schnittstelle hinzugefügt. Jetzt reicht es aus, nur eine Klasse zu erstellen, die ihn implementiert.
public interface INopStartup {
Hier können Sie Ihre Middleware hinzufügen und konfigurieren:
Schritt 7. Integriertes DI verwenden
Die Abhängigkeitsinjektion ist eine der Hauptfunktionen im Anwendungsentwurfsprozess in ASP.NET Core. Sie können damit lose gekoppelte Anwendungen erstellen, die testbarer, modularer und damit wartbarer sind. Möglich wurde dies durch das Prinzip der Abhängigkeitsinversion. Zum Installieren von Abhängigkeiten werden IoC-Container (Inversion of Control) verwendet. In ASP.NET Core wird ein solcher Container durch die IServiceProvider-Schnittstelle dargestellt. Dienste werden in der Anwendung in der Methode
Startup.ConfigureServices()
installiert.
Jeder registrierte Dienst kann mit drei Bereichen konfiguriert werden:
- vorübergehend
- Umfang
- Singleton
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddSingleton<Isingleton,MySingleton>();
Schritt 8. Verwenden von WebAPI Project Compatibility Shells (Shim)
Um die Migration einer vorhandenen Web-API-Implementierung zu vereinfachen, wird empfohlen, das
Microsoft.AspNetCore.Mvc.WebApiCompatShim NuGet-Paket zu verwenden. Folgende
kompatible Funktionen werden unterstützt:
- Fügt den ApiController-Typ hinzu
- Aktiviert die Modellbindung im Web-API-Stil
- Erweitert die Modellbindung, sodass Controller-Aktionen Parameter vom Typ HttpRequestMessage akzeptieren können.
- Fügt Nachrichtenformatierer hinzu, mit denen Aktionen Ergebnisse vom Typ HttpResponseMessage zurückgeben können
services.AddMvc().AddWebApiConventions(); routes.MapWebApiRoute(name: "DefaultApi", template: "api/{controller}/{id?}" );
Schritt 9. Anwendungskonfiguration übertragen
Zuvor wurden einige Einstellungen in der Datei web.config gespeichert. Wir verfolgen jetzt einen
neuen Ansatz, der auf Schlüssel-Wert-Paaren basiert, die
von Konfigurationsanbietern festgelegt
wurden . Dies ist der empfohlene Mechanismus in ASP.NET Core, und wir verwenden die Datei appsettings.json.
Sie können auch das NuGet-Paket
System.Configuration.ConfigurationManager
wenn Sie aus irgendeinem Grund weiterhin * .config verwenden möchten. In diesem Fall müssen Sie die Möglichkeit aufgeben, die Anwendung auf Unix-Plattformen auszuführen, und sie nur unter IIS ausführen.
Wenn Sie den
Azure Key Vault- Konfigurationsanbieter verwenden möchten,
lesen Sie die Inhaltsmigration
zu Azure Key Valut-Inhalten . In unserem Projekt war dies nicht die Aufgabe.
Schritt 10. Übertragen von statischem Inhalt auf wwwroot
Um
statischen Inhalt bereitzustellen, müssen Sie dem Webhost das Stammverzeichnis des Inhalts des aktuellen Verzeichnisses mitteilen. Der Standardwert ist wwwroot. Sie können Ihr Verzeichnis zum Speichern statischer Dateien anpassen, indem Sie Middleware einrichten.
Schritt 11. Portieren von EntityFramework auf EF Core
Wenn das Projekt einige spezifische
Funktionen von Entity Framework 6 verwendet ,
die in
EF Core
nicht unterstützt werden , ist es sinnvoll, die Anwendung auf dem
NET Framework
auszuführen. In diesem Fall müssen Sie jedoch die Multiplattform opfern. Die Anwendung funktioniert nur unter Windows und unter IIS.
Werfen wir einen Blick auf die wichtigsten Änderungen, die berücksichtigt werden müssen:- Der System.Data.Entity-Namespace wurde durch Microsoft.EntityFrameworkCore ersetzt
- Die Signatur des DbContext-Konstruktors wurde geändert. Jetzt müssen Sie DbContextOptions injizieren
- HasDatabaseGeneratedOption (DatabaseGeneratedOption.None) -Methode ersetzt durch ValueGeneratedNever ()
- WillCascadeOnDelete (false) -Methode ersetzt durch OnDelete (DeleteBehavior.Restrict)
- OnModelCreating (DbModelBuilder modelBuilder) -Methode ersetzt durch OnModelCreating (ModelBuilder modelBuilder)
- Die HasOptional-Methode ist nicht mehr verfügbar
- Die Konfiguration der Objekte wurde geändert. Jetzt müssen Sie OnModelCreating verwenden, da EntityTypeConfiguration ist nicht mehr verfügbar
- Das ComplexType-Attribut ist nicht mehr verfügbar
- Ersetzen der IDbSet-Schnittstelle durch DbSet
- ComplexType - Unterstützung für komplexe Typen wurde in EF Core 2 mit dem Typ Owned Entity ( https://docs.microsoft.com/en-us/ef/core/modeling/owners-entities ) und Tabellen ohne Primärschlüssel mit QueryType in EF Core angezeigt 2.1 ( https://docs.microsoft.com/en-us/ef/core/modeling/query-types )
- Fremdschlüssel in EF Core generieren Schatteneigenschaften mithilfe des ID-Musters [Entity], im Gegensatz zu EF6, das das _Id-Muster [Entity] verwendet. Fügen Sie der Entität daher zunächst Fremdschlüssel als reguläre Eigenschaft hinzu.
- Um DI für DbContext zu unterstützen, konfigurieren Sie Ihren DbContex in
ConfigureServices
Verwenden Sie das
SQL Compare- Tool, um zu überprüfen, ob
EF Core
während der
Migration ein ähnliches Datenbankschema wie das
Entity Framework
generiert.
Schritt 12. Entfernen aller HttpContext-Referenzen, Ersetzen veralteter Klassen und Ändern des Namespace
Während der Migration Ihres Projekts werden Sie feststellen, dass eine ausreichend große Anzahl von Klassen umbenannt oder verschoben wurde. Jetzt müssen Sie alles an die neuen Anforderungen anpassen. Hier ist eine Liste der wichtigsten Übergänge, auf die Sie stoßen können:
- HttpPostedFileBase -> IFormFile
- Der Zugriff auf HttpContext erfolgt jetzt über IHttpContextAccessor
- HtmlHelper -> IHtmlHelper
- ActionResult -> IActionResult
- HttpUtility -> WebUtility
- Anstelle von HttpSessionStateBase - ISession kann über HttpContext.Session zugegriffen werden. von Microsoft.AspNetCore.Http
- Request.Cookies gibt IRequestCookieCollection zurück: IEnumerable <KeyValuePair <string, string >>, also anstelle von HttpCookie, KeyValuePair <string, string> von Microsoft.AspNetCore.Http
Namespace-Ersatz:
- SelectList -> Microsoft.AspNetCore.Mvc.Rendering
- UrlHelper -> WebUtitlity
- MimeMapping -> FileExtensionContentTypeProvider
- MvcHtmlString -> IHtmlString und HtmlString
- ModelState, ModelStateDictionary, ModelError -> Microsoft.AspNetCore.Mvc.ModelBinding
- FormCollection -> IFormCollection
- Request.Url.Scheme -> this.Url.ActionContext.HttpContext.Request.Scheme
Sonstiges:
- MvcHtmlString.IsNullOrEmpty (IHtmlString) -> String.IsNullOrEmpty (variable.ToHtmlString ())
- [ValidateInput (false)] - ist im Allgemeinen nicht mehr vorhanden und wird nicht benötigt
- HttpUnauthorizedResult -> UnauthorizedResult
- [AllowHtml] - Es gibt keine Direktive mehr und sie wird nicht benötigt
- TagBuilder.SetInnerText-Methode ersetzt - jetzt ist dies InnerHtml.AppendHtml
- JsonRequestBehavior.AllowGet bei der Rückgabe von Json wird nicht mehr benötigt
- HttpUtility.JavaScriptStringEncode. -> JavaScriptEncoder.Default.Encode
- Request.RawUrl. Es ist erforderlich, Request.Path + Request.QueryString separat zu verbinden
- AllowHtmlAttribute - keine Klasse mehr
- XmlDownloadResult - jetzt können Sie einfach die Rückgabedatei (Encoding.UTF8.GetBytes (xml), "application / xml", "filename.xml") verwenden.
- [ValidateInput (false)] - Es gibt keine Direktive mehr und sie wird nicht benötigt
Schritt 13. Aktualisieren der Authentifizierung und Autorisierung
Ich habe bereits oben geschrieben, dass in unserem Projekt die Authentifizierung nicht mithilfe des integrierten Identitätssystems implementiert wird, sondern in einer separaten Middleware-Schicht ausgeführt wird. ASP.NET Core verfügt jedoch über einen eigenen Mechanismus zum Bereitstellen von Anmeldeinformationen. Weitere Details finden Sie in der Dokumentation
hier .
Zum Datenschutz verwenden wir
MachineKey nicht mehr. Stattdessen verwenden wir die integrierte Datenschutzfunktion. Standardmäßig werden Schlüssel beim Start der Anwendung generiert. Das Data Warehouse kann sein:
- Dateisystem - Dateisystem-basierter Keystore
- Azure Storage - Datenschutzschlüssel im Azure Blob-Speicher
- Redis - Datenschutzschlüssel im Redis-Cache
- Registrierung - muss verwendet werden, wenn die Anwendung keinen Zugriff auf das Dateisystem hat
- EF Core - Schlüssel werden in der Datenbank gespeichert
Wenn die integrierten Mechanismen nicht geeignet sind, können Sie Ihren eigenen Schlüsselspeichermechanismus angeben, indem Sie ein benutzerdefiniertes
IXmlRepository bereitstellen .
Schritt 14. Aktualisieren von JS / CSS
Die Arbeitsweise mit statischen Ressourcen hat sich geändert: Jetzt sollten alle im Stammordner des
wwwroot- Projekts gespeichert werden, sofern natürlich keine anderen Einstellungen angegeben sind.
Wenn Sie integrierte Javascript-Blöcke verwenden, wird empfohlen, diese an das Ende der Seite zu verschieben. Verwenden Sie einfach das Attribut asp-location = "Footer" für Ihre Tags. Die gleiche Regel gilt für js-Dateien.
Verwenden Sie die
BundlerMinifier- Erweiterung als Ersatz für System.Web.Optimization. Auf diese Weise können Sie JavaScript und CSS beim
Erstellen des Projekts binden und minimieren.
Link zur Dokumentation.
Schritt 15. Ansichten migrieren
Untergeordnete Aktionen werden nicht mehr verwendet. Stattdessen bietet ASP.NET Core ein neues leistungsstarkes Tool -
ViewComponents , das asynchron aufgerufen wird.
So erhalten Sie eine Zeichenfolge von ViewComponent:
Es ist nicht mehr erforderlich, HtmlHelper zu verwenden - ASP.NET Core verfügt über eine große Anzahl integrierter Helper-Tag-Funktionen (
Tag-Helfer ). Wenn die Anwendung ausgeführt wird, werden sie von der Razor-Engine auf der Serverseite verarbeitet und schließlich in Standard-HTML-Elemente konvertiert. Dies vereinfacht die Anwendungsentwicklung erheblich. Und natürlich können Sie Ihre eigenen Tag-Helfer implementieren.
Wir haben begonnen, die Abhängigkeitsinjektion in Ansichten zu verwenden, anstatt Einstellungen und Dienste mithilfe von
EngineContext
.
Die wichtigsten Punkte zur Migration von Ansichten:
- Konvertieren Sie
Views/web.config Views/_ViewImports.cshtml
- wird zum Importieren von Namespaces und Views/web.config Views/_ViewImports.cshtml
Abhängigkeiten verwendet. Diese Datei unterstützt keine anderen Razor
Funktionen wie Funktions- und Abschnittsdefinitionen. - Konvertieren Sie
namespaces.add
in @using
- Übertragen Sie alle Einstellungen in die Hauptanwendungskonfiguration
Scripts.Render
und Styles.Render
nicht vorhanden. Ersetzen Sie libman
oder BundlerMinifier
Links zur Ausgabe
Abschließend
Wir haben aus unserer Erfahrung gesehen, dass der Prozess der Migration einer großen Webanwendung eine sehr zeitaufwändige Aufgabe ist, die ohne Fallstricke kaum ausgeführt werden kann. Wir hatten vor, auf ein neues Framework umzusteigen, sobald die erste stabile Version veröffentlicht wurde, konnten es jedoch nicht sofort fertigstellen: Es gab einige wichtige Funktionen, die zu diesem Zeitpunkt noch nicht auf .NET Core übertragen worden waren, insbesondere im Zusammenhang mit EntityFramework. Daher mussten wir zuerst die nächste Version mit einem gemischten Ansatz veröffentlichen - der .NET Core-Architektur mit den .NET Framework-Abhängigkeiten.
Wir konnten das Projekt nach der Veröffentlichung von .NET Core 2.1 vollständig anpassen, da zu diesem Zeitpunkt bereits eine stabile Lösung für die neue Architektur vorhanden war. Es mussten lediglich einige Pakete ersetzt und die Arbeit mit EF Core neu geschrieben werden. Die vollständige Migration auf das neue Framework dauerte daher mehrere Monate.
Weitere Informationen zu unserem Projekt finden Sie in unserem
Repository auf GitHub .