15. Jul 2019
Lesedauer 12 Min.
Routen und Controller
Inside ASP.NET Core 3.0, Teil 2
Annäherung an das ASP.NET der nächsten Dekade.

Dies ist der zweite Teil des Artikels zur Entwicklung von ASP.NET von seinen frühen Anfängen im Jahr 1999 bis heute und in die kommenden Jahre hinein. Er baut auf dem im vorangegangenen Heft erschienenen ersten Teil auf [1]. Der erste Teil befasste sich mit dem Weg zur modernen ASP.NET Pipeline und der ASP.NET Core Middleware. Weiter geht es nun mit Routen und Controllern.Ein Web-API ist womöglich nicht so reich an Endpunkten wie eine klassische UI-basierte Webanwendung. Dennoch könnte es ein Problem sein, die wenigen Endpunkte – vielleicht ein Dutzend – durch direkte und explizit zugeordnete URLs anzuordnen, wenn der Code nicht fest verdrahtet ist. Der Mechanismus einer Frontend-Klasse – des Controllers – mit Methoden, die in irgendeiner Weise an URL-Routen (zum Beispiel Attribut-Routing) gebunden sind, ist eine viel nachhaltigere Lösung. Sie haben alle Methoden an einem Ort und einen flexiblen Routing-Mechanismus, sei es Attribut-Routing (jede Controllermethode ist mit einem eindeutigen URL versehen) oder aktionsbasiertes Routing.Das Problem ist die Komplexität der Maschinen hinter den Steuerungen in MVC. Routing wurde mit ASP.NET MVC eingeführt, aber ursprünglich nur als Teil der MVC-Infrastruktur in ASP.NET Core importiert. Das Problem mit dem auf diese Weise implementierten Routing besteht darin, dass es innerhalb der MVC-Sandbox stattfindet und die Mapping-Logik gegenüber anderen Middleware-Komponenten völlig undurchsichtig ist. Das perfekte Beispiel dafür, warum MVC-sandboxed-Routing im Kontext der allgemeineren Architektur von ASP.NET Core (im Vergleich zum alten) ein Problem ist, ist CORS. Cross-Origin Resource Sharing ist ein Mechanismus, der es einer Webseite ermöglicht, auf eingeschränkte Endpunkte zuzugreifen, die auf einer anderen Domain gehostet werden. Um CORS zu unterstützen, muss eine ASP.NET-Core-Anwendung Einstellungen zweimal definieren, innerhalb und außerhalb des MVC-Bereichs. Dies liegt daran, dass die eingehende Anforderung vor oder nach MVC bearbeitet werden kann.Erst mit ASP.NET Core 2.2 wurde eine globale Handhabung des Routings außerhalb des Bereichs von MVC eingeführt. Diese Funktion, das sogenannte Endpunkt-Routing, stellt eine globale Datenquelle für die von der Anwendung verwalteten Endpunkte dar. Hier ist ein Beispiel für den Code der Endpunkt-Routing-Funktion in der Methode Configure.
var routeBuilder = new RouteBuilder(app);
routeBuilder.MapGet("hello/{name}", context => {
var name = context.GetRouteValue("name");
return context.Response.WriteAsync(
$"Hello, {name}!");§ });
routeBuilder.MapRoute("Trip routes",
"trip/{operation:regex(^track|create|edit$)}/
{id:int}");
var routes = routeBuilder.Build();
app.UseRouter(routes);
Wie Sie sehen, erstellen Sie eine Routentabelle mit einer Syntax, die zwischen MVC-Routing und Map-Methoden des IApplicationBuilder liegt. Die Routentabelle wird in der Pipeline von ASP.NET Core 2.2 und neueren Versionen früher als MVC verarbeitet. Auf diese Weise werden alle Middleware-Komponenten über die Route informiert. Ist CORS der Hauptanwendungszweck für das Endpunkt-Routing, würde ich sagen, dass das Endpunkt-Routing eher nebensächlich ist.Das globale Routing hat einen doppelten Vorteil: Es ermöglichte das Neuschreiben der internen Implementierung des MVC-Routings, was zu einer Leistungssteigerung führte, und machte es einfacher, ein Routing-Schema für ein relativ kleines API ohne Benutzeroberfläche zu entwickeln. Mit anderen Worten, das globale Routing war der erste Schritt zu einem tieferen Redesign, tatsächlich zu einer tieferen Verallgemeinerung der gesamten Pipeline von ASP.NET Core. In dieser Hinsicht ist ASP.NET Core 3.0 nur der erste Schritt, und vielleicht nur zufällig erhält ASP.NET Core 3.0 keinen LTS-Status (LTS = Long Term Support), was bedeutet, dass es noch etwas mehr Aufmerksamkeit erfahren wird, bevor Microsoft die Garantie eines langfristigen Supports geben möchte.Wenn Routing der erste Schritt zu einem tieferen Redesign des ASP.NET Core Frameworks ist, was wäre dann der zweite Schritt? Der zweite Schritt ist eine Verallgemeinerung der Controller.
Die Vorteile von POCO-Controllern
Ich gestehe, ich habe den Sinn von POCO-Controllern nie wirklich verstanden – bis vor Kurzem. Sicher, POCO-Controller sind leichtgewichtige Controller-Klassen, die sich wie eine klassische ASP.NET-MVC-Controller-Klasse verhalten, die nicht von der kanonischen Controller-Basisklasse erbt. In ASP.NET Core kann eine Controller-Klasse tatsächlich ein einfaches altes C#-Objekt sein:
public class PocoController {
// Your action methods here
}
Wie aber erkennt ASP.NET Core, dass eine bestimmte Klasse als Controller-Klasse behandelt werden sollte? Dafür gibt es zwei Möglichkeiten. Eine davon ist, wenn die Klasse das Suffix Controller im Namen hat. Die andere ist, wenn die Klasse mit dem Attribut Controller dekoriert ist.
[Controller]
public class Poco {
// Your action methods here
}
Auf den ersten Blick erreicht man mit einem POCO-Controller den Wegfall einiger Funktionen, um Overhead und Speicherbedarf zu reduzieren. Nicht von einer bekannten Basisklasse abzuleiten, schließt aber einige häufige Operationen aus und macht sie etwas aufwendiger zu implementieren. In erster Linie hat ein POCO-Controller keinen Zugriff auf den HTTP-Kontext und empfängt Parameter nur über die Modellbindung. Solange es um die Rückgabe von JSON geht, ist ein POCO-Controller genauso effektiv wie ein normaler Controller.
public class PocoController {
public IActionResult Today() {
return new ContentResult() {
Content = DateTime.Now.ToString("ddd, d MMM")
};
}
}
Geht es um den Umgang mit HTML-Views, wird es etwas komplizierter, und die Kosten für das Schreiben von Code steigen, was den Kompromiss mit der Performance weniger interessant macht. Sehen Sie sich als Beispiel den Code an, der notwendig wäre, um eine HTML-Ansicht basierend auf einem benutzerdefinierten Ansichtsmodell zu bedienen.
public IActionResult Index([FromServices]
IModelMetadataProvider provider)
{
// Initialize a ViewData dictionary to make
// data available within the view
var viewdata = new ViewDataDictionary<MyViewModel>(
provider, new ModelStateDictionary());
// Fill the data model for the view
viewdata.Model = new MyViewModel() { Title = "Hi!" };
// Invoke the view passing data
return new ViewResult() { ViewData =
viewdata, ViewName = "index" };
}
Letztendlich ist eine POCO-Steuerung ideal für einfache Dinge, so einfach wie das Bereitstellen einer klassenbasierten Fassade für einen Routen-URL. Es war ein weiterer kleiner Schritt auf einer längeren Reise. Was ist das Ziel dieser Transformationsreise der ASP.NET-Core-Runtime-Umgebung?
ASP.NET Core für Microservices
Das Internet ist voll von Blog-Posts und Artikeln, die darüber diskutieren, wie man Microservices mit ASP.NET Core erstellt. Die überwiegende Mehrheit von ihnen konzentriert sich auf den Aufbau eines Web-APIs und dessen Bereitstellung in einem Docker-Container. Lassen Sie uns den Docker-Teil, der hier nicht relevant ist, überspringen und uns auf den Teil über den Aufbau eines Web-APIs konzentrieren.In ASP.NET Core ist ein Web-API nichts Besonderes. Beim alten ASP.NET-Gebäude bedeutete ein Web-API, eine komplett neue Laufzeit-Pipeline zu erstellen, sich von der Host-Umgebung zu lösen, Ein- und Ausgabeformatierungen zu unterstützen, Inhalte auszuhandeln und idealerweise eine REST-Schnittstelle bereitzustellen. In ASP.NET Core ist ein Web-API einfach eine Sammlung von Controllern, möglicherweise, aber nicht unbedingt, POCO-Controllern. Am Ende ist ein Web-API eine HTTP-Fassade oder, allgemeiner gesagt, eine entfernte Softwarefassade, die über ein HTTP-basiertes Netzwerkprotokoll erreichbar ist, einschließlich WebSockets, TCP oder UDP, die Daten zurückgibt und fast keine Benutzeroberfläche bietet. Ein ASP.NET Core Microservice ist ein Web-API, das mit ASP.NET Core erstellt wurde.Die Frage ist, ob wir wirklich die gesamte MVC-Maschinerie für den Aufbau eines Web-API und eines Microservice mit ASP.NET Core benötigen. Lassen Sie uns kurz einige Fakten über das MVC-Anwendungsmodell, wie es ursprünglich in ASP.NET implementiert wurde und wie es derzeit in ASP.NET Core implementiert ist, besprechen.Wie in Bild 1 war das MVC-Anwendungsmodell im alten ASP.NET eine alternative Möglichkeit, eine eingehende Anforderung zu verarbeiten. Sie verzweigte aus der Haupt-Pipeline, um sich nach vollständiger Bearbeitung der Anforderung wieder mit ihr zu verbinden, um dem anfordernden Agenten Ergebnisse zu liefern. In ASP.NET Core (Bild 2) ist das MVC-Anwendungsmodell stattdessen eine terminierende Middleware, die direkt zum anfordernden Agenten zurückkehrt. In beiden Fällen behält das MVC-Anwendungsmodell jedoch seine eigene interne Pipeline aus Routing, Action-Methoden-Selektoren und einer Reihe von Aktionsfiltern, Berechtigungsfiltern und Ausnahmefiltern. Ein POCO-Controller enthält keine dieser Funktionen, da er strikt an die Interna der Basiscontrollerklasse gebunden ist. Gleichzeitig verfügte die alte Web-API-Pipeline, die völlig unabhängig von der MVC-Maschine sein sollte, über einen eigenen Satz von Filtern, mit denen die angebundenen Listener während der Bearbeitung der Anfrage eingreifen konnten. Generell gilt, dass mit der aktuellen Architektur des MVC-Controllers die Middleware-Komponenten keine Möglichkeit haben, einzugreifen. Sobald die Anfrageverarbeitung an einen Controller delegiert wurde, ist sie für andere, einschließlich globaler Diagnosetools, unzugänglich und unsichtbar. Der Nettoeffekt ist, dass bestimmte Querschnittsfunktionen wie Caching, Autorisierung, Protokollierung, Authentifizierung, Zustandsprüfung außerhalb und innerhalb von MVC dupliziert und bestenfalls nur über Dependency Injection (DI) injiziert werden müssen.
Web Forms und MVC-Anwendungsmodelleder alten ASP.NET Runtime-Pipeline(Bild 1)
Autor

Die ASP.NET Core Runtime-Pipelineund die MVC Application Middleware(Bild 2)
Autor
Gleichzeitig ist ein Microservice ein einfaches Web-Frontend für REST- und RPC-Clients und das Controller-Artefakt ist ideal, um diese Anfragen zu empfangen und zu versenden. Allerdings ist eine einheitliche und gemeinsame Infrastruktur erforderlich, die Routing (in ASP.NET Core 2.2), Unterstützung für mehrere Anwendungsmodelle (in ASP.NET Core 3.0) und idealerweise Aktionsfilter (hoffentlich in naher Zukunft) beinhaltet.
Zusätzliche Anwendungsmodelle
ASP.NET Core 3.0 ist die erste große Version von ASP.NET Core, die mit allen Teilen ausgeliefert wird, und in den Falten davon finden wir drei Varianten von Anwendungsmodellen, die ideal sind, um Microservices und moderne Web-/Mobil-Lösungen basierend auf einem reichen Frontend und einem stillen Backend zu betreiben. Bild 3listet einige der (Micro-)Servicetypen auf, die Sie mit ASP.NET Core 3.0 erstellen können, wie sie in Visual Studio 2019 angezeigt werden. Insbesondere werden die Optionen Worker Service und gRPC Service hervorgehoben. Obwohl sie nicht in der Liste der Standard-Templates von Visual Studio 2019 enthalten ist, möchte ich eine dritte Art von Dienst erwähnen, den SignalR Service.
ASP.NET Core Services, die als Vorlagen in Visual Studio 2019verfügbar sind(Bild 3)
Autor
Es gibt drei Arten von ASP.NET-Core-basierten Diensten, die keine Benutzeroberfläche benötigen (wie HTML, Razor-Seiten und Razor-Ansichten), aber andererseits in Controllern die natürliche Fassade finden. Durch Controller-Methoden können Sie sogar Endpunkte, die über verschiedene Protokolle und Nutzlasten verfügbar sind, einfach freigeben.Im Moment basieren die SignalR-Dienste auf der Hub-Klasse. Worker-Services bauen auf Klassen auf, die auf der IHostedService-Schnittstelle basieren. Das .NET Core Framework bringt die einzige BackgroundService-Klasse für das Interface, mit der lang laufende Aufgaben in die Warteschlange gestellt werden können. Um Scheduler oder Timer zu erstellen, schreiben Sie Ihre eigenen Klassen auf Basis der Schnittstelle. Schließlich basieren gRPC-Dienste auf der dynamisch generierten Klasse, die in der .proto-Datei als Vertrag des Dienstes beschrieben ist.Das Interessante ist, dass mindestens zwei (gRPC und SignalR) dieser drei Klassentypen URL-basierte Endpunkte enthalten. Der dritte (Worker Service) besteht immer noch aus Code, der ein aufrufbares Fragment darstellt, das gut in den Kontext eines Microservices passt.Worker Services, SignalR Hubs, gRPC Services und POCO-Controller sind verschiedene Arten von HTTP-
Fassaden, die alle durch ein breiteres Controller-Konzept angesprochen werden können. Mit diesem neuen Konzept eines Controllers und dem bestehenden globalen Routing glaube ich, dass ASP.NET Core endlich völlig frei von jeglichem Legacy-Erbe aus dem vergangenen ASP.NET wäre.
Fassaden, die alle durch ein breiteres Controller-Konzept angesprochen werden können. Mit diesem neuen Konzept eines Controllers und dem bestehenden globalen Routing glaube ich, dass ASP.NET Core endlich völlig frei von jeglichem Legacy-Erbe aus dem vergangenen ASP.NET wäre.
Erstellen von gRPC-Diensten
Das gRPC-Framework ist ein relativ neues Framework, das speziell für Remote-Procedure-Call-Systeme (RPC) geschrieben wurde. Es wurde ursprünglich bei Google entwickelt und anschließend quelloffen vertrieben. Das gRPC-Framework nutzt HTTP/2 als Transportprotokoll und verwendet eine eigene Schnittstellenbeschreibungssprache, aus der die eigentliche Serviceklasse dynamisch aufgebaut wird. Hier ist eine Beispiel-Schnittstellendefinition, die als .proto-Datei im Projekt gespeichert ist:
syntax = "proto3";
package Company.Api;
service MyService {
rpc DoWork (DoWorkRequest) returns (DoWorkReply) {}
}
message DoWorkRequest { string data = 1; }
message DoWorkReply { string result = 1; }
Die Datei legt den Namen des Pakets und die öffentliche Schnittstelle des Dienstes fest. Im Beispielcode besteht die Schnittstelle aus einer einzigen Methode namens DoWork. Von allen Methoden wird erwartet, dass sie ein Datenübertragungsobjekt zum Empfangen und Zurückgeben von Daten haben. Im Beispiel sind dies DoWorkRequest und DoWorkReply. Alle diese Inhalte werden in C#-Klassen umgewandelt und zu einer Assembly kompiliert.Wenn Sie eine Authentifizierung benötigen, dann ist die Verwendung von Identity Server 4.0 das Einfachste, was Sie in einem ASP.NET-Core-Szenario tun können. Die Authentifizierung ändert jedoch nichts an der Schnittstellendefinition. Die Authentifizierung wird im Klempnercode zwischen der gRPC-Klasse und dem ASP.NET Core Framework hinzugefügt. Hier ist die Startklasse eines exemplarischen gRPC-ASP.NET-Dienstes:
public class Startup {
public void ConfigureServices(
IServiceCollection services) {
services.AddGrpc();
}
public void Configure(IApplicationBuilder app) {
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapGrpcService<MyService>(); });
}
}
Für die Authentifizierung fügen Sie einfach die üblichen Authentifizierungs- und Autorisierungsaufrufe hinzu, die der Identitätsdienst benötigt. Der Kunde dieses gRPC-Dienstes nimmt das folgende Formular an:
var channel = new Channel(server, credentials);
var client = new MyService. MyServiceClient(channel);
var reply = await client.DoWorkAsync(
new DoWorkRequest { Data = "..." }, callOptions);
await channel.ShutdownAsync();
Die Anmeldeinformationen sind eine Instanz der Klasse SslCredentials, die beispielsweise für ein Zertifikat eingerichtet wurde, wenn Sie möchten, dass es sich um HTTPS handelt. Andernfalls ist es der Wert ChannelCredentials.In-
secure. Das Token für die Authentifizierung wird über die Aufrufoptionen übergeben und über den üblichen Autorisierungs-Header übermittelt.
secure. Das Token für die Authentifizierung wird über die Aufrufoptionen übergeben und über den üblichen Autorisierungs-Header übermittelt.
Worker Services anlegen
ASP.NET Core 3.0 unterstützt zwei Haupttypen von gehosteten Diensten. Einer davon ist der Hintergrunddienst – derjenige, den die Visual-Studio-2019-Vorlage standardmäßig einrichtet. Der andere ist ein Taskplaner. Sie verwenden einen Hintergrunddienst jedes Mal, wenn Sie eine lang laufende Aufgabe haben, die Sie entladen möchten, ohne den Server zu blockieren. Die Klasse BackgroundService erstellt eine separate Aufgabe und stellt ein Wrapper-API zum Starten/Stoppen bereit. Alles, worauf Sie sich konzentrieren müssen, ist die eigentliche Aufgabe. Wenn Sie mit der BackgroundService-Klasse in Windows Forms und WPF vertraut sind, ist es fast die gleiche Erfahrung, außer dass sie jetzt auch für das Web funktioniert. Die Klasse BackgroundService implementiert die Schnittstellen IHostedService und IDisposable. Wenn Sie eine Aufgabe planen und sicherstellen wollen, dass Ihr Code periodisch oder zu einem bestimmten (wiederkehrenden) Zeitpunkt ausgeführt wird, müssen Sie eine eigene Implementierung beider Schnittstellen erstellen. Hier ist ein Beispiel, das auf einem Timer basiert:
public class DailyUpdaterService :
IHostedService, IDisposable {
private Timer _timer;
public void Dispose() {
_timer?.Dispose();
}
public Task StartAsync(
CancellationToken cancellationToken) {
_timer = new Timer(PerformTask, null, TimeSpan.Zero,
TimeSpan.FromDays(1));
return Task.CompletedTask;
}
public Task StopAsync(
CancellationToken cancellationToken) {
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
private void PerformTask(object state) {
// Do some work here periodically
}
}
Der gehostete Dienst wird beim Start der Anwendung aktiviert und beim Herunterfahren der Anwendung wieder beendet. Die Instanz läuft als Singleton und der Timer stellt sicher, dass Ihr Code (der Code in PerformTask im Beispiel) aufgerufen wird, wenn der Timer tickt. Der obige Code löst die Aufgabe alle 24 Stunden aus, aber der tatsächliche Tick hängt von der Startzeit ab. Um sicherzustellen, dass die Aufgabe zu einem festen Zeitpunkt ausgeführt wird, sollten Sie den Timer so anpassen, dass er bei Bedarf ausgelöst wird.Abhängig von der zu erwartenden Arbeit, die von der zeitgesteuerten Aufgabe ausgeführt werden soll, können Sie ihr eine Lebensdauer von einem bestimmten Umfang geben. Mit anderen Worten, der Scope-Service lässt sich nicht einfach direkt wie im obigen Codeausschnitt aufrufen, sondern muss in eine Klasse verpackt werden, die in die Anwendung als Scope-Abhängigkeit injiziert wird. Sie legen zunächst eine Klasse an, um die Arbeit, die Sie periodisch erledigen möchten, abzuschließen:
public class MyTimedTask
{
public void PerformTask(object state) {
// Some work to be done periodically
// with a per-request lifetime
}
}
Als Nächstes injizieren Sie diese Klasse in das DI-System mit einer definierten Lebensdauer. In der Methode ConfigureServices der Anwendung fügen Sie den folgenden Code hinzu:
services.AddHostedService<DailyUpdaterService>();
services.AddScoped<MyTimedTask>();
Beachten Sie, dass die erste Zeile ohnehin hinzugefügt werden muss, auch wenn ein gehosteter Singleton-Dienst in Ordnung ist. Schließlich muss der gehostete Dienst optimiert werden, um die Abhängigkeitsinjektion zu ermöglichen.
public class DailyUpdaterService :
IHostedService, IDisposable
{
public DailyUpdaterService(IServiceProvider services)
{ }
private void PerformTask(object state) {
// Do some work here periodically
using (var scope = Services.CreateScope()) {
var timedTask = scope.ServiceProvider
.GetRequiredService<MyTimedTask>();
timedTask.PerformTask(state);
}
}
}
Erstellen von SignalR-Diensten
Wenn Sie SignalR zu einer ASP.NET Core-Anwendung hinzufügen, müssen Sie lediglich eine Hub-Klasse erstellen, um Ihre Endpunkte anzuzeigen. Das Interessante daran ist, dass die Hub-Klasse völlig unabhängig von Controllern sein kann. Mit anderen Worten, Sie benötigen MVC nicht, um die Vorteile der SignalR-Benachrichtigungsfunktionen zu nutzen.In der ASP.NET-Core-Version der SignalR-Bibliothek verhält sich die Hub-Klasse wie ein Frontend-Controller, der bereit ist, externe Anfragen zu bedienen. Eine Methode, die von einer Hub-Klasse exponiert wird, kann jede Arbeit ausführen, auch Arbeiten, die nichts mit dem anwendungsübergreifenden Benachrichtigungscharakter des Frameworks zu tun haben. Hier ein Beispiel:
public class SampleHub : Hub {
public async Task SendMessage(string user,
string message) {
await Clients.All.SendAsync(
"ReceiveMessage", user, message);
}
}
Die SendMessage-Methode ist als Endpunkt für den JavaScript-Code eines Clients verfügbar, der aufgerufen werden kann. Gleichzeitig kann der SignalR-Kontext aus den klassischen MVC-Controller-Klassen über den Wrapper IHubContext<THub> abgerufen werden.
public TaskController(
IHubContext<SampleHub> hubContext) {
_sampleHubContext = hubContext; }
Über den Hub-Kontext können Controller-Methoden an die angeschlossenen Clients zurückmelden oder Hub-Methoden aufrufen, damit sowohl Logik als auch Nachrichten erfolgen.
Zusammenfassung
ASP.NET Core wird in wenigen Wochen ausgeliefert. Es wird wohl nicht die nächste Langzeit-Support-Version (LTS) von ASP.NET Core sein, aber sie ist nahe dran. Wenn das Angekündigte durch Fakten bestätigt wird, wird ASP.NET Core 3.1 die nächste LTS-Version sein, welche die aktuelle LTS-Version (ASP.NET Core 2.1) ersetzt. Wenn Sie sich die neuen Funktionen in ASP.NET Core 3.0 ansehen, werden Sie offen gesagt darüber hinaus nicht viel mehr finden. Wahrscheinlich sind das einzig wirklich Neue an ASP.NET die Blazor-Komponenten. Blazor wurde in diesem Artikel nicht behandelt, aber ich habe in [2] einen Artikel dazu geschrieben. Mehr als in diesem Artikel vorgestellt wurde, bietet Blazor derzeit noch nicht.ASP.NET Core 3.0 ist jedoch die erste Version von ASP.NET Core seit über fünf Jahren, die mit allen Einzelteilen ausgeliefert wird. Es gibt gRPC, SignalR, Worker Services, Razor Pages und ein wenig Blazor auch. Es gibt nicht viel anderes, worauf man warten muss, das die Adaption für eine längere Zeit verzögern könnte. Die Zeit für ein Upgrade ist jetzt gekommen. Punkt. Gleichzeitig ist die Gesamtarchitektur der ASP.NET Core Runtime jedoch noch nicht perfekt, da sie noch einige Designabhängigkeiten (nicht Codeabhängigkeiten) vom alten ASP.NET hat – insbesondere die Art und Weise, wie das alte ASP.NET das MVC-Anwendungsmodell integriert hat. Ich erwarte, dass sich das in der Zukunft ändern wird, aber kann kaum sagen, wann. Auch bin ich nicht in der Lage, die Art und Weise zu erraten, wie sich das Laufzeitdesign entwickeln wird, um im Wesentlichen ein gemeinsames Controller-Modell bereitzustellen, das alle Arten von Webservices umfassen könnte, die heute notwendig sind, um effektiv ASP.NET-Core-basierte Microservices oder Webfassaden für Einzelseitenanwendungen zu implementieren.Fussnoten
- Dino Esposito, Inside ASP.NET Core 3.0, Teil 1, dotnetpro 7/2019, Seite 16 ff., http://www.dotnetpro.de/A1907ASPNETCore3
- Dino Esposito, Der Nachfolger von JavaScript?, dotnetpro 1/2019, S. 26 ff, http://www.dotnetpro.de/A1901Blazor