3. Controller, Aktionen, Routing
Betrachten wir die Architektur einer ASP.NET-MVC-Anwendung:
![]() |
In diesem Kapitel untersuchen wir den Prozess, der die Anfrage [1] an den Controller und die Aktion [2a] weiterleitet, die sie verarbeiten wird – ein Mechanismus, der als Routing bezeichnet wird. Außerdem stellen wir die verschiedenen Antworten [3] vor, die eine Aktion an den Browser zurückgeben kann. Dabei kann es sich um etwas anderes als eine Ansicht V [4b] handeln.
3.1. Der Aufbau eines ASP.NET MVC-Projekts
Erstellen wir unser erstes ASP.NET MVC-Projekt mit Visual Studio Express 2012. Wir fügen es [1] der im vorherigen Kapitel verwendeten Lösung hinzu:
![]() |
![]() |
- in [2] den Namen des neuen Projekts;
- in [3, 4] wählen wir ein einfaches ASP.NET MVC-Projekt. Diese Vorlage stellt uns eine leere Webanwendung zur Verfügung, die dennoch alle Ressourcen (DLLs, JavaScript-Bibliotheken usw.) enthält, die für den Einstieg erforderlich sind.
Das resultierende Projekt wird in [5] angezeigt. Wir machen es [6] zum Startprojekt „ “ der Lösung:
![]() |
Beachten Sie die folgenden Punkte in [5]:
- Die Projektarchitektur spiegelt das MVC-Modell wider:
- C-Controller werden im Ordner [Controllers] abgelegt,
- M-Datenmodelle werden im Ordner [Models] abgelegt,
- V-Ansichten werden im Ordner [Views] abgelegt,
![]() |
- In [1] ist die Datei [Site.css] die Standard-CSS-Datei der Anwendung;
- in [2] stehen eine Reihe von JavaScript-Bibliotheken zur Verfügung;
- in [3] gibt es drei spezifische Ansichten: _ViewStart, _Layout und Error.
Die Datei [_ViewStart] sieht wie folgt aus:
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
- Zeile 1: Das Zeichen @ markiert den Beginn eines C#-Blocks innerhalb der Ansicht. Tatsächlich kann C#-Code in eine Ansicht eingebunden werden;
- Zeile 2: definiert eine Layout-Variable, die die übergeordnete Ansicht für alle Ansichten festlegt. Sie entspricht der Master-Seite im klassischen ASP.NET-Framework.
Die Datei [ _Layout ] sieht wie folgt aus:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
@RenderBody()
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
</body>
</html>
Wenn eine Ansicht aus dem Ordner [Views] gerendert wird, wird ihr Hauptteil durch Zeile 11 oben gerendert. Das bedeutet, dass die Ansicht die Tags <html>, <head> und <body> nicht enthalten muss. Diese werden von der obigen Datei bereitgestellt. Im Moment ist diese Datei noch recht kryptisch. Vereinfachen wir sie:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Tutoriel ASP.NET MVC</title>
</head>
<body>
<h2>Tutoriel ASP.NET MVC</h2>
@RenderBody()
</body>
</html>
- Zeile 6: der für alle Ansichten gemeinsame Titel;
- Zeile 9: die für alle Ansichten gemeinsame Kopfzeile;
- Zeile 10: der für die angezeigte Ansicht spezifische Inhalt.

- [Web.config] ist die Konfigurationsdatei der Webanwendung. Sie ist komplex. Sie müssen sie anpassen, wenn Sie das [Spring.net]-Framework in einer mehrschichtigen Architektur verwenden.
- [Global.asax] enthält den Code, der beim Start der Anwendung ausgeführt wird. Im Allgemeinen nutzt dieser Code die verschiedenen Konfigurationsdateien der Anwendung, einschließlich [Web.config].
3.2. Standard-URL-Routing
Der Code in [Global.asax] lautet derzeit wie folgt:
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace Exemple_01
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
}
}
}
- Zeile 6: der Klassen-Namespace. Er leitet sich direkt vom Projektnamen ab und ist in den Projekteigenschaften aufgeführt:

![]() |
Wir legen [1] als Standard-Namespace fest. Dieser wird dann standardmäßig für alle Klassen verwendet, die im Projekt erstellt werden.
Kehren wir zum Code in [Global.asax] zurück:
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace Exemple_01
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
}
}
}
- Zeile 9: Die Klasse [MvcApplication] leitet sich von der Klasse [HttpApplication] ab. Der Name [MvcApplication] kann geändert werden;
- Zeile 11: Die Methode [Application_Start] ist die Methode, die beim Start der Webanwendung ausgeführt wird. Sie wird nur einmal ausgeführt. Hier wird die Anwendung initialisiert.
Der Code für [Application_Start] lautet derzeit wie folgt:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Im Moment müssen Sie diesen Code noch nicht vollständig verstehen. Die Zeilen 5–8 definieren die von der Webanwendung akzeptierten Routen. Kehren wir zur Architektur einer ASP.NET MVC-Anwendung zurück:
![]() |
Wir haben erklärt, dass der [Front Controller] eine URL an die Aktion weiterleiten muss, die für deren Verarbeitung zuständig ist. Eine Route wird verwendet, um ein URL-Muster mit einer Aktion zu verknüpfen. Diese Routen werden im Ordner [App_Start] des Projekts durch die Klassen [WebApiConfig, FilterConfig, RouteConfig, BundleConfig] definiert:

Im Moment interessiert uns nur die Klasse [RouteConfig]:
using System.Web.Mvc;
using System.Web.Routing;
namespace Exemple_01
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
Die Zeilen 12–16 definieren das Format der von der Anwendung akzeptierten URLs. Dies wird als Route bezeichnet. Es kann mehrere mögliche Routen geben (= mehrere mögliche URL-Muster). Sie unterscheiden sich voneinander durch ihren Namen (Zeile 13). Das Format der URLs der Route wird in Zeile 14 definiert. Hier besteht die URL aus drei Komponenten:
- {controller}: der Name einer von [Controller] abgeleiteten Klasse. Diese wird im Ordner [Controllers] des Projekts gesucht. Gemäß Konvention ist bei der URL /X/Y/Z die Klasse XController für die Verarbeitung dieser URL zuständig. Das Suffix Controller wird dem Namen des in der URL enthaltenen Controllers hinzugefügt;
- {action}: der Name einer Methode in dem oben angegebenen Controller. Diese Methode empfängt die mit der URL übermittelten Parameter und verarbeitet sie. Diese Methode kann verschiedene Ergebnisse zurückgeben:
- void: Die Aktion erstellt die Antwort an den Browser des Clients selbst
- String: Die Aktion gibt eine Zeichenkette an den Client zurück;
- ViewResult: gibt eine Ansicht an den Client zurück;
- PartialViewResult: gibt eine partielle Ansicht zurück;
- EmptyResult: Eine leere Antwort wird an den Client gesendet;
- RedirectResult: weist den Client an, zu einer URL umzuleiten
- RedirectToRouteResult: wie oben, jedoch wird die URL aus den Routen der Anwendung gebildet;
- JsonResult: sendet eine JSON-Antwort
- JavaScriptResult: gibt JavaScript-Code an den Client zurück;
- ContentResult: gibt einen HTML-Stream an den Client zurück, ohne eine Ansicht zu durchlaufen;
- FileContentResult: gibt eine Datei an den Client zurück;
- FileStreamResult: wie oben, jedoch über eine andere Methode;
- FilePathResult: ...
- {id}: Ein Parameter, der an die Aktion übergeben wird. Damit dies funktioniert, muss die Aktion über einen Parameter namens id verfügen.
Zeile 15 definiert Standardwerte, wenn die URL nicht das erwartete Format /{controller}/{action}/{id} aufweist. Sie gibt auch an, dass der Parameter {id} in der URL optional ist. Hier ist eine Liste unvollständiger URLs und der mit den Standardwerten vervollständigten URLs:
Ursprüngliche URL | Vervollständigte URL |
/ | /Home/Index |
/Do | /Do/Index |
/Do/Etwas | /Tun/Etwas |
/Tun/Etwas/4 | /Tun/Etwas/4 |
/Do/Something/x/y/z | Nicht zugewiesene URL |
3.3. Erstellen eines Controllers und einer ersten Aktion
Erstellen wir einen ersten Controller:

![]() |
- Geben Sie in [1] den Namen des Controllers mit dem Suffix [Controller] ein;
- Erstellen Sie in [2] einen leeren MVC-Controller;
- in [3] wurde er erstellt.
Der Code für [FirstController] lautet wie folgt:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Exemple_01.Controllers
{
public class FirstController : Controller
{
//
// GET: /First/
public ActionResult Index()
{
return View();
}
}
}
- Zeile 7: Ein Standard-Namespace wurde generiert;
- Zeile 9: Die Klasse [FirstController] leitet sich von der Klasse [System.Web.Mvc.Controller] ab;
- Zeilen 14–17: Eine [Index]-Aktion wurde standardmäßig generiert. Sie ist öffentlich. Dies ist wichtig; andernfalls wird sie nicht gefunden. Sie gibt einen [ActionResult]-Typ zurück, bei dem es sich um eine abstrakte Klasse handelt, von der die meisten Ergebnisse abgeleitet sind, die typischerweise von einer Aktion zurückgegeben werden. Dies ist ein „Catch-All“-Typ, der durch Ersetzen durch den tatsächlichen Namen des zurückgegebenen Typs spezifiziert werden kann;
- Zeile 16: Die Methode führt keine Aktion aus. Sie gibt lediglich eine Ansicht zurück, d. h. einen [ViewResult]-Typ. Der Name der Ansicht ist nicht angegeben. In diesem Fall durchsucht das Framework den Ordner [Views/First] nach einer Ansicht mit dem gleichen Namen wie die Aktion, in diesem Fall [Index.cshtml].
Erstellen wir nun die Ansicht [Index.cshtml]:
![]() |
- in [1] klicken Sie mit der rechten Maustaste in den Aktionscode und wählen die Option [Ansicht hinzufügen];
- In [2] schlägt der Assistent eine Ansicht mit dem gleichen Namen wie die Aktion vor. Das ist genau das, was wir hier wollen;
- in [3] wird standardmäßig die Verwendung der Master-Seite [_Layout.cshtml] vorgeschlagen;
- in [4] erstellt der Assistent nach der Bestätigung die Ansicht in einem Unterordner des Ordners [Views], der nach dem Controller (First) benannt ist.
Der für die Ansicht [Index] generierte Code lautet wie folgt:
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
- Zeilen 1–3: C#-Code, der eine Variable definiert;
- Zeile 5: ein HTML-Tag.
Ersetzen Sie den gesamten bisherigen Code durch Folgendes:
<strong>Vue [Index]...</strong>
Zusammenfassend:
- Wir haben einen C#-Controller namens [First];
- wir haben eine Aktion namens [Index], die die Anzeige einer Ansicht namens [Index] anfordert;
- wir haben die Ansicht V [Index].
Wir können die Aktion [Index] auf zwei Arten aufrufen:
- /First/Index;
- /First, da [Index] auch die Standardaktion in den Routen ist.
Starten wir die Anwendung (STRG-F5). Wir erhalten die folgende Seite:

In [1] lautete die angeforderte URL http://localhost:49302. Es fehlt der Pfad. Wir wissen, dass unser Router URLs in der Form /{controller}/{action}/{id} erwartet. Da diese Elemente fehlen, werden die Standardwerte verwendet. Die URL lautet nun http://localhost:49302/Home/Index. Der [Home]-Controller existiert nicht. Daher wird die URL abgelehnt.
Versuchen wir nun die URL http://localhost:49302/First/Index, indem wir sie direkt in den Browser eingeben:
![]() |
Die obige Seite wurde durch die Aktion [Index] des Controllers [First] generiert. Die durch diese Aktion generierte Seite ist die Ansicht [Index], deren Code wie folgt lautete:
<strong>Vue [Index]...</strong>
Sie generiert Teil [1]. Teil [2] stammt hingegen aus der Master-Seite [_Layout], die wir zuvor definiert haben:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Tutoriel ASP.NET MVC</title>
</head>
<body>
<h2>Tutoriel ASP.NET MVC</h2>
@RenderBody()
</body>
</html>
Zeile 9 generierte Abschnitt [2] der Seite. Die Ansicht [Index] erscheint jedoch erst in Zeile 10.
Wenn wir uns den Quellcode der empfangenen Seite ansehen, können wir feststellen, dass die [Index]-Seite tatsächlich (in Zeile 10 unten) in die [Layout]-Seite eingebunden ist:
Probieren wir nun die URL [/First] aus:

Die URL [/First] war unvollständig. Sie wurde mit den Standardwerten der Route vervollständigt und lautete nun [/First/Index]. Wir erhalten daher das gleiche Ergebnis wie zuvor.
3.4. Aktion mit einem Ergebnis vom Typ [ContentResult] – 1
Erstellen wir eine neue Aktion im [First]-Controller:
using System.Text;
using System.Web.Mvc;
namespace Exemple_01.Controllers
{
public class FirstController : Controller
{
// Index
public ViewResult Index()
{
return View();
}
// Action01
public ContentResult Action01()
{
return Content("<h1>Action [Action01]</h1>", "text/plain", Encoding.UTF8);
}
}
}
Die neue Aktion ist in den Zeilen 14–18 definiert. Sie gibt einfach eine Zeichenkette mithilfe der [Content]-Methode (Zeile 16) der [Controller]-Klasse (Zeile 6) zurück. Die Parameter der Methode sind:
- die Antwortzeichenfolge;
- eine Angabe zum Typ des gesendeten Textes: „text/plain“, „text/html“, „text/xml“ usw. Diese Angabe wird als MIME-Typ (http://fr.wikipedia.org/wiki/Type_MIME) bezeichnet;
- der dritte Parameter gibt den für den Text verwendeten Kodierungstyp an.
Anstatt den abstrakten Typ [ActionResult] zu verwenden, geben unsere Methoden den tatsächlichen Rückgabetyp an (Zeilen 9 und 14).
Rufen wir die URL [/First/Action01] auf. Wir erhalten die folgende Seite:

Sehen wir uns den Quellcode der empfangenen Seite an:
Der Browser hat nur den von der Aktion gesendeten Text empfangen und sonst nichts. Dieser Modus ist nützlich, wenn Sie Rohdaten vom Webserver ohne das umgebende HTML-Markup anfordern möchten. Beachten Sie oben, dass der Browser den HTML-Tag <h1> nicht interpretiert hat. Um zu verstehen, warum das so ist, schauen wir uns den HTTP-Datenaustausch in Chrome an:
Der Browser hat die folgenden HTTP-Header gesendet:
Der Server antwortete mit den folgenden Headern:
- Zeile 3: Legt den Dokumenttyp fest. Wir sehen die in der Methode [Action01] festgelegten Attribute. Da dem Browser mitgeteilt wurde, dass das Dokument vom Typ „text/plain“ und nicht „text/html“ war, hat er das im empfangenen Dokument enthaltene <h1>-Tag nicht interpretiert.
3.5. Aktion mit einem Ergebnis vom Typ [ContentResult] – 2
Betrachten wir nun die folgende dritte Aktion:
using System.Text;
using System.Web.Mvc;
namespace Exemple_01.Controllers
{
public class FirstController : Controller
{
...
// Action02
public ContentResult Action02()
{
string data = "<action><name>Action02</name><description>renvoie un texte XML</description></action>";
return Content(data, "text/xml", Encoding.UTF8);
}
}
}
- Zeile 12: Wir definieren einen XML-Text;
- Zeile 13: Wir senden ihn an den Browser und geben dabei an, dass es sich um XML mit dem MIME-Typ „text/xml“ handelt.
Im Browser wird folgende Seite angezeigt:

Sehen wir uns die HTTP-Antwort des Servers in Chrome an:
- Zeile 3: gibt den Dokumenttyp an. Die in der Methode [Action02] festgelegten Attribute sind hier enthalten;
- Zeile 12: Die Größe des vom Server gesendeten Dokuments in Byte.
Das vom Server gesendete Dokument ist dieses (Chrome-Screenshot):

3.6. Aktion mit einem Ergebnis vom Typ [JsonResult]
Fügen wir die folgende Aktion zum [First]-Controller hinzu:
// Action03
public JsonResult Action03()
{
dynamic personne = new ExpandoObject();
personne.nom = "someone";
personne.age = 20;
return Json(personne,JsonRequestBehavior.AllowGet);
}
- Zeile 4: eine Variable vom Typ „dynamic“. Zur Laufzeit können einer solchen Variable beliebig Eigenschaften hinzugefügt werden. Die Eigenschaft wird gleichzeitig mit ihrer Initialisierung erstellt;
- Zeilen 5–6: Wir initialisieren zwei Eigenschaften, name und age;
- Zeile 7: Gibt die JSON-Darstellung (JavaScript Object Notation) des Objekts zurück. JSON ermöglicht es, ein Objekt in eine Zeichenfolge zu serialisieren und umgekehrt eine Zeichenfolge in ein Objekt zu deserialisieren. Es ist eine Alternative zur XML-Serialisierung/Deserialisierung;
- Zeile 2: Die Aktion gibt einen Typ [JsonResult] zurück. Dieser Typ kann nur für eine POST-Anfrage zurückgegeben werden. Wenn Sie ihn für eine GET-Methode zurückgeben möchten, müssen Sie den zweiten Parameter des Konstruktors der Json-Klasse (Zeile 7) auf JsonRequestBehavior.AllowGet setzen.
Wenn Sie die URL [/First/Action03] aufrufen, zeigt der Browser Folgendes an:

Die HTTP-Antwort des Servers lautet wie folgt:
- Zeile 3: gibt an, dass das gesendete Dokument JSON ist;
- Zeile 10: Das gesendete Dokument ist 58 Byte groß. Es lautet wie folgt:
Das dynamische Element [person] wird von JSON als Array von Dictionaries betrachtet, wobei jedes Dictionary:
- einem Feld der Variablen [person] entspricht;
- zwei Schlüssel hat: „Key“ und „Value“. „Key“ hat den Feldnamen als zugehörigen Wert, und „Value“ hat den Wert des Feldes.
3.7. Aktion mit einem [string]-Ergebnis
Fügen wir die folgende Aktion zum [First]-Controller hinzu:
// Action04
public string Action04()
{
return "<h3>Contrôleur=First, Action=Action04</h3>";
}
Wenn wir die URL [/First/Action04] in Chrome aufrufen, erhalten wir folgende Antwort:

Wir sehen, dass das <h3>-Tag interpretiert wurde. Schauen wir uns die HTTP-Antwort des Servers an:
und das folgende Dokument:
Wie in Zeile 3 zu sehen ist, hat der Server angegeben, dass er Text im HTML-Format sendet. Aus diesem Grund hat der Browser das <h3>-Tag interpretiert. Wenn Sie reinen Text senden möchten, ist es daher vorzuziehen, ein [ContentResult] anstelle eines [string] zurückzugeben. Mit [ContentResult] können wir den MIME-Typ „text/plain“ angeben, um zu signalisieren, dass wir unformatierten Text senden, den der Browser nicht zu interpretieren versucht.
3.8. Aktion mit einem [EmptyResult]-Typ
Betrachten Sie die folgende neue Aktion:
// Action05
public EmptyResult Action05()
{
return new EmptyResult();
}
Die Aktion gibt einfach einen Typ [EmptyResult] zurück. In diesem Fall sendet der Server eine leere Antwort an den Client, wie in der HTTP-Antwort zu sehen ist:
- Zeile 9: Der Server teilt seinem Client mit, dass er ein leeres Dokument sendet.
3.9. Aktion mit einem Ergebnis vom Typ [RedirectResult] – 1
Betrachten Sie die folgende neue Aktion:
// Action06
public RedirectResult Action06()
{
return new RedirectResult("/First/Action05");
}
Die Aktion gibt einen Typ [RedirectResult] zurück. Dieser Typ ermöglicht es, eine Umleitungsanforderung an den Client an die im Konstruktor angegebene URL (Zeile 4) zu senden. Der Client sendet daraufhin eine neue GET-Anforderung an [/First/Action05]. Der Client stellt somit insgesamt zwei Anforderungen.
Der Browser zeigt das Ergebnis der zweiten Anfrage an:

Sehen wir uns die HTTP-Antwort des Servers in Chrome an:

Oben sehen wir die beiden Anfragen des Browsers. Sehen wir uns die erste Anfrage [Action06] an. Die HTTP-Antwort des Servers lautet wie folgt:
- Zeile 1: Der Server antwortete mit dem Statuscode 302 Found. Zuvor lautete der Code 200 OK, was bedeutet, dass das angeforderte Dokument gefunden wurde. Der Code 302 zeigt an, dass eine Weiterleitung angefordert wird. Die Weiterleitungs-URL wird in Zeile 4 angegeben. Diese stimmt mit der Weiterleitungs-URL überein, die wir im Aktionscode angegeben haben;
- Zeile 11: Der Server gibt an, dass er mit seiner HTTP-Antwort ein text/html-Dokument (Zeile 3) mit einer Größe von 132 Bytes (Zeile 11) sendet. Wenn wir die Antwort auf die [Action06]-Anfrage in Chrome untersuchen, ist sie erwartungsgemäß leer. Es gibt wahrscheinlich eine Erklärung dafür, aber ich weiß nicht, welche.
Aufgrund der Weiterleitung sendet der Browser eine neue GET-Anfrage an die in Zeile 4 oben angegebene URL, wie in Chrome in Zeile 1 unten zu sehen ist:
3.10. Aktion mit einem Ergebnis vom Typ [RedirectResult] – 2
Betrachten Sie die folgende neue Aktion:
// Action07
public RedirectResult Action07()
{
return new RedirectResult("/First/Action05",true);
}
In Zeile 4 haben wir dem Konstruktor von [RedirectResult] einen zweiten Parameter hinzugefügt. Es handelt sich um einen booleschen Wert, dessen Standardwert „false“ ist. Wenn er auf „true“ gesetzt wird, ändert er die an den Client gesendete HTTP-Antwort. Sie lautet dann:
Somit lautet der an den Client gesendete Antwortcode nun 301 Moved Permanently. Die Weiterleitung erfolgt wie zuvor, wir geben jedoch an, dass diese Weiterleitung dauerhaft ist. Dadurch können Suchmaschinen die alte URL in ihren Ergebnissen durch die neue ersetzen.
3.11. Aktion mit einem Ergebnis vom Typ [RedirectToRouteResult]
Betrachten Sie die folgende neue Aktion:
// Action08
public RedirectToRouteResult Action08()
{
return new RedirectToRouteResult("Default",new RouteValueDictionary(new {controller="First",action="Action05"}));
}
- Zeile 2: Die Aktion gibt einen Typ [RedirectToRouteResult] zurück. Dieser Typ ermöglicht es, einen Client nicht wie zuvor über eine Zeichenfolge, sondern über eine Route zu einer bestimmten URL umzuleiten.
Routen werden in [App_Start/RouteConfig] definiert. Derzeit gibt es nur eine:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
- In Zeile 4 wird der Client angewiesen, zur Route mit dem Namen [Default] umzuleiten, wobei die Variable „controller“ auf „First“ und die Variable „action“ auf „Action05“ gesetzt ist. Das Routing-System generiert daraufhin die Umleitungs-URL /First/Action05. Dies wird in der HTTP-Antwort des Servers angezeigt:
- Zeile 1: die Weiterleitung;
- Zeile 4: die vom URL-Routing-System generierte Weiterleitungs-URL.
3.12. Aktion mit dem Rückgabetyp [void]
Betrachten Sie die folgende neue Aktion:
// Action09
public void Action09()
{
string nom = Request.QueryString["nom"] ?? "inconnu";
Response.AddHeader("Content-Type", "text/plain");
Response.Write(string.Format("<h3>Action09</h3>nom={0}", nom));
}
- Zeile 2: Die Aktion gibt kein Ergebnis zurück. Sie schreibt direkt in den an den Client gesendeten Antwortstrom;
- Zeile 4: Wir rufen einen potenziellen Parameter namens [name] aus der Anfrage ab. Dieser ist über die [Request]-Eigenschaft der [Controller]-Klasse zugänglich, von der der [First]-Controller erbt. Der Parameter [name], der in der Form [/First/Action09?name=something] übergeben wird, ist in Request.QueryString["name"] verfügbar. Die Syntax von Zeile 4 entspricht:
- Zeile 5: Die an den Client gesendete Antwort ist über die Eigenschaft [Response] der Klasse [Controller] zugänglich, von der der Controller [First] erbt;
- Zeile 5: Wir setzen den HTTP-Header [Content-Type], der die Art des Dokuments angibt, das der Server an den Client senden wird. Hier bedeutet „text/plain“, dass es sich um reinen Text handelt, der vom Browser nicht interpretiert werden soll;
- Zeile 6: Wir schreiben eine Zeichenfolge in den Antworttext. Wir haben HTML-Tags eingefügt, die vom Browser nicht interpretiert werden sollten, da der Browser zuvor den HTTP-Header [Content-Type: text/plain] erhalten hat. Genau das wollen wir überprüfen.
Kompilieren wir das Projekt und rufen wir die URL [/First/Action09?name=someone ][1] und anschließend die URL [/First/Action09 ] [2] auf:
![]() |
Sehen wir uns nun die HTTP-Antwort des Servers in Chrome an:
- Zeile 3: Wir sehen den HTTP-Header, den wir selbst im Aktionscode gesetzt haben.
3.13. Ein zweiter Controller
Erstellen wir einen zweiten Controller im Projekt. Wir folgen dabei der in Abschnitt 3.1 auf Seite 36 beschriebenen Methode. Wir nennen ihn [Second].

Der generierte Code sieht wie folgt aus:
namespace Exemple_01.Controllers
{
public class SecondController : Controller
{
//
// GET: /Second/
public ActionResult Index()
{
return View();
}
}
}
Ändern wir es wie folgt:
using System.Text;
using System.Web.Mvc;
namespace Exemple_01.Controllers
{
public class SecondController : Controller
{
// /Second/Action01
public ContentResult Action01()
{
return Content("Contrôleur=Second, Action=Action01", "text/plain", Encoding.UTF8);
}
}
}
Rufen wir nun die URL [/Second/Action01] über einen Browser auf. Wir erhalten folgende Antwort:

Diese URL wurde mit einer HTTP-GET-Anfrage aufgerufen, wie aus den HTTP-Protokollen für die Anfrage in Chrome hervorgeht:
Die URL kann auch über eine HTTP-POST-Anfrage aufgerufen werden. Um dies zu veranschaulichen, verwenden wir erneut die App [Advanced Rest Client]:
![]() |
- Starten Sie in [1] die Anwendung (auf der Registerkarte [Applications] eines neuen Chrome-Tabs);
- Wählen Sie in [2] die Option [Request] aus;
- Geben Sie in [3] die angeforderte URL an;
- Geben Sie in [4] an, dass die URL mit einer POST-Anfrage abgerufen werden soll;
Wir aktivieren die Chrome-Protokolle (STRG-I), um die HTTP-Antwort des Servers anzuzeigen. Wenn wir auf [Senden] klicken, um die vorherige Anfrage auszuführen, sieht der HTTP-Datenaustausch wie folgt aus:
Der Browser sendet die folgende Anfrage:
- Zeile 1: Die URL wird tatsächlich mit einem POST-Request angefordert;
- Zeile 4: Die Größe der gesendeten Elemente in Byte. Hier gibt es keine.
Die HTTP-Antwort des Servers lautet wie folgt:
- Zeile 3: Der Server sendet ein unformatiertes (reines) Textdokument;
- Zeile 12: 148 Zeichen.
Das gesendete Dokument lautet wie folgt:

Wir erhalten dasselbe Dokument wie bei der GET-Anfrage.
3.14. Nach einem Attribut gefilterte Aktion
Erstellen wir die folgende neue Aktion:
// /Second/Action02
[HttpPost]
public ContentResult Action02()
{
return Content("Contrôleur=Second, Action=Action02", "text/plain", Encoding.UTF8);
}
Die Aktion [Action02] ähnelt der Aktion [Action01], legt jedoch fest, dass sie nur über eine HTTP-POST-Anfrage zugänglich ist (Zeile 2). Es können weitere Attribute verwendet werden:
HttpGet | bedient nur die GET-Anfrage |
HttpHead | bedient nur die HEAD-Anfrage |
HttpOptions | unterstützt nur den OPTIONS-Befehl |
HttpPut | unterstützt nur den PUT-Befehl |
HttpDelete | wird nur für den DELETE-Befehl verwendet |
Rufen wir die URL [/Second/Action02] direkt im Browser auf. Sie wird dann über einen GET-Befehl aufgerufen. Der Browser zeigt daraufhin die folgende Antwort an:

Die HTTP-Antwort des Servers lautete wie folgt:
- Zeile 1: Der HTTP-Code 404 Nicht gefunden zeigt an, dass der Server das angeforderte Dokument nicht finden konnte. Hier konnte die Aktion [Action02] die GET-Anfrage nicht verarbeiten, da sie nur POST-Anfragen verarbeitet;
- Zeile 3: Die Größe des zurückgegebenen Dokuments. Dies ist die Seite, die vom Browser angezeigt wurde:

3.15. Abrufen von Elementen aus einer Route
In den beiden oben beschriebenen Aktionen haben wir etwa Folgendes geschrieben:
public ContentResult Action02()
{
return Content("Contrôleur=Second, Action=Action02", "text/plain", Encoding.UTF8);
}
Die Namen des Controllers und der Aktion wurden fest in den Code geschrieben. Wenn wir diese Namen ändern, ist der Code nicht mehr korrekt. Wir können wie folgt auf den Controller und die Aktion zugreifen:
// /Second/Action03
public ContentResult Action03()
{
string texte = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
return Content(texte, "text/plain", Encoding.UTF8);
}
Die in [App_Start/RouteConfig] definierte Route lautet wie folgt:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Zeile 3: Die drei Routenelemente können mit RouteData.Values["element"] abgerufen werden, wobei element einer der Werte [controller, action, id] ist.
Rufen wir die URL [http://localhost:49302/Second/Action03] auf:

Wir haben sowohl den Namen des Controllers als auch den Namen der Aktion erfolgreich abgerufen.











