Migration von ASP.NET zu ASP.NET CoreMigrate from ASP.NET to ASP.NET Core

Von Isaac LevinBy Isaac Levin

Dieser Artikel dient als Leitfaden zum Migrieren von ASP.NET-Anwendungen zu ASP.NET Core.This article serves as a reference guide for migrating ASP.NET apps to ASP.NET Core.

VoraussetzungenPrerequisites

.NET Core SDK 2.2 oder höher.NET Core SDK 2.2 or later

ZielframeworksTarget frameworks

ASP.NET Core-Projekte bieten Entwicklern die Flexibilität, Anwendungen für .NET Core, .NET Framework oder für beide Frameworks zu erstellen.ASP.NET Core projects offer developers the flexibility of targeting .NET Core, .NET Framework, or both. Informationen zur Auswahl eines geeigneten Frameworks finden Sie unter Wahl zwischen .NET Core und .NET Framework für Server-Apps.See Choosing between .NET Core and .NET Framework for server apps to determine which target framework is most appropriate.

Bei der Erstellung von Anwendungen für .NET Framework müssen Projekte auf einzelne NuGet-Pakete verweisen.When targeting .NET Framework, projects need to reference individual NuGet packages.

Wenn das Zielframework .NET Core ist, können Sie mit dem Metapaket für ASP.NET Core auf die meisten expliziten Paketverweise verzichten.Targeting .NET Core allows you to eliminate numerous explicit package references, thanks to the ASP.NET Core metapackage. Das Microsoft.AspNetCore.App-Metapaket können Sie folgendermaßen in Ihrem Projekt installieren:Install the Microsoft.AspNetCore.App metapackage in your project:

<ItemGroup>
   <PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

Wenn das Metapaket verwendet wird, werden mit der Anwendung keine Pakete bereitgestellt, auf die im Metapaket verwiesen wird.When the metapackage is used, no packages referenced in the metapackage are deployed with the app. Die notwendigen Objekte sind im .NET Core-Laufzeitspeicher vorhanden und werden zur Verbesserung der Leistung vorkompiliert.The .NET Core Runtime Store includes these assets, and they're precompiled to improve performance. Weitere Informationen finden Sie unter Das Metapaket „Microsoft.AspNetCore.App“ für ASP.NET Core 2.1.See Microsoft.AspNetCore.App metapackage for ASP.NET Core for more detail.

Unterschiede bei ProjektstrukturenProject structure differences

Das Dateiformat .csproj wurde in ASP.NET Core vereinfacht.The .csproj file format has been simplified in ASP.NET Core. Zu einigen wichtigen Änderungen gehören folgende Punkte:Some notable changes include:

  • Dateien müssen nicht explizit eingebunden werden, um als Teil des Projekts behandelt zu werden.Explicit inclusion of files isn't necessary for them to be considered part of the project. Dadurch wird in großen Entwicklerteams das Risiko von Konflikten beim Zusammenführen von XML-Dateien reduziert.This reduces the risk of XML merge conflicts when working on large teams.

  • Auf GUID-Verweise zu anderen Projekten wird verzichtet, wodurch die Lesbarkeit von Dateien erhöht wird.There are no GUID-based references to other projects, which improves file readability.

  • Die Datei kann bearbeitet werden, ohne in Visual Studio entladen zu werden:The file can be edited without unloading it in Visual Studio:

    Kontextmenüoption „Edit CSPROJ“ (CSPROJ-Datei bearbeiten) in Visual Studio 2017

Ersetzen der Datei „Global.asax“Global.asax file replacement

Mit ASP.NET Core wurde ein neuer Mechanismus für den Bootstrap einer Anwendung eingeführt.ASP.NET Core introduced a new mechanism for bootstrapping an app. Der Einstiegspunkt für ASP.NET-Anwendungen ist die Datei Global.asax.The entry point for ASP.NET applications is the Global.asax file. In der Datei Global.asax werden Aufgaben wie die Routenkonfiguration, die Einrichtung von Filtern und Bereichsregistrierungen bearbeitet.Tasks such as route configuration and filter and area registrations are handled in the Global.asax file.

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

Bei diesem Ansatz werden die Anwendung und der Server, auf dem die Anwendung bereitgestellt wird, so miteinander gekoppelt, dass es zu Konflikten mit der Implementierung kommt.This approach couples the application and the server to which it's deployed in a way that interferes with the implementation. OWIN wurde mit dem Ziel eingeführt, beide Komponenten zu entkoppeln und so mehrere Frameworks leichter gemeinsam verwenden zu können.In an effort to decouple, OWIN was introduced to provide a cleaner way to use multiple frameworks together. OWIN stellt eine Pipeline zur Verfügung, über die nur die benötigten Module hinzugefügt werden.OWIN provides a pipeline to add only the modules needed. Die Hostingumgebung verwendet eine Startup-Funktion, um Dienste und die Anforderungspipeline der Anwendung zu konfigurieren.The hosting environment takes a Startup function to configure services and the app's request pipeline. Startup registriert die Middleware bei der Anwendung.Startup registers a set of middleware with the application. Bei jeder Anforderung ruft die Anwendung alle Middlewarekomponenten auf, wobei der Hauptzeiger einer verknüpften Liste auf die vorhandenen Handler zeigt.For each request, the application calls each of the middleware components with the head pointer of a linked list to an existing set of handlers. Jede Middlewarekomponente kann einen oder mehrere Handler zur Anforderungspipeline hinzufügen.Each middleware component can add one or more handlers to the request handling pipeline. Möglich wird dies, indem ein Verweis auf den Handler zurückgegeben wird, der zum neuen ersten Element der Liste wird.This is accomplished by returning a reference to the handler that's the new head of the list. Jeder Handler ist dafür verantwortlich, sich den nächsten Handler in der Liste zu merken und diesen aufzurufen.Each handler is responsible for remembering and invoking the next handler in the list. In ASP.NET Core ist Startup der Einstiegspunkt für eine Anwendung. Eine Abhängigkeit von Global.asax ist nicht mehr vorhanden.With ASP.NET Core, the entry point to an application is Startup, and you no longer have a dependency on Global.asax. Wenn Sie OWIN mit .NET Framework verwenden möchten, können Sie sich beispielsweise an folgendem Code für die Pipeline orientieren:When using OWIN with .NET Framework, use something like the following as a pipeline:

using Owin;
using System.Web.Http;

namespace WebApi
{
    // Note: By default all requests go through this OWIN pipeline. Alternatively you can turn this off by adding an appSetting owin:AutomaticAppStartup with value “false”. 
    // With this turned off you can still have OWIN apps listening on specific routes by adding routes in global.asax file using MapOwinPath or MapOwinRoute extensions on RouteTable.Routes
    public class Startup
    {
        // Invoked once at startup to configure your application.
        public void Configuration(IAppBuilder builder)
        {
            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute("Default", "{controller}/{customerID}", new { controller = "Customer", customerID = RouteParameter.Optional });

            config.Formatters.XmlFormatter.UseXmlSerializer = true;
            config.Formatters.Remove(config.Formatters.JsonFormatter);
            // config.Formatters.JsonFormatter.UseDataContractJsonSerializer = true;

            builder.UseWebApi(config);
        }
    }
}

Hierdurch werden Ihre Standardrouten konfiguriert. Außerdem wird standardmäßig XmlSerialization anstelle von JSON verwendet.This configures your default routes, and defaults to XmlSerialization over Json. Bei Bedarf können Sie weitere Middleware (z.B. zum Laden von Diensten, für Konfigurationseinstellungen, für statische Dateien usw.) zur Pipeline hinzufügen.Add other Middleware to this pipeline as needed (loading services, configuration settings, static files, etc.).

ASP.NET Core verwendet einen ähnlichen Ansatz, ist jedoch hinsichtlich des Einstiegspunkts nicht auf OWIN angewiesen.ASP.NET Core uses a similar approach, but doesn't rely on OWIN to handle the entry. Stattdessen kommt – ähnlich wie bei Konsolenanwendungen – in Program.cs die Main-Methode zum Einsatz, in der Startup geladen wird.Instead, that's done through the Program.cs Main method (similar to console applications) and Startup is loaded through there.

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace WebApplication2
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

In Startup muss die Configure-Methode enthalten sein.Startup must include a Configure method. Fügen Sie in Configure der Pipeline die erforderliche Middleware hinzu.In Configure, add the necessary middleware to the pipeline. Im folgenden Beispiel, das der Standardwebsitevorlage entnommen wurde, konfigurieren Erweiterungsmethoden die Pipeline mit Unterstützung für Folgendes:In the following example (from the default web site template), extension methods configure the pipeline with support for:

  • FehlerseitenError pages
  • HTTP Strict Transport SecurityHTTP Strict Transport Security
  • HTTP-Umleitung zu HTTPSHTTP redirection to HTTPS
  • ASP.NET Core MVCASP.NET Core MVC
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseMvc();
}

Durch die Entkopplung von Host und Anwendung wird die Möglichkeit geschaffen, in der Zukunft eine Migration zu einer anderen Plattform vorzunehmen.The host and application have been decoupled, which provides the flexibility of moving to a different platform in the future.

Hinweis

Ausführliche Informationen zum Start einer Anwendung in ASP.NET Core und zu Middleware finden Sie unter Startup in ASP.NET Core (Starten von Anwendungen in ASP.NET Core).For a more in-depth reference to ASP.NET Core Startup and Middleware, see Startup in ASP.NET Core

SpeicherkonfigurationenStore configurations

ASP.NET unterstützt das Speichern von Einstellungen.ASP.NET supports storing settings. Diese Einstellungen dienen z.B. der Unterstützung der Umgebung, in der die Anwendungen bereitgestellt werden.These setting are used, for example, to support the environment to which the applications were deployed. Häufig werden alle benutzerdefinierten Schlüssel-Wert-Paare im Abschnitt <appSettings> der Datei Web.config gespeichert:A common practice was to store all custom key-value pairs in the <appSettings> section of the Web.config file:

<appSettings>
  <add key="UserName" value="User" />
  <add key="Password" value="Password" />
</appSettings>

Anwendungen lesen diese Einstellungen über die ConfigurationManager.AppSettings-Auflistung im System.Configuration-Namespace aus:Applications read these settings using the ConfigurationManager.AppSettings collection in the System.Configuration namespace:

string userName = System.Web.Configuration.ConfigurationManager.AppSettings["UserName"];
string password = System.Web.Configuration.ConfigurationManager.AppSettings["Password"];

ASP.NET Core kann Konfigurationsdaten der Anwendung in einer beliebigen Datei speichern und diese während des Middleware-Bootstraps laden.ASP.NET Core can store configuration data for the application in any file and load them as part of middleware bootstrapping. Die in Projektvorlagen verwendete Standarddatei ist appsettings.json :The default file used in the project templates is appsettings.json :

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "AppConfiguration": {
    "UserName": "UserName",
    "Password": "Password"
  }
}

Diese Datei wird in Ihrer Anwendung in eine Instanz von IConfiguration in Startup.cs geladen:Loading this file into an instance of IConfiguration inside your application is done in Startup.cs :

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

Die Anwendung liest aus Configuration, um die Einstellungen abzurufen:The app reads from Configuration to get the settings:

string userName = Configuration.GetSection("AppConfiguration")["UserName"];
string password = Configuration.GetSection("AppConfiguration")["Password"];

Dieser Ansatz kann erweitert werden, um einen noch stabileren Prozess zu gewährleisten. Beispielsweise kann über die Abhängigkeitsinjektion ein Dienst mit diesen Werten geladen werden.There are extensions to this approach to make the process more robust, such as using Dependency Injection (DI) to load a service with these values. Durch die Abhängigkeitsinjektion wird eine Reihe stark typisierter Konfigurationsobjekte zur Verfügung gestellt.The DI approach provides a strongly-typed set of configuration objects.

// Assume AppConfiguration is a class representing a strongly-typed version of AppConfiguration section
services.Configure<AppConfiguration>(Configuration.GetSection("AppConfiguration"));

Hinweis

Ausführliche Informationen zur ASP.NET Core-Konfiguration finden Sie unter Configuration in ASP.NET Core (Konfiguration in ASP.NET Core).For a more in-depth reference to ASP.NET Core configuration, see Configuration in ASP.NET Core.

Native AbhängigkeitsinjektionNative dependency injection

Ein wichtiges Ziel bei der Erstellung großer, skalierbarer Anwendungen besteht in der losen Kopplung von Komponenten und Diensten.An important goal when building large, scalable applications is the loose coupling of components and services. Die Abhängigkeitsinjektion ist hierfür eine beliebte Methode und eine native Komponente von ASP.NET Core.Dependency Injection is a popular technique for achieving this, and it's a native component of ASP.NET Core.

Zur Implementierung der Dependency Injection greifen Entwickler in ASP.NET-Anwendungen auf Bibliotheken von Drittanbietern zurück.In ASP.NET apps, developers rely on a third-party library to implement Dependency Injection. Eine solche Bibliothek ist Unity, die von Microsoft Patterns & Practices bereitgestellt wird.One such library is Unity, provided by Microsoft Patterns & Practices.

Ein Beispiel für das Einrichten der Abhängigkeitsinjektion mit Unity ist die Implementierung der Schnittstelle IDependencyResolver, die einen UnityContainer umschließt:An example of setting up Dependency Injection with Unity is implementing IDependencyResolver that wraps a UnityContainer:

using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;

public class UnityResolver : IDependencyResolver
{
    protected IUnityContainer container;

    public UnityResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = container.CreateChildContainer();
        return new UnityResolver(child);
    }

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        container.Dispose();
    }
}

Erstellen Sie eine Instanz von UnityContainer, registrieren Sie den Dienst, und weisen Sie für Ihren Container den Abhängigkeitskonfliktlöser von HttpConfiguration der neuen Instanz von UnityResolver zu:Create an instance of your UnityContainer, register your service, and set the dependency resolver of HttpConfiguration to the new instance of UnityResolver for your container:

public static void Register(HttpConfiguration config)
{
    var container = new UnityContainer();
    container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
    config.DependencyResolver = new UnityResolver(container);

    // Other Web API configuration not shown.
}

Fügen Sie bei Bedarf IProductRepository ein:Inject IProductRepository where needed:

public class ProductsController : ApiController
{
    private IProductRepository _repository;

    public ProductsController(IProductRepository repository)  
    {
        _repository = repository;
    }

    // Other controller methods not shown.
}

Da die Abhängigkeitsinjektion eine Komponente von ASP.NET Core ist, können Sie Ihren Dienst in Startup.cs der Methode ConfigureServices hinzufügen:Because Dependency Injection is part of ASP.NET Core, you can add your service in the ConfigureServices method of Startup.cs :

public void ConfigureServices(IServiceCollection services)
{
    // Add application services.
    services.AddTransient<IProductRepository, ProductRepository>();
}

Genau wie bei Unity kann auch hier das Repository an einer beliebigen Stelle eingefügt werden.The repository can be injected anywhere, as was true with Unity.

Hinweis

Weitere Informationen zur Dependency Injection finden Sie unter Dependency Injection.For more information on dependency injection, see Dependency injection.

Bereitstellen statischer DateienServe static files

Ein wichtiger Teil der Webentwicklung ist die Möglichkeit, statische, clientseitige Objekte bereitzustellen.An important part of web development is the ability to serve static, client-side assets. Die häufigsten Beispiele für statische Dateien sind HTML-, CSS-, JavaScript- und Bilddateien.The most common examples of static files are HTML, CSS, Javascript, and images. Diese Dateien müssen am veröffentlichten Speicherort der Anwendung (oder des CDN) gespeichert werden. Außerdem muss auf diese verwiesen werden, damit sie von einer Anforderung geladen werden können.These files need to be saved in the published location of the app (or CDN) and referenced so they can be loaded by a request. Dieser Prozess wurde in ASP.NET Core geändert.This process has changed in ASP.NET Core.

Statische Dateien werden in ASP.NET in verschiedenen Verzeichnissen gespeichert. Der Verweis auf die Dateien erfolgt in den Ansichten.In ASP.NET, static files are stored in various directories and referenced in the views.

In ASP.NET Core werden statische Dateien im Webstammverzeichnis ( <content root>/wwwroot ) gespeichert, falls keine anderen Einstellungen vorgenommen wurden.In ASP.NET Core, static files are stored in the "web root" ( <content root>/wwwroot ), unless configured otherwise. Die Dateien werden über den Aufruf der Erweiterungsmethode UseStaticFiles aus Startup.Configure in die Anforderungspipeline geladen:The files are loaded into the request pipeline by invoking the UseStaticFiles extension method from Startup.Configure:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
}

Hinweis

Wenn Sie Anwendungen für .NET Framework entwickeln, installieren Sie das NuGet-Paket Microsoft.AspNetCore.StaticFiles.If targeting .NET Framework, install the NuGet package Microsoft.AspNetCore.StaticFiles.

Beispielsweise kann ein Browser an einem Speicherort wie http://<app>/images/<imageFileName> auf ein Bildobjekt im Ordner wwwroot/images zugreifen.For example, an image asset in the wwwroot/images folder is accessible to the browser at a location such as http://<app>/images/<imageFileName>.

Hinweis

Ausführliche Informationen zum Bereitstellen statischer Dateien in ASP.NET Core finden Sie im Artikel zu statischen Dateien.For a more in-depth reference to serving static files in ASP.NET Core, see Static files.

Mehrwertige cookiesMulti-value cookies

Mehrwertige cookies werden in ASP.NET Core nicht unterstützt.Multi-value cookies aren't supported in ASP.NET Core. Erstellen Sie ein cookie pro Wert.Create one cookie per value.

Partielle App-MigrationPartial app migration

Ein Ansatz für die partielle App-Migration besteht darin, eine IIS-Unteranwendung zu erstellen und nur bestimmte Routen von ASP.NET 4.x zu ASP.NET Core zu verschieben, wobei die URL-Struktur der App beibehalten wird.One approach to partial app migration is to create an IIS sub-application and only move certain routes from ASP.NET 4.x to ASP.NET Core while preserving the URL structure the app. Betrachten Sie beispielsweise die URL-Struktur der Anwendung aus der Datei applicationHost.config :For example, consider the URL structure of the app from the applicationHost.config file:

<sites>
    <site name="Default Web Site" id="1" serverAutoStart="true">
        <application path="/">
            <virtualDirectory path="/" physicalPath="D:\sites\MainSite\" />
        </application>
        <application path="/api" applicationPool="DefaultAppPool">
            <virtualDirectory path="/" physicalPath="D:\sites\netcoreapi" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:80:" />
            <binding protocol="https" bindingInformation="*:443:" sslFlags="0" />
        </bindings>
    </site>
    ...
</sites>

Verzeichnisstruktur:Directory structure:

.
├── MainSite
│   ├── ...
│   └── Web.config
└── NetCoreApi
    ├── ...
    └── web.config

[Bind] und Eingabeformatierer[BIND] and Input Formatters

In früheren Versionen von ASP.NET wurde das [Bind]-Attribut zum Schutz vor Overpostingangriffen verwendet.Previous versions of ASP.NET used the [Bind] attribute to protect against overposting attacks. Eingabeformatierer funktionieren in ASP.NET Core unterschiedlich.Input formatters work differently in ASP.NET Core. Das [Bind]-Attribut ist nicht mehr darauf ausgelegt, Overposting zu verhindern, wenn es mit Eingabeformatierern für die Verarbeitung von JSON- oder XML-Dateien verwendet wird.The [Bind] attribute is no longer designed to prevent overposting when used with input formatters to parse JSON or XML. Diese Attribute wirken sich auf die Modellbindung aus, wenn es sich bei den Quelldaten um Formulardaten handelt, die mit dem Inhaltstyp x-www-form-urlencoded gepostet wurden.These attributes affect model binding when the source of data is form data posted with the x-www-form-urlencoded content type.

Für Apps, die JSON-Informationen an Controller senden und JSON-Eingabeformatierer für die Verarbeitung der Daten verwenden, sollten Sie das [Bind]-Attribut durch ein Ansichtsmodell ersetzen, das den vom [Bind]-Attribut definierten Eigenschaften entspricht.For apps that post JSON information to controllers and use JSON Input Formatters to parse the data, we recommend replacing the [Bind] attribute with a view model that matches the properties defined by the [Bind] attribute.

Zusätzliche RessourcenAdditional resources