Dieser Artikel wurde maschinell übersetzt.

Topaktuell

Dynamische Aktionsfilter in ASP.NET MVC

Dino Esposito

Dino EspositoLetzten Monat wurde die Rolle und die Implementierung der Aktion Filter in einer ASP.NET MVC-Anwendung beschrieben. Um ein bisschen zu überprüfen: Aktion-Filter sind Attribute, die Sie Controller-Methoden und Klassen mit den Zweck der Sie einige optionalen Aktionen ausführen. Beispielsweise können Sie komprimieren-Attribut zu schreiben und es transparent über einen komprimierten Gzip-Stream-Methode generierte Antworten zu filtern. Der größte Vorteil darin, dass code die Komprimierung bleiben in eine unterschiedliche und problemlos wiederverwendbare-Klasse, die leistet einen Beitrag für die Zuständigkeiten der Methode so gering wie möglich halten isoliert.

Attribute sind jedoch eine statische Sache. Um Ihre Flexibilität inhärente Vorteile nutzen zu können, müssen Sie eine zusätzliche kompilieren Schritt durchgehen. Ändern die zusätzliche Aspekte der die Controllerklasse ist einfach, aber es geht auf Kosten der Quellcode ändern. Dies ist im Allgemeinen keinen großen Nachteil. Die meisten der Codeverwaltung arbeiten Durchläufe durch physische Änderungen am Quellcode vorgenommen. Je mehr können Sie effektiv und kein Risiko Einführung von Regression, desto besser diese Änderungen vornehmen.

Websites (hauptsächlich Webportale) stark veränderliche Inhalte und Funktionen und überaus anpassbaren Software als Dienstanwendungen (SaaS) ist eine Lösung, die Sie vom Berühren des Quellcodes speichert mehr als Willkommen. Daher ist die Frage, ist alles, was Sie tun können, um Aktion Filter dynamisch zu laden? Wie im weiteren Verlauf dieses Artikels gezeigt wird, lautet die Antwort "Ja" lautet.

Einblick in ASP.NET MVC

Das ASP.NET MVC Framework stellt eine Reihe von Schnittstellen und überschreibbare Methoden, denen fast jeden Aspekt der angepasst werden kann. Kurz gesagt, ist die gesamte Auflistung der Aktion Filter für eine Controller-Methode geladen und in einer Liste im Arbeitsspeicher gespeichert. Als Entwickler sind Sie berechtigt, den Zugriff auf und überprüfen diese Liste. Mit einigen Mehraufwand können ändern Sie die Liste der Aktion Filter und sogar dynamisch zu füllen.

Let’s näher an, wie dies funktioniert mit einer Übersicht über die Schritte, die vom Framework zur Ausführung einer Aktion ausgeführt. Dabei erfüllen Sie die zentrale Komponente, die für dynamische Filter, deren Bearbeitung ermöglicht: die aufrufende Aktion.

Die aufrufende Aktion ist verantwortlich für die Ausführung der Aktion Methoden für eine Controllerklasse. Die aufrufende Aktion implementiert den internen Lebenszyklus jeder ASP.NET MVC-Anforderung. Die aufrufende ist eine Instanz einer Klasse, die IActionInvoker-Schnittstelle implementiert. Jeder Controllerklasse verfügt über ein eigenes aufrufende Objekt auf der ganzen Welt über eine einfache Get/Set-Eigenschaft mit dem Namen ActionInvoker verfügbar gemacht. Die Eigenschaft ist für den Basistyp von System.Web.MVC.Controller wie folgt definiert:

public IActionInvoker ActionInvoker {

  get {

    if (this._actionInvoker == null) {

      this._actionInvoker = this.CreateActionInvoker();

    }

    return this._actionInvoker;

  }

  set {

    this._actionInvoker = value;

  }

}

Die Methode CreateActionInvoker ist eine geschützte überschreibbare Methode des Controller-Typs. Hier ist die Implementierung:

protected virtual IActionInvoker CreateActionInvoker() {

  // Creates an instance of the built-in invoker

  return new ControllerActionInvoker();

}

Es stellt sich heraus, dass die aufrufende Aktion werden für alle Domänencontroller geändert werden kann. Da die aufrufende ziemlich einer frühen Phase des Lebenszyklus der Anforderung beteiligt ist, benötigen Sie jedoch wahrscheinlich eine Controller Factory eigene aufrufende für die standardmäßige aufrufende austauschen. Ein Framework für die Umkehrung des Steuerelements (IoC) wie Unity gekoppelt, würde dieser Ansatz die aufrufende Geschäftslogik direkt von den Einstellungen der IoC-Container (offline) ändern können.

Als Alternative können Sie eine benutzerdefinierte Controller-Basisklasse für Ihre eigene Anwendung definieren und überschreiben, damit Sie genau das aufrufende Objekt zurückgeben, das Sie müssen, die CreateActionInvoker-Methode. Dies ist der Ansatz, den ASP.NET MVC Framework, einsetzt um die asynchrone Ausführung der Controller Aktionen zu unterstützen.

Die aufrufende Aktion ist die Schnittstelle IActionInvoker Zentrum der relativ einfach, ist wie es nur eine Methode verfügbar macht:

public interface IActionInvoker {

  bool InvokeAction(

    ControllerContext controllerContext, 

    String actionName);

}

Lassen Sie einen Blick auf die Standard-Aktion aufrufende, let’s Überprüfen Sie die wichtigsten Aufgaben, für die eine Aktion aufrufende zuständig ist. Die aufrufende ruft zunächst Informationen über die Domänencontroller hinter der Anforderung und den speziellen Vorgang durchführen. Informationen über ein ad-hoc-Deskriptor-Objekt stammen. Die Sicherheitsbeschreibung enthält den Namen und den Typ des Domänencontrollers sowie die Liste der Attribute und Aktionen. Aus Gründen der Leistungsfähigkeit baut die aufrufende einen eigenen Cache der Aktion und Controller-Deskriptoren.

Es ist interessant, einen kurzen Blick auf den Prototyp der ControllerDescriptor-Klasse werden in Abbildung 1 . Die Klasse stellt nur die Basisklasse für alle tatsächlichen Deskriptor.

Abbildung 1 Die ControllerDescriptor-Klasse

public abstract class ControllerDescriptor : 

  ICustomAttributeProvider {



  // Properties

  public virtual string ControllerName { get; }

  public abstract Type ControllerType { get; }



  // Method

  public abstract ActionDescriptor[] GetCanonicalActions();

  public virtual object[] GetCustomAttributes(bool inherit);

  public abstract ActionDescriptor FindAction(

    ControllerContext controllerContext, 

    string actionName);

  public virtual object[] GetCustomAttributes(

    Type attributeType, bool inherit);

  public virtual bool IsDefined(

    Type attributeType, bool inherit);

}

Das ASP.NET MVC Framework setzt zwei konkrete Deskriptor-Klassen, die die Microsoft .NET Framework Reflektion intern stark zu verwenden. Eine heißt ReflectedControllerDescriptor;die andere ist nur für asynchrone Controller verwendet und ReflectedAsyncControllerDescriptor heißt.

Ich fällt kaum ein realistisches Szenario, müssen Sie zum Erstellen Ihrer eigenen Deskriptor. Allerdings für diejenigen, die neugierig sind, let’s betrachten wie es gemacht wird.

Genommen Sie an, eine Sicherheitsbeschreibung abgeleiteten Klasse erstellen und überschreiben die Methode GetCanonicalActions, lesen die Liste der unterstützten Aktionen aus einer Konfigurationsdatei oder in einer Datenbanktabelle. Auf diese Weise können Sie Methoden der gültige Aktion aus der Liste basierend auf einige konfigurierbare Inhalt entfernen. Sie müssen dafür benötigen Sie jedoch in Ihren eigenen aufrufende Aktion führen und seine Methode GetControllerDescriptor entsprechend schreiben, um eine Instanz der benutzerdefinierten Deskriptor zurückzugeben:

protected virtual ControllerDescriptor 

  GetControllerDescriptor(

  ControllerContext controllerContext);

Abrufen von Informationen über die Controller und Aktion-Methode ist nur der erste Schritt durch die aufrufende Aktion erreicht. Als Nächstes und interessanter für die Zwecke dieses Artikels die aufrufende Aktion ruft die Liste der Filter der Aktion für die Methode, die verarbeitet werden. Darüber hinaus die aufrufende Aktion überprüft die Autorisierung-Berechtigungen des Benutzers, die Anforderung vor potenziell gefährlichen bereitgestellten Daten überprüft und ruft dann die Methode haben.

Ruft die Liste der Action-Filter

Obwohl die aufrufende Aktion mit der Schnittstelle IActionInvoker identifiziert wird, verwendet ASP.NET MVC Framework die Dienste der integrierten ControllerActionInvoker-Klasse. Diese Klasse unterstützt viele weitere Methoden und Funktionen, einschließlich der oben genannten Deskriptoren und Filter für die Aktion.

Die ControllerActionInvoker-Klasse bietet zwei wichtigsten Punkte zum Bearbeiten von Filtern für die Aktion von Seiten des Benutzers. Eine ist die GetFilters-Methode:

protected virtual ActionExecutedContext 

  InvokeActionMethodWithFilters(

  ControllerContext controllerContext, 

  IList<IActionFilter> filters, 

  ActionDescriptor actionDescriptor, 

  IDictionary<string, object> parameters);

Der andere ist der InvokeActionMethodWithFilters-Methode:

protected virtual FilterInfo GetFilters(

  ControllerContext controllerContext, 

  ActionDescriptor actionDescriptor)

Beide Methoden sind geschützt und virtual markiert, wie Sie sehen können.

Die aufrufende aufruft GetFilters, wenn die Liste der Filter für eine bestimmte Aktion definiert werden muss. Wie Sie denken möglicherweise, geschieht dies sehr früh im Lebenszyklus einer Anforderung und vor jedem Aufruf der Methode InvokeActionMethodWithFilters.

Beachten Sie, dass nach dem Aufruf von GetFilters die aufrufende verfügbaren die gesamte Liste der Filter für jede mögliche Kategorie enthält, z. B. Ausnahmefilter, Ergebnis filtern, Autorisierungsfilter und, natürlich Aktion filtert. Betrachten Sie die folgenden Controllerklasse:

[HandleError]

public class HomeController : Controller {

  public ActionResult About() {

    return View();

  }

}

Die gesamte Klasse wird mit dem HandleError-Attribut wird von einem Ausnahmefilter ergänzt und keine andere Attribute wird angezeigt.

Jetzt let’s Hinzufügen einer benutzerdefinierten aufrufende, überschreiben Sie die Methode GetFilters und setzen Sie einen Haltepunkt auf die letzte Zeile des Codes, wie folgt:

protected override FilterInfo GetFilters(

  ControllerContext controllerContext, 

  ActionDescriptor actionDescriptor) {



  var filters = base.GetFilters(

    controllerContext, actionDescriptor);

  return filters;

}

Abbildung 2 zeigt den eigentlichen Inhalt der Variablen Filter.

image: Intercepting the Content of the Filters Collection

Abbildung 2 Abfangen des Inhalts der Filters-Auflistung

Die Klasse FilterInfo – eine öffentliche Klasse in System.Web.Mvc—offers bestimmte Auflistungen von Filtern für jede Kategorie:

public class FilterInfo {

  public IList<IActionFilter> ActionFilters { get; }

  public IList<IAuthorizationFilter> AuthorizationFilters { get; }

  public IList<IExceptionFilter> ExceptionFilters { get; }

  public IList<IResultFilter> ResultFilters { get; }

  ...
}

Wie in Abbildung 2 Anzahl der zuvor gezeigten trivial-Klasse Sie Filter für eine Aktion, einen Autorisierungsfilter, ein Ergebnis Filter und zwei Ausnahmefilter. Wer definiert die Aktion, Ergebnis und Autorisierung-Filter? Die Controllerklasse selbst ist ein Aktionsfilters. Die Controller-Basisklasse implementiert tatsächlich alle verknüpften Filter-Schnittstellen:

public abstract class Controller : 

    ControllerBase, IDisposable,

    IActionFilter, IAuthorizationFilter, 

    IExceptionFilter, IResultFilter {

    ...
}

Die Basisimplementierung der GetFilters widerspiegelt, Attribute aus der Domänencontroller-Klasse mithilfe der Reflektion in .NET Framework. In der Implementierung der Methode GetFilters können Sie beliebig viele Filter wie von jeder Art von Speicherort lesen soll, hinzufügen. Sie benötigen lediglich ein Stück Code wie diesem:

protected override FilterInfo GetFilters(

  ControllerContext controllerContext, 

  ActionDescriptor actionDescriptor) {



  var filters = base.GetFilters(

    controllerContext, actionDescriptor);



  // Load additional filters

  var extraFilters = ReadFiltersFromConfig();

  filters.Add(extraFilters);



  return filters;

}

Dieser Ansatz bietet die größte Flexibilität und kann für jedes Ziel erreicht werden soll, oder mit den gewünschten Typ von Filter, die Sie hinzufügen möchten.

Aufrufen einer Aktion

InvokeActionMethodWithFilters wird während des Prozesses aufgerufen, die die Leistung der Aktionsmethode akzeptiert. In diesem Fall erhält die Methode die Liste der Aktion Filter berücksichtigt werden. Sie sind jedoch weiterhin zulässig, zusätzliche Filter zu diesem Zeitpunkt hinzufügen. Abbildung 3 zeigt eine Beispielimplementierung InvokeActionMethodWithFilters, die einen Aktionsfilter für das Komprimieren der Ausgabe dynamisch hinzugefügt. Der Code in Abbildung 3 überprüft zuerst, ob die aufgerufene Methode eine und anschließend instanziiert und fügt einen neuen Filter. Es versteht sich von selbst die Filter, die in irgendeiner Weise zu laden, die z. B. beim Lesen aus einer Konfigurationsdatei, einer Datenbank oder andere geeignete bestimmen. Beim Überschreiben der Methode InvokeActionMethodWithFilters Sie lediglich die ausgeführten Methode zu überprüfen, fügen Sie zusätzliche Aktionen Filtern und die Basismethode aufrufen, damit die aufrufende wie gewohnt fortgesetzt werden kann. Zum Abrufen von Informationen über die Methode ausgeführt wird, greifen Sie auf den Controller-Kontext und die Beschreibung der Aktion.

Abbildung 3 Hinzufügen ein Filters Aktion vor die Aktion ausführen von

protected override ActionExecutedContext 

  InvokeActionMethodWithFilters(

  ControllerContext controllerContext, 

  IList<IActionFilter> filters, 

  ActionDescriptor actionDescriptor, 

  IDictionary<String, Object> parameters) {



  if (

    actionDescriptor.ControllerDescriptor.ControllerName == "Home" 

    && actionDescriptor.ActionName == "About") {



    var compressFilter = new CompressAttribute();

    filters.Add(compressFilter);

  }



  return base.InvokeActionMethodWithFilters(

    controllerContext, 

    filters, actionDescriptor, parameters);

}

Daher gibt es zwei mögliche Ansätze zum dynamischen Hinzufügen von Filtern zum Controller-Instanz: GetFilters überschreiben und InvokeActionMethodWithFilters überschreiben.Jedoch gibt es ein Unterschied?

Die Aktion Lifecycle

Durchgehen GetFilters oder InvokeActionMethodWithFilters ist weitgehend identisch.Einige Unterschiede sind vorhanden, obwohl dies kein großes Problem ist.Um den Unterschied zu verstehen, let’s erfahren Sie mehr über die Schritte die Standard-Aktion aufrufende bei der Ausführung einer Aktion-Methode ist.Abbildung 4 enthält eine Zusammenfassung des Lebenszyklus.

image: The Lifecycle of an Action Method

Abbildung 4 für eine Aktion-Methode der Lifecycle

Nach dem Abrufen der Sicherheitsbeschreibungen, die aufrufende Ruft die Liste der Filter und trägt in der Phase der Autorisierung.Zu diesem Zeitpunkt behandelt keine Autorisierungsfilter, die Sie registriert haben, können die aufrufende.Wenn die Autorisierung fehlschlägt, wird Aktion Ergebnis vollständig ignoriert alle Filter ausgeführt.

Danach überprüft die aufrufende, ob die Anforderung erfordert die Überprüfung der gesendeten Daten und wechselt dann zum Ausführen der Aktionsmethode Laden aller gegenwärtig registrierten Filter.

Letztendlich Wenn Sie alle Autorisierungsfilter dynamisch hinzufügen möchten funktioniert Sie nur Fall durch die GetFilters-Methode.Wenn Ihr Ziel nur Aktion Filter, Ergebnis filtern oder Ausnahmefilter hinzugefügt wird, führt dann einfach mit beiden Methoden zum selben Ergebnis.

Dynamische Filter

Dynamisches Laden von Filtern ist eine optionale Funktion, die vor allem den Zweck von Anwendungen mit einer sehr allgemeinen Funktion Volatilität dient.Ein Filter speziell eine Aktion filtern, ermöglicht Aspekt-orientierten Funktionen in einer ASP.NET MVC-Controller-Klasse als es Entwicklern aktivieren und Verhalten auf deklarative Weise deaktivieren kann.

Wenn Sie den Quellcode der Controllerklasse schreiben, können Sie auswählen, um den Klassen- oder Methodenebene Aktion Attribute hinzuzufügen.Wie Sie Informationen so organisieren, dass es deaktiviert ist, welche Filter anwenden, um die Methoden sind möglicherweise nicht offensichtlich, beim Lesen von Informationen zu Aktionen Filtern aus einer externen Datenquelle.In einem Szenario mit Datenbank können Sie eine Tabelle erstellen, wo Sie als Schlüssel-Methode und den Domänencontroller verwenden.In einem Konfigurationsszenario mit müssen Sie wahrscheinlich einen benutzerdefinierten Konfigurationsabschnitt zu arbeiten, die nur die Informationen übermittelt werden müssen.In jedem Fall ist das ASP.NET MVC Framework flexibel genug ist, können Sie entscheiden, welche Filter auf einer pro-Methode und sogar auf Basis pro Aufruf angewendet werden.

Dino Esposito* ist der Autor des “ Programming ASP.NET MVC ” von Microsoft Press (2010).Esposito lebt in Italien und ist ein weltweit gefragter Referent bei Branchenveranstaltungen.Weblogs.asp.net/despos-können Sie seinen Blog beitreten.*

Dank an den folgenden technischen Experten für die Überprüfung der in diesem Artikel: Scott Hanselman