Homepage-Webhilfe Event-Banner

Steuerung

Steuerung-Icon Steuerungen (oder auch Controller genannt) sind der Grundbaustein für MVC-Anwendungen und stehen nach dem Erhalt einer HTTP-Anfrage an erster Stelle. Der für die URL zugehörige Controller sowie die für die URL zugehörige Anwendung wird mittels eines Routing-Verfahrens vom MVC-Framework ermittelt, welches wir im nächsten Abschnitt genauer erklären werden. Die Steuerung repräsentiert die sogenannte Anwendungslogik. Jede öffentliche Funktion (Zugriffsmodifizierer public) stellt eine sogenannte Aktionsmethode dar. Eine Aktionsmethode kann in der Regel von außen indirekt über die angegebene URL aufgerufen werden. Als Rückgabetyp verfügen Aktionsmethoden üblicherweise über die Klasse ActionResult (bzw. über eine von der Klasse ActionResult abgeleitete Klasse). Aktionsmethoden können dabei Übergabeparameter besitzen. Dies können zum einen individuelle Parameter (festgelegt durch Routen) und zum anderen ein Datenmodell sein (bei POST-Aktionen). Darauf werden wir jedoch später noch genauer eingehen.

Prinzipiell sind Steuerungen nichts anderes als C#-Klassen. Jedoch sind diese von der Klasse Controller (Namensraum System.Web.Mvc) abgeleitet und müssen am Ende des Klassennamens über den Suffix Controller verfügen. Der andere Teil des Klassennamens stellt den eigentlichen Controller-Namen dar. Der Name der Aktionsmethode entspricht, sofern dieser nicht über den ActionName-Selektor (dazu später mehr) geändert wurde, auch dem Namen, welcher in der URL zum Aufruf der Aktion angegeben wird.


Wie bereits erklärt, werden die URLs mittels eines Routing-Verfahrens zu allererst einer Anwendung, anschließend einer Steuerung und letztendlich einer Aktionsmethode zugeordnet. Dabei gilt für die URL innerhalb einer MVC-Anwendung folgender Aufbau: {controller}/{action}/{id}. Ein Aufruf von Home/Index/1 wird also dem Controller Home und der Aktionsmethode Index() zugewiesen. Dieser kann (sofern gewünscht) ein Parameter übergeben werden, welcher im obigen Beispiel dem Wert 1 entsprechen würde. Ein Aufruf von Kunden/Editierung/4781 würde die Aktionsmethode Editierung() des Controllers Kunden (Datei KundenController.cs) aufrufen und der Methode den Wert 4781 übergeben. Dies ist wohl ein typisches Beispiel für ASP.NET MVC, wie die URL für die Editierung eines Kunden in einem Firmen-Portal aussehen könnte.

Möchten wir diesen Standardaufbau ändern oder erweitern, so müssen wir weitere Routen registrieren oder vorhandene anpassen. Eine Route ist beim Erstellen eines MVC-Projekts bereits vorhanden. Diese, welche wir oben bereits erklärt haben, wird auch als Standard-Route (engl. default route) bezeichnet. Routen werden auf Anwendungsebene definiert und sind standardmäßig in der Funktion RegisterRoutes() der Datei App_Start/RouteConfig.cs definiert. Der Funktion wird als Parameter ein Objekt der Klasse RouteCollection übergeben. In diesem werden die Routen registriert.

Innerhalb der Funktion RegisterRoutes() wird nun die Funktion MapRoute() aufgerufen, mit welcher URL-Routen festgelegt werden können. Als Parameter werden der Routenname, das URL-Muster und die Standard-Werte übergeben. Der Routenname kann zur Identifizierung der Route und für Routenlinks verwendet werden. Der Routenname wird in der Routing-Tabelle als Index verwendet, weshalb der Name eindeutig sein muss. Das URL-Muster für Routen besteht aus Platzhaltern, Schrägstrichen (zur Trennung) sowie bei Bedarf Konstanten. Zwischen Platzhaltern ist es zwingend erforderlich, dass ein Schrägstrich vorhanden ist. Platzhalter werden in geschweifte Klammern notiert. Die einfachsten Beispiele sind die in der Standard-Route enthaltenen Platzhalter {controller} und {action}. {controller} verweist dabei direkt auf den Namen der Steuerung und {action} auf den Namen der Aktionsmethode. Weitere Platzhalter können nach Belieben definiert werden. Der Wert solcher Platzhalter werden ebenfalls über die eingegebene URL spezifiziert und der Aktionsmethode als Parameter übergeben. Die Zuordnung des Platzhalterwerts zu dem Parameter wird über den Namen getroffen, d. h. der Name des Platzhalters muss auch dem Parameternamen der Aktionsmethode entsprechen. Über den dritten Parameter der Funktion MapRoute() werden die Standardwerte der Platzhalter festgelegt. Dafür wird in der Regel ein anonymes Objekt erzeugt und dieses der Funktion übergeben. Das (anonyme) Objekt enthält Eigenschaften, die die Standardwerte der Platzhalter repräsentieren. Hierfür muss der Name der Eigenschaft dem Namen des Platzhalters entsprechen. Die Standardwerte (engl. default values) werden immer dann benötigt, wenn einer der Werte nicht angegeben wurde. Dies ist auch der Grund, warum beim Aufruf des Root-Verzeichnisses der Anwendung standardmäßig die Steuerung Home und die Aktionsmethode Index aufgerufen wird. Existiert z. B. ein weiterer Controller mit dem Namen Produkt, so wird beim Aufruf von ~/Produkt die Aktionsmethode Index() des Produkt-Controllers aufgerufen. Möchten Sie einen Platzhalter nicht mit einem Standard-Wert belegen, sondern diesen als optional markieren, so können Sie der Eigenschaft des Objekts für Standardwerte die Konstante UrlParameter.Optional zuweisen. Wird der Platzhalter in der URL nicht angegeben, so wird der Aktionsmethode als Wert null übergeben. Hierbei ist darauf zu achten, dass der Datentyp den Wert null unterstützt. Die Funktion IgnoreRoute() erlaubt es mit Hilfe eines URL-Musters, bestimmte Routen zu ignorieren, um somit z. B. einen Controller „zu deaktivieren“.

Im unteren Beispiel gibt es zwei Controller: Home und Info. Beide Controller verfügen über mehrere Aktionsmethoden. Die Aktionsmethode MeineID() des Controllers Home verwendet den Platzhalter bzw. Parameter id und gibt dessen Wert aus. In der Routenkonfiguration wurde eine Route hinzugefügt, mit welcher die Aktionsmethode auch über die URL ~/ID aufgerufen werden kann. Die folgende Tabelle zeigt die verschiedenen Aufrufmöglichkeiten für die Webanwendung und die dazugehörigen Controller sowie Aktionsmethoden:

URL Controller Aktionsmethode id-Parameter
~/ Home Index() null
~/Home Home Index() null
~/Home/Index Home Index() null
~/Home/DatumUhrzeit Home DatumUhrzeit() null
~/Home/MeineID Home MeineID() null
~/Home/MeineID/123 Home MeineID() 123
~/Info/Anfrage Info Anfrage() null
~/Info/Antwort Info Antwort() null
~/ID Home MeineID() null
~/ID/123 Home MeineID() 123

Übrigens: Ein Aufruf von ~/Info ist ungültig (bzw. führt zu einem 404 HTTP-Status-Fehler), da der Info-Controller über keine Index()-Aktionsmethode verfügt.

Hier der Quellcode der zwei Controller sowie der Routenkonfiguration:

HomeController.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HWhBsp.Routing.Controllers
{
    public class HomeController : Controller
    {
        public string Index()
        {
            return "Hallo Welt!";
        }

        public string DatumUhrzeit()
        {
            return "Aktuelles Datum und Uhrzeit: " + DateTime.Now.ToString();
        }

        public string MeineID(string id)
        {
            return "ID: " + ((id == null) ? "-" : id);
        }
    }
}

InfoController.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HWhBsp.Routing.Controllers
{
    public class InfoController : Controller
    {
        public string Anfrage()
        {
            return "User-Agent: " + Request.UserAgent;
        }

        public string Antwort()
        {
            return "Zeichenkodierung: " + Response.Charset;
        }
    }
}

RouteConfig.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace HWhBsp.Routing
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "ID-Ausgabe",
                url: "ID/{id}",
                defaults: new { controller = "Home", action = "MeineID", id = UrlParameter.Optional }
            ); 
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}
VorschauDownload

Wichtig: Die Routen werden von oben nach unten abgearbeitet. Daher muss die Standard-Route immer als letztes notiert werden.

Übrigens: Bei der Angabe von Parametern kann zusätzlich zum Wert auch noch der Name angegeben werden (name: wert). Dies wird gemacht, sodass der Programmierer direkt erkennen kann, welcher Wert zu welchem Parameter gehört (ohne die Parameter-Reihenfolge zu kennen). Diese „Beschriftung“ kann jedoch ohne weiteres weggelassen werden. Es gibt zudem einige Funktionen, welche „Benannte Argumente“ verwenden. Bei diesen muss der Parametername angegeben werden, da darüber die Zuordnung stattfindet. Für Sie mag diese Art der Parameterangabe evtl. neu sein, jedoch werden Sie sehen, dass diese beiden Verfahren oft bei ASP.NET MVC verwendet werden.

Stellen wir uns ein praxisnahes Szenario vor: Sie möchten auf Grund von Suchmaschinenoptimierung der URL zusätzlich zum Namen des Controllers und der Aktionsmethode ein Sprachkürzel hinzufügen. So soll es z. B. an Stelle der URL ~/Produkte/Liste die URLs ~/DE/Produkte/Liste und ~/EN/Produkte/Liste geben. Das URL-Muster könnte in einem solchen Fall z. B. so aussehen: {lang}/{controller}/{action}/{id}. Der Parameter lang wird dabei den Aktionsmethoden übergeben, wodurch dieser den Inhalt der jeweiligen Seite laden kann. Hier zwei Beispielcodeausschnitte:

public string Index(string lang)
{
    return "Ihre Sprache ist: " + lang;
}
routes.MapRoute(
    name: "Default",
    url: "{lang}/{controller}/{action}/{id}",
    defaults: new { lang = "DE", controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Wichtig: Parameter am Anfang oder in der Mitte einer URL müssen angegeben werden. Im obigen Beispiel kann der Parameter lang also nicht weggelassen werden. Grundsätzlich können Parameter also immer nur in umgekehrter Reihenfolge und somit vom Ende zum Anfang weggelassen werden.


Aktionsmethoden können unterschiedliche Rückgabetypen haben. Bisher haben wir der Einfachheit halber den Rückgabetyp string verwendet. Im Regelfall wird jedoch der Rückgabetyp ActionResult verwendet. Die Klasse ActionResult ist eine abstrakte Klasse, d. h. von dieser kann kein Objekt erzeugt werden. Jedoch gibt es einige Klassen, welche von der Klasse ActionResult abgeleitet sind. Trotzdem kann als Rückgabetyp stets ActionResult angegeben werden. Dies ermöglicht z. B. das Zurückgeben von einem Objekt der Klasse RedirectResult oder ContentResult innerhalb der gleichen Aktionsmethode. Um ein Objekt solcher Klassen zu erzeugen, können oft Hilfsfunktionen eingesetzt werden. Die folgende Tabelle zeigt eine Auflistung der wichtigsten Klassen, welche von ActionResult abgeleitet sind, sowie der Hilfsfunktionen und einer Beschreibung:

Klasse Hilfsfunktion Beschreibung
ContentResult Content() Gibt einen Inhalt (ggf. mit einem angegebenen Inhaltstyp) zurück.
FileResult File() Gibt den Inhalt der angegebenen Datei (ggf. mit dem angegebenen Inhaltstyp) zurück.
HttpNotFoundResult - Gibt einen 404 HTTP-Status-Fehler bzw. eine Umleitung zur dazugehörigen Fehlerseite zurück.
HttpStatusCodeResult - Gibt einen beliebigen HTTP-Status-Fehler bzw. eine Umleitung zur dazugehörigen Fehlerseite zurück.
HttpUnauthorizedResult - Gibt einen 403 HTTP-Status-Fehler bzw. eine Umleitung zur dazugehörigen Fehlerseite zurück.
RedirectResult Redirect() Gibt eine Umleitung an Hand einer URL zurück.
RedirectToRouteResult RedirectToAction() Gibt eine Umleitung an Hand eines Controllers und einer Aktion zurück.
RedirectToRoute() Gibt eine Umleitung an Hand einer Route (Angabe aller Platzhalter möglich) zurück.
ViewResult View() Gibt eine Ansicht zurück (dazu später mehr).

Im Folgenden sehen Sie ein Beispiel mit mehreren Aktionsmethoden. Zur klaren Darstellung wurde als Rückgabetyp explizit die jeweils verwendete Klasse angegeben und nicht, wie es üblich ist, die Klasse ActionResult.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HWhBsp.Aktionen.Controllers
{
    public class HomeController : Controller
    {
        public string Index()
        {
            return "Hallo Welt!";
        }

        public RedirectResult UmleitungStartseite()
        {
            return Redirect("~/");
        }

        public RedirectToRouteResult UmleitungRoute()
        {
            return RedirectToAction("InhaltHTML");
        }

        public ContentResult InhaltHTML()
        {
            return Content("<b>Hallo</b> Welt!", "text/html");
        }

        public ContentResult InhaltXML()
        {
            return Content("<a>\r\n  <b>123</b>\r\n  <b>456</b>\r\n</a>", "text/xml");
        }

        public HttpStatusCodeResult ServerFehler()
        {
            return new HttpStatusCodeResult(500);
        }

        public HttpUnauthorizedResult AuthentifizierungsFehler()
        {
            return new HttpUnauthorizedResult();
        }

        public HttpNotFoundResult NichtGefundenFehler()
        {
            return new HttpNotFoundResult();
        }

        public FileResult Datei()
        {
            return File("~/Controllers/HomeController.cs", "text/plain");
        }
    }
}
VorschauDownload

Filter erlauben das Anwenden einer bestimmten Logik auf eine Aktion. Diese Logik wird vor (lat. pre) oder nach (lat. post) der Ausführung der Aktionsmethode ausgeführt. Bei Filtern handelt es sich um Attribut-Klassen, d. h. der Attribut-Name der Klasse wird innerhalb von eckigen Klammern oberhalb der Funktion oder der Klasse angegeben. Da das Thema Filter und vor allem das Erstellen von benutzerdefinierten Filtern komplexer ist und es eher für einfachere Anwendungen nicht benötigt wird, werden wir uns hier lediglich mit dem Filter OutputCache beschäftigen. Das Attribut OutputCache ermöglicht das Festlegen des Cache-Verhaltens für die jeweilige Aktion. Mit der Eigenschaft Duration können Sie bestimmen, wie lange (angegeben in Sekunden) die Aktion gecacht werden darf. Im unteren Beispiel wird die Aktion Index() für 5 Sekunden gecacht. Dieses Verhalten ist im Beispiel auf Grund der Datum- und Uhrzeitausgabe gut ersichtlich.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HWhBsp.Filter.Controllers
{
    public class HomeController : Controller
    {
        [OutputCache(Duration=5)]
        public string Index()
        {
            return DateTime.Now.ToString();
        }
    }
}
VorschauDownload

Selektoren dienen dazu, Aktionsmethoden anzupassen, um somit das Verhalten bei Anfragen zu steuern. Selektoren unterstützen dabei also das Routing-Verfahren. In ASP.NET MVC gibt es drei Selektoren: ActionName, NonAction und ActionVerbs. ActionName und NonAction werden direkt als Attribute oberhalb der Funktion notiert. Mit ActionName können Sie den Namen der Aktionsmethode ändern. Der Aktionsname wird im Konstruktor übergeben. Durch dieses Attribut ändert sich jedoch nicht der Name der Funktion, sondern lediglich der Zugriffsname, welcher in der URL zum Aufruf der Aktion verwendet wird. Haben wir also eine Aktionsmethode mit dem Namen GetDatumUndUhrzeit(), welcher wir nun den Namen DatumUhrzeit zuweisen, so heißt die Funktion weiterhin GetDatumUndUhrzeit(). Ein Zugriff mittels einer URL kann jedoch nur noch mit dem Aktionsnamen DatumUhrzeit erfolgen. GetDatumUndUhrzeit kann dann nicht mehr als Zugriffsname in der URL verwendet werden. Mit dem Attribut NonAction können Sie eine Funktion markieren, dass diese nicht als Aktion über die URL aufgerufen werden kann. Dieses Attribut benötigen Sie immer dann, wenn eine öffentliche Funktion nicht für den HTTP-Zugriff bestimmt ist. ActionVerbs sind spezielle Selektoren, welche Aktionen auf bestimmte HTTP-Methoden begrenzen. Die jeweilig anzugebenden Attribute setzen sich aus Http und dem Namen der HTTP-Methode (in Camel-Case-Schreibweise) zusammen (z. B. HttpGet und HttpPost). Hier nun ein Beispiel zum Thema Selektoren:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HWhBsp.Selektoren.Controllers
{
    public class HomeController : Controller
    {
        [HttpGet]
        public string Index()
        {
            return "<form action=\"" + Url.Content("~/Home/FormularVerarbeitung/") + "\" method=\"post\"><input type=\"submit\" value=\"Formular per POST senden\" /></form>";
        }

        [HttpPost]
        public string FormularVerarbeitung()
        {
            return "<a href=\"" + Url.Content("~/") + "\">Seite per GET anzeigen</a>";
        }

        [ActionName("DatumUhrzeit")]
        public string GetDatumUndUhrzeit()
        {
            return GetDatum() + " " + GetUhrzeit();
        }

        [NonAction]
        public string GetDatum()
        {
            return DateTime.Now.ToShortDateString();
        }

        [NonAction]
        public string GetUhrzeit()
        {
            return DateTime.Now.ToShortTimeString();
        }
    }
}
VorschauDownload
Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen OK