Mit ASP.NET MVC und ASP.NET Web API existierten jahrelang zwei sehr ähnliche Frameworks nebeneinander. Um Mehrgleisigkeiten zu vermeiden, integriert das Produktteam die Möglichkeiten von Web API künftig in MVC 6.
Um diesen Umstand aus der Welt zu schaffen, wird ASP.NET Web API in ASP.NET MVC 6 aufgehen. Dieser Artikel zeigt, wie MVC 6 künftig für die Entwicklung von Web-APIs genutzt werden kann. Am einfachsten lassen sich die hier gezeigten Beispiele mit der aktuellen CTP von Visual Studio 2015 [1] nachstellen.
Wie beim Vorgänger MVC 5 und seiner Schwestertechnologie ASP.NET Web API üblich, stellen Controller serverseitige Routinen zur Verfügung. Die einfachste und häufigste Möglichkeit, Controller bereitzustellen, besteht darin, Controller von der Basisklasse zu erben. Standardmäßig stellt MVC sämtliche Methoden der Controller-Klassen, die sich in diesem Kontext auch Action-Methoden nennen, über HTTP zur Verfügung. Dazu kommt ein als Routing bezeichneter Mechanismus zum Einsatz, der URLs auf Action-Methoden abbildet. Wird die Projektvorlage von Visual Studio genutzt, herrscht standardmäßig eine Route vor, die sich wie folgt gestaltet:
{controller}/{action}/{id?}
Der Platzhalter {controller} steht dabei für den Namen des Controllers. In der Regel ist dies der Name der Controller-Klasse ohne Endung Controller. Der Name des durch die Klasse FlugController beschriebenen Controllers ist somit Flug. Den Namen der aufzurufenden Action-Methode spiegelt der Platzhalter {action} wider. Auf Groß-/und Kleinschreibung legt MVC an dieser Stelle keinen Wert. Der optionale Platzhalter {id?} steht für einen Wert, der an einen Parameter mit dem Namen id zu übergeben ist. Das Fragezeichen am Ende des Parameternamens drückt aus, dass die Angabe dieses Werts bzw. das Vorhandensein eines Parameters id optional ist.
Ein Aufruf des URLs Flug/GetById/17 führt somit dazu, dass MVC die Methode GetById des Controllers FlugController aufruft und den Wert 17 an dessen Parameter id übergibt. Da es sich bei {id} um einen optionalen Platzhalter handelt und MVC sämtliche URL-Parameter standardmäßig auf gleichnamige Parameter der adressierten Action-Methode abbildet, könnte sich dieser Aufruf auch wie folgt gestalten: Flug/GetById?id=17.
Ein Beispiel für solch einen Controller findet sich in Listing 1. Zur Vereinfachung verwaltet er Flüge in einer statischen Liste, die sein Konstruktor initialisiert, sofern sie noch nicht vorhanden ist. Darüber hinaus weist er einige Action-Methoden auf, die MVC 6 anhand der besprochenen Route auf URLs abbildet. Diese Methoden rufen Flüge nach bestimmten Kriterien ab oder geben die Möglichkeit, sie zu bearbeiten. Liefern Sie ein Objekt retour, wird dieses von einem Mechanismus, der sich Output Formatter nennt, in ein Übertragungsformat serialisiert. Das Ergebnis der Serialisierung wird von MVC 6 zum Aufrufer übertragen. Im Lieferumfang befinden sich Output Formatter für die Datenformate JSON und XML. Weitere Output Formatter kann der Entwickler bereitstellen. Standardmäßig kommt JSON zum Einsatz. Der Aufrufer kann jedoch unter Verwendung der HTTP-Kopfzeile Accept andere Formate anfordern.
Wie bereits angemerkt, bildet MVC standardmäßig sämtliche URL-Parameter auf gleichnamige Parameter der Action-Methoden ab. Möchte der Entwickler jedoch angeben, dass sich ein Parameter aus den übersendeten Nutzdaten ergibt, annotiert er diesen mit dem Attribut FromBody. Ein Beispiel dafür ist der Parameter flug der Action-Methode PostFlug in Listing 1. Das Parsen der Nutzdaten übernimmt ein so genannter Input Formatter. Anhand des Datenformats, das der Aufrufer über die Kopfzeile Content-Type angibt, wählt MVC einen passenden Input Formatter, der sich um das Deserialisieren der Nutzdaten in einen Typ des Parameters kümmert. Analog zu den Output Formattern befinden sich auch Input Formatter für JSON und XML im Lieferumfang.
Listing 1
public class FlugController : Controller
{
private static List<Flug> fluege;
public FlugController()
{
if (fluege == null)
{
fluege = new List<Flug>();
fluege.Add(new Flug { [...] });
[...]
}
}
public Flug GetById(int id)
{
return fluege.FirstOrDefault(f => f.FlugId == id);
}
public Flug GetByFlugNumberAndDate(string flugNummer, DateTime datum)
{
return fluege.FirstOrDefault(
f => f.FlugNr == flugNummer && f.Datum.Date == datum.Date);
}
public List<Flug> GetAll()
{
return fluege;
}
public List<Flug> GetByRoute(string abflugOrt, string zielOrt)
{
return fluege.Where(f => f.AbflugOrt == abflugOrt
&& f.ZielOrt == zielOrt).ToList();
}
public void PostFlug([FromBody]Flug flug)
{
flug.FlugId = fluege.Max(f => f.FlugId) + 1;
fluege.Add(flug);
}
}
Im Gegensatz zu ASP.NET Web API geben die Namen der Action-Methode keine Auskunft über die HTTP-Methoden (Verben), für die sie gedacht sind. Vielmehr kann der Aufrufer standardmäßig alle Action-Methoden unter Verwendung jeder HTTP-Methode anstoßen. Attribute wie HttpGet, HttpPost, HttpPatch, HttpPut oder HttpDelete bieten jedoch die Möglichkeit, Action-Methoden auf bestimmte HTTP-Methoden zu beschränken. Um anzugeben, dass eine Action-Methode nur bei POST-Aufrufen in Erwägung zu ziehen ist, annotiert der Entwickler diese beispielsweise mit HttpPost:
[HttpPost]
public void PostFlug([FromBody]Flug flug) { ... }
Alternativ besteht die Möglichkeit, die zu akzeptierenden HTTP-Methoden als Parameter an das Attribut AcceptVerbs zu übergeben. Dies ist nützlich, um HTTP-Methoden, für die keine eigenen Attribute zur...