Teil 2: Unter der Motorhaube

Web APIs mit ASP.NET MVC 6
Kommentare

Nachdem der erste Teil dieser Serie gezeigt hat, wie mit ASP.NET MVC 6 künftig Web APIs bereitgestellt werden können, betrachtet der vorliegende zweite Teil das Konzept der Formatter. Dabei handelt es sich um Komponenten, die zum (De-)Serialisieren von Objekten zum Einsatz kommen und auf diese Weise Datenformate wie JSON oder XML unterstützen. Daneben geht dieser zweite Teil auch auf das Protokollieren von Aufrufen sowie auf das Thema Self-Hosting ein. Die hier beschriebenen Möglichkeiten beziehen sich auf die aktuell vorliegende Beta 3 von ASP.NET MVC 6, die mit der CTP 6 von Visual Studio 2015 ausgeliefert wird.

Formatter

Zum Serialisieren und Deserialisieren von Objekten nutzt ASP.NET MVC 6, ähnlich wie auch die Vorgängerversion ASP.NET Web API, so genannte Formatter. Dabei unterscheidet MVC 6 zwischen InputFormatter und OutputFormatter. Erstere kümmern sich um das Deserialisieren von eingehenden Daten. Ein Beispiel dafür ist das Umwandeln von JSON-basierten Informationen in Objekte. Letztere kümmern sich hingegen um das Serialisieren von ausgehenden Daten, beispielsweise das Umwandeln von Objekten in ein JSON-Dokument. Sämtliche Input- und OutputFormatter verwaltet MVC 6 in einer Auflistung. Immer, wenn es Daten zu (de-)serialisieren gilt, durchsucht MVC 6 diese Auflistungen nach einem passenden Formatter und zieht ihn heran. Die Auswahl erfolgt dabei anhand des Typs des vorherrschenden Objekts sowie anhand des MIME-Type des gewünschten Datenformats.

Standardmäßig finden sich in den genannten Auflistungen Formatter, die sich um die Arbeit mit JSON kümmern. Sie nennen sich JsonInputFormatter und JsonOutputFormatter und basieren auf dem populären Open-Source-Projekt Json.NET. Die Auflistung der Output Formatter beinhaltet in der hier betrachteten Beta 3 darüber hinaus zwei weitere standardmäßig eingerichtete Einträge: Der StringOutputFormatter kümmert sich um das Verarbeiten von Ergebnissen, die lediglich aus einem String bestehen. Die Aufgabe des  HttpNoContentFormatters ist es, den HTTP-Statuscode auf 204 (NO CONTENT) zu setzen, falls keine Antwort vorliegt. Das ist bei Operationen, die den Rückgabewert void aufweisen, der Fall.

Formatter konfigurieren

Um die (De-)Serialisierung zu beeinflussen, kann der Entwickler beim Start der Anwendung die standardmäßig eingerichteten Formatter konfigurieren bzw. die genannten Auflistungen manipulieren, sprich weitere Formatter hinzufügen oder bestehende entfernen. Ein Beispiel dafür findet sich in Listing 1. Es zeigt die Methode ConfigureServices der Klasse Startup, die sich in jedem ASP.NET-MVC-6-Projekt befindet und die Webanwendung beim Hochfahren initialisiert. Die Aufgabe von ConfigureServices ist es, austauschbare Komponenten über den Dependency-Injection-Mechanismus von ASP.NET zur Verfügung zu stellen. Diese Komponenten, die sich auch Services oder Dienste nennen, hinterlegt ConfigureServices in einer vom Webserver übergebenen Auflistung des Typs IServiceCollection.

Zu diesen Komponenten zählen auch die Services, auf die sich ASP.NET MVC stützt. Die Erweiterungsmethode AddMvc fügt sie hinzu. Die Methode Configure gibt dem Entwickler die Möglichkeit, die hinzugefügten Komponenten zu konfigurieren. Dazu führt er als Typparameter den Typ der Komponente an, über die Konfigurationsoptionen festzulegen sind. Im Fall von ASP.NET MVC nennt sich diese Komponente MvcOptions. Der erste Parameter dieser Methode ist ein Lambda-Ausdruck, der eine Instanz dieser Komponente entgegennimmt und sie konfiguriert.

Listing 1 durchforstet die Auflistung InputFormatters, um den standardmäßig vorherrschenden JsonOutputFormatter zu finden. Dabei ist zu beachten, dass die Auflistung OutputFormatterDescriptor-Objekte, die – wie der Name schon vermuten lässt, OutputFormatter beschreiben – beinhaltet. Über ihre Eigenschaft Instance verweisen diese Objekte auf den jeweiligen Formatter. Daher findet im betrachteten Fall auch mit Select eine Projektion auf diese Eigenschaft statt. Die LINQ-Methode OfType filtert anschließend nach dem gewünschten Typ, und FirstOrDefault liefert ein einzelnes Objekt retour. Damit diese LINQ-Methoden zur Verfügung stehen, ist der Namensraum System.Linq einzubinden.

Der auf diesem Weg ermittelte JsonOutputFormatter bietet sich über seine Eigenschaft ReferenceLoopHandling ein Konfigurationsobjekt an. Um die Arbeit mit diesem Objekt zu veranschaulichen, setzt das betrachtete Listing dessen Eigenschaft ReferenceLoopHandling auf Ignore. Das hat zur Folge, dass der Formatter Zyklen in den zu serialisierenden Objektgraphen ignoriert. Ein solcher Zyklus ergibt sich zum Beispiel, wenn zwei Objekte gegenseitig aufeinander verweisen. Gerade beim Einsatz von Entitäten mit bidirektionalen Beziehungen ist dies häufig der Fall. Der Standardwert von ReferenceLoopHandling nennt sich Error. Diese Einstellung bewirkt, dass der Formatter beim Vorfinden eines Zyklus eine Ausnahme auslöst.

Der Vollständigkeit halber wiederholt das betrachtete Listing dieselben Schritte für den JsonInputFormatter. Informationen über die vielen zur Verfügung stehenden Konfigurationsoptionen finden sich hier.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().Configure(options =>
    {
        var jsonOutput = options
                               .OutputFormatters
                               .Select(d => d.Instance)
                               .OfType()
                               .FirstOrDefault();

        jsonOutput.SerializerSettings.ReferenceLoopHandling = 
                             Newtonsoft.Json.ReferenceLoopHandling.Ignore;

        var jsonInput = options
                               .InputFormatters
                               .Select(d => d.Instance)
                               .OfType()
                               .FirstOrDefault();

        jsonInput.SerializerSettings.ReferenceLoopHandling = 
                             Newtonsoft.Json.ReferenceLoopHandling.Ignore;

    }
}

Formatter für XML einrichten

Im Lieferumfang von MVC 6 befinden sich auch Formatter für die Arbeit mit XML. Die Formatter XmlDataContractSerializerOutputFormatter und XmlDataContractSerializerInputFormatter verwenden dazu den aus der Welt von WCF bekannten DataContractSerializer. Mit dem XmlSerializerOutputFormatter und XmlSerializerInputFormatter liegen ergänzend dazu zwei Alternativen vor, die sich nicht des DataContractSerializers bedienen, sondern auf den älteren, seit den ersten Tagen von .NET vorliegenden XmlSerializer zurückgreifen.

Da diese Formatter standardmäßig nicht eingerichtet sind, muss der Entwickler sie innerhalb der in Listing 1 gezeigten Methode ConfigureServices zu den Auflistungen OutputFormatters und InputFormatters hinzufügen:

var xmlOutput = new XmlDataContractSerializerOutputFormatter(); options.OutputFormatters.Add(xmlOutput); var xmlInput = new XmlDataContractSerializerInputFormatter(); options.InputFormatters.Add(xmlInput);

Eigenen InputFormatter implementieren

Um eigene InputFormatter bereitzustellen, implementiert der Entwickler das Interface IInputFormatter. Dieses Interface gibt zwei Methoden vor: CanRead und ReadAsync. CanRead prüft, ob der InputFormatter vorliegende Daten deserialisieren kann. Das hängt in der Regel vom vorherrschenden Datenformat sowie vom gewünschten Objekttyp ab. ASP.NET MVC 6 nutzt diese Methode, um einen geeigneten Formatter zu ermitteln. Dazu iteriert das Framework sämtliche registrierte InputFormatter und zieht den ersten, dessen Methode CanRead den Wert true liefert, heran. Das zeigt, dass auch die Reihenfolge, in der die Formatter in der Auflistung vorliegen, ausschlaggebend für das Verhalten zur Laufzeit ist. Nachdem MVC 6 auf diese Weise einen Formatter gewählt hat, ruft es dessen Methode ReadAsync auf, die sich um die Deserialisierung kümmert. Sowohl CanRead als auch ReadAsync bekommen von ASP.NET MVC ein Kontextobjekt übergeben, das über den aktuellen Fall informiert, beispielsweise über die vorliegenden Kopfzeilen und somit auch über das vorliegende Datenformat (Content Type) sowie über den gewünschten Objekttyp.

Ein Beispiel dafür findet sich in Listing 2. Es zeigt einen benutzerdefinierten InputFormatter, der sich CsvFlugInputFormatter nennt, und in der Lage ist, ein Flugobjekt zu deserialisieren, das in Form eines kommagetrennten String übergeben wurde. Seine Methode CanRead entnimmt dem übergebenen Kontext das Request-Objekt, das die aktuelle Anfrage beschreibt. Dessen Eigenschaft ContentType informiert über den Wert der übersendeten gleichnamigen Kopfzeile (Content Type) und somit per Definition auch über das Datenformat (den MIME Type) der übersendeten Daten. Am Ende prüft CanRead, ob es sich dabei um text/csv handelt und ob die vorliegenden Daten in ein Flugobjekt überzuführen sind. Letztere Information findet sich in der Eigenschaft ModelType, die der Kontext anbietet. Nur wenn beides zutrifft, retourniert CanRead den Wert true.

Die Methode ReadAsync entnimmt dem übergebenen Kontext ebenfalls das aktuelle Request-Objekt. Ihre Eigenschaft Body verweist auf einen Stream, der die übersendeten Nutzdaten repräsentiert. Über einen StreamReader liest sie dessen Inhalt als String und führt diesen in ein Flugobjekt über.

public class CsvFlugInputFormatter : IInputFormatter
{  
    public bool CanRead(InputFormatterContext context)
    {
        var request = context.ActionContext.HttpContext.Request;
        var contentType = request.ContentType;

        if (string.IsNullOrEmpty(contentType)) return false;

        return contentType == "text/csv" && context.ModelType == typeof(Flug);
    }

    public async Task ReadAsync(InputFormatterContext context)
    {
        var request = context.ActionContext.HttpContext.Request;
            
        using(var reader = new StreamReader(request.Body, Encoding.UTF8, 
                                                    false, 8*1024, leaveOpen: true))
        {
            var line = await reader.ReadLineAsync();
            var parts = line.Split(',');

            var flug = new Flug();
            flug.Id = Convert.ToInt32(parts[0]);
            flug.Datum = Convert.ToDateTime(parts[1]);
            flug.Abflugort = Convert.ToString(parts[2]);
            flug.Zielort = Convert.ToString(parts[3]);

            flug.FreiePlaetze = Convert.ToInt16(parts[4]);
            flug.Plaetze = Convert.ToInt16(parts[5]);
            flug.PilotId = Convert.ToInt32(parts[6]);

            return flug;
        }
    }
}

Eigenen OutputFormatter implementieren

Um einen eigenen OutputFormatter bereitzustellen, implementiert der Entwickler das Interface IOutputFormatter. Dieses gibt die Methoden GetSupportedContentTypes, CanWriteResult sowie WriteAsync vor. GetSupportedContentTypes liefert eine Auflistung mit sämtlichen unterstützten Datenformaten (MIME-Types). Die Methode CanWriteResult prüft, ob der Formatter in der Lage ist, ein vorliegendes Objekt zu serialisieren. Um einen geeigneten OutputFormatter zu finden, iteriert MVC 6 sämtliche OutputFormatter und prüft durch Aufruf von GetSupportedContentTypes sowie CanWriteResult, welche Instanzen für den aktuellen Fall in Frage kommen. Der erste auf diesem Weg ermittelte Formatter wird herangezogen. WriteAsync kümmert sich anschließend um die Serialisierung.

Ein Beispiel dafür stellt der CsvFlugOutputFormatter in Listing 3 dar. Er weist eine private Auflistung supportedTypes auf, die sämtliche unterstützte Datentypen repräsentiert. GetSupportedContentTypes liefert diese Auflistung zurück, ohne die von ASP.NET MVC übergebenen Parameter zu beachten. Diese könnte GetSupportedContentTypes nutzen, um den deklarierten Typ (declaredType) und den Laufzeittyp (runtimeType) des zu serialisierenden Objekts sowie die vom Aufrufer akzeptierten Datenformate (contentType) in Erfahrung zu bringen. Wenn der Laufzeittyp vom deklarierten Typ abweicht, muss es sich dabei – wie in .NET üblich – um einen Subtyp davon handeln.

Die Methode CanWriteResult nimmt ein Kontextobjekt mit Informationen über den aktuellen Vorgang (context) sowie ein Objekt mit einem vom Aufrufer akzeptierten Datenformat (contentType) entgegen. Die hier betrachtete Implementierung entnimmt der Eigenschaft Object des Kontextobjekts das zu serialisierende Objekt. Anschließend prüft sie, ob das übergebene Datenformat unterstützt wird und ob es sich beim zu serialisierenden Objekt um ein Objekt vom Typ Flug handelt. Trifft beides zu, legt sie über den Context das zu nutzende Datenformat und die zu nutzende Kodierung fest. Letztere wird im betrachteten Beispiel hardkodiert auf UTF-8 (Unicode) gesetzt. In aufwändigeren Implementierungen könnte durch einen Vergleich der vom Aufrufer unterstützten Kodierungen mit den vom Formatter unterstützten Kodierungen eine Kodierung ausgewählt werden. Ähnlich wie die vom Aufrufer unterstützten Datenformate finden sich auch die vom Aufrufer unterstützten Kodierungen, sofern er sie bekannt gibt, in den übersendeten Kopfzeilen wieder. Die hierzu per Definition zu nutzende Kopfzeile nennt sich Accept Charset und kann über die Auflistung Headers des Request-Objekts abgerufen werden:

var charSet = Request.Headers[„Accept-Charset“]

Anschließend zeigt CanWriteResult mit dem Rückgabewert true an, dass der OutputFormatter in der Lage ist, das Objekt zu serialisieren. In Fällen, in denen das gewünschte Datenformat nicht unterstützt wird oder in denen andere Objekttypen vorliegen, liefert CanWriteResult hingegen false.

Die Methode WriteAsync entnimmt dem von MVC 6 übergebenen Kontext das aktuelle Response-Objekt, das die Antwortnachricht repräsentiert. Darüber hinaus erhält WriteAsync Zugriff auf die von CanWriteResult im Kontext verstauten Informationen. Darunter befindet sich die gewünschte Kodierung. Das zu serialisierende Objekt findet sich auch hier in der Eigenschaft Object, die vom Kontext angeboten wird. Die Eigenschaft Body von Response repräsentiert die zurückzuliefernden Nutzdaten als Stream. Um in diesem Stream zu schreiben, zieht die betrachtete Implementierung einen StreamWriter heran.

public class CsvFlugOutputFormatter : IOutputFormatter
{
    private List supportedTypes = 
                                        new List();

    public CsvFlugOutputFormatter()
    {
        supportedTypes.Add(MediaTypeHeaderValue.Parse("text/csv"));
    }

    public IReadOnlyList GetSupportedContentTypes(
              Type declaredType, Type runtimeType, MediaTypeHeaderValue contentType)
    {
        return supportedTypes;
    }

    public bool CanWriteResult(OutputFormatterContext context,
                                   MediaTypeHeaderValue contentType)
    {
        var obj = context.Object;
        if (supportedTypes.Contains(contentType) 
                               && obj.GetType() == typeof(Flug))
        {
            context.SelectedContentType = contentType;
            context.SelectedEncoding = Encoding.UTF8;
            return true;
        }
        return false;
    }

    public async Task WriteAsync(OutputFormatterContext context)
    {
        var response = context.ActionContext.HttpContext.Response;
        var flug = context.Object as Flug;

        var selectedEncoding = context.SelectedEncoding;

        if (flug != null)
        {
            using (var writer = new StreamWriter(response.Body, 
                                           selectedEncoding, 1024, leaveOpen: true))
            {
                await writer.WriteLineAsync(
                                flug.Id + "," +
                                flug.Datum + "," +
                                flug.Abflugort + "," +
                                flug.Zielort + "," +
                                flug.FreiePlaetze + "," +
                                flug.Plaetze + "," +
                                flug.PilotId);
            }
        }

    }
}

Als Alternative zum Interface IOutputFormatter bietet MVC 6 auch die Basisklasse OutputFormatter an. Sie implementiert bereits eine Aushandlung des zu verwendenden Datenformats und der zu nutzenden Kodierung. Dazu vergleicht sie die vom Formatter unterstützten Datenformate und Kodierungen mit den vom Client angeforderten Formattern und Datenformaten.

Ein Beispiel für die Nutzung der Basisklasse OutputFormatter findet sich in Listing 4. Die hier gezeigte Klasse CsvFlugOutputFormatter2 gibt über ihren Konstruktor die unterstützten Datenformate und Kodierungen bekannt. Dazu nutzt sie die geerbten Eigenschaften SupportedMediaTypes und SupportedEncodings.

CanWriteType informiert darüber, ob der Formatter einen bestimmten Typ serialisieren kann und WriteResponseBodyAsync kümmert sich, analog zum Beispiel in Listing 3, um die Serialisierung. Die von den Möglichkeiten der Basisklasse ausgehandelte Kodierung ist hier aus der Eigenschaft SelectedEncoding des Kontextobjekts ersichtlich. Analog dazu findet WriteResponseBodyAsync in der Eigenschaft SelectedContentType des Kontextobjekts das ausgehandelte Datenformat. Letzteres ist im betrachteten Fall jedoch nur durch einen Kommentar angedeutet, zumal der betrachtete Formatter nur ein einziges Datenformat unterstützt. 

public class CsvFlugOutputFormatter2 : OutputFormatter
{
    public CsvFlugOutputFormatter2()
    {
        this.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/csv"));
        this.SupportedEncodings.Add(Encoding.UTF8);
        this.SupportedEncodings.Add(Encoding.GetEncoding("ISO-8859-1"));
    }

    protected override bool CanWriteType(Type declaredType, Type runtimeType)
    {
        return declaredType == typeof(Flug);
    }

    public override async Task WriteResponseBodyAsync(
                                         OutputFormatterContext context)
    {
        var response = context.ActionContext.HttpContext.Response;
        var flug = context.Object as Flug;

        var selectedEncoding = context.SelectedEncoding;
        // context.SelectedContextType

        if (flug != null)
        {
            using (var writer = new StreamWriter(response.Body,
                                           selectedEncoding, 1024, leaveOpen: true))
            {
                await writer.WriteLineAsync(
                                flug.Id + "," + 
                                flug.Datum + "," + 
                                flug.Abflugort + "," + 
                                flug.Zielort + "," +
                                flug.FreiePlaetze + "," +
                                flug.Plaetze + "," +
                                flug.PilotId);
            }
        }

    }
}

Eigenen OutputFormatter registrieren

Zum Registrieren eigener Formatter fügt der Entwickler Instanzen davon innerhalb der Methode ConfigureServices der Klasse Startup zu den Auflistungen OutputFormatters bzw. InputFormatters hinzu:

var csvOutput = new CsvFlugOutputFormatter(); options.OutputFormatters.Add(csvOutput); var csvInput = new CsvFlugInputFormatter(); options.InputFormatters.Add(csvInput);

Logger konfigurieren

Um von MVC 6 Informationen über aufgerufene Operationen und interne Vorgänge zu erhalten, bedient sich der Entwickler des neuen durchgängigen Logger-Konzepts. Dazu spendiert er der Methode ConfigureServices der Klasse Startup einen zusätzlichen Parameter vom Typ ILoggerFactory und registriert bei dieser Factory einen so genannten LoggerProvider. Letzterer ist dafür verantwortlich, Logger bereitzustellen. Der im Lieferumfang von MVC 6 enthaltene ConsoleLoggerProvider stellt zum Beispiel Logger zur Verfügung, die Informationen auf der Konsole protokollieren. Um diese Informationen zu sehen, muss der Entwickler den Webserver auf der Konsole, wie weiter unten gezeigt, mittels Self Hosting starten.

Der ConsoleLoggerProvider findet sich in der Assembly Microsoft.Framework.Logging.Console. Referenziert der Entwickler auch den gleichnamigen Namensraum, erhält die LoggerFactory-Instanz eine Erweiterungsmethode AddConsole. Diese registriert den ConsoleLoggerProvider (Listing 5). Im Zuge dessen nimmt sie ein Loglevel zum Filtern von Lognachrichten entgegen. Sämtliche Nachrichten, deren Loglevel größer oder gleich des durch den Filter festgelegten Loglevel ist, werden protokolliert. Die Loglevel werden durch den Enum LogLevel beschrieben. Die nachfolgende Auflistung spiegelt die Werte dieses Enums aufsteigend geordnet wieder: Verbose, Information, Warning, Error, Critical.

public void ConfigureServices(IServiceCollection services, 
                                  ILoggerFactory  loggerFactory)
{
    loggerFactory.AddConsole(LogLevel.Information);
    [...]
}

Um auch eigene Informationen zu protokollieren, lässt sich der Entwickler über den Dependeny-Injection-Mechanismus von ASP.NET eine Instanz des Typs ILoggerFactory injizieren. Diese weist eine Methode Create zum Erzeugen eines Loggers auf. Create nimmt den Namen, den der neue Logger erhalten soll, entgegen. Viele Logging-Frameworks bieten die Möglichkeit, Nachrichten in Abhängigkeit dieses Namens zu filtern. Der einfache ConsoleLogger gehört zwar nicht dazu, allerdings nimmt er den Namen des Loggers als zusätzliche Information in die protokollierten Nachrichten auf.

Es hat sich eingebürgert, die Logger nach dem vollständigen Namen jener Klasse zu benennen, die die Nachrichten protokolliert. Um diese Aufgabe zu erleichtern, existiert eine Überladung von Create, die anstatt des Logger-Namens einen Typparameter entgegennimmt. Der Name des damit referenzierten Typs wird in diesem Fall vom Logger übernommen. Listing 6 veranschaulicht dies, indem es im Konstruktor einen Logger erzeugt. Die Methode GetAll nutzt diesen Logger, um eine Nachricht zu protokollieren. Das geschieht unter Nutzung der Erweiterungsmethode WriteInformation, die – wie der Name ausdrückt – eine Nachricht unter Verwendung des Loglevels Information protokolliert. Analog dazu existieren für die anderen Loglevel entsprechende Methoden.

public class FlugController : Controller
{
    private ILogger logger;

    public FlugController(ILoggerFactory loggerFactory)
    {
        logger = loggerFactory.Create();
    }

    public List GetAll()
    {
        logger.WriteInformation("FlugController.GetAll");

        [...]
    }
}

Neben dem ConsoleLogger wird die nächste Version von ASP.NET vNext auch Logger-Implementierungen beinhalten, die an Logging-Frameworks delegieren. Eines davon ist das populäre quelloffene Framework NLog. Darüber hinaus hat der Entwickler die Möglichkeit, eigene Logging-Implementierungen über eigene LoggerProvider bereitzustellen. Informationen dazu finden Sie hier.

Self Hosting

Neben dem Hosting in IIS bzw. IIS Express können ASP.NET-Anwendungen künftig auch in einem eigenen leichtgewichtigen Webserver gestartet werden. Hierbei ist auch von Self Hosting die Rede. Die einfachste Weise, dies zu bewerkstelligen, liegt im Einrichten eines Befehls über die Datei project.json:

„commands“: {
        „web „: „Microsoft.AspNet.Hosting –server Microsoft.AspNet.Server.WebListener –server.urls http://localhost:5000
    }
 
Eine Ausführung des gezeigten Befehls web führt dazu, dass die ausführbare Klasse Program im Paket Microsoft.AspNet.Hosting angestoßen wird. Die Parameter server und server.urls werden dabei als Kommandozeilenparameter übergeben. Ersterer gibt an, dass die Klasse Microsoft.AspNet.Server.WebListener zur Kommunikation via HTTP heranzuziehen ist. Letzterer gibt die Adresse bekannt, über die der Webserver erreichbar sein soll. Um diesen Befehl zur Ausführung zu bringen, wählt ihn der Entwickler beim Start der Anwendung in Visual Studio aus (Abb. 1). 
 
Abb. 1: Konfigurierten Befehl via Visual Studio 2015 ausführen

Alternativ dazu kann der Befehl auch über die Kommandozeile unter Verwendung des Dienstprogramms k zur Ausführung gebracht werden: k web

Informationen über die nötigen Schritte zur Installation von k finden sich hier.

Daneben hat der Entwickler auch die Möglichkeit, einen Self Host unter Verwendung eines Objektmodells aus einer .NET-Anwendung heraus zu starten. Beispiele hierzu finden sich hier und hier.

Fazit

Bei ASP.NET MVC 6 handelt es sich nicht nur um ein Framework zur Erstellung von Webanwendungen, sondern auch um das Serviceframework zur Bereitstellung von Web APIs mit der Microsoft-Plattform. In letzterer Rolle ist es nicht nur für Webentwickler interessant, sondern für sämtliche Entwickler, die die Aufgabe haben, Dienste über das Netzwerk bereitzustellen. Zu den Betrieben dieser Dienste muss nicht zwangsweise IIS zum Einsatz kommen, zumal ASP.NET künftig vollständig via Self Hosting genutzt werden kann.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -