Thomas Bandt

Über mich | Kontakt | Archiv

ASP.NET MVC - Controller und Views in "Areas" aufteilen

In der aktuellen Beta von ASP.NET MVC sieht das Standard-Projektlayout folgende Struktur vor:

Das ist absolut übersichtlich und ausreichend für kleinere Websites, aber schon dann, wenn man seine Seite in zwei logische Bereiche unterteilen will und sich einzelne Elemente wiederholen, sollte das Ganze weiter verschachtelt werden können. Beispiel:

Es gibt einen allgemein gültigen Bereich für Impressum usw. dazu noch ein Forum und einen Katalog. Alle drei Bereiche haben eine "Startseite". Im herkömmlichen Layout würde das Ganze dann so aussehen:

Die entsprechenden URLs dazu:

Nicht besonders schön, oder? Also sollte man es logisch aufteilen. Das Problem: im derzeitigen Stand von ASP.NET MVC ist das nicht vorgesehen, und da "Beta" bei Microsoft auch immer weitestgehend "Feature Complete" bedeutet, dürfte das Ganze auch trotz neuerlicher Bemühungen nicht mehr den Weg in die finale Version finden.

Trotzdem gibt es einen Weg, das auch heute schon selbst "hinzutricksen", wobei da gar nicht viel Aufwand notwendig wird. Das Layout sollte also wie folgt aussehen:

Die URLs dazu:

Nötig sind dafür eigentlich nur zwei kleinere Eingriffe:

1. Die Area muss in der URL mitgegeben werden

Hierfür ergänzen wir erstmal nur die Default-Route um den Parameter.

   1:  routes.MapRoute(
   2:      "Default",
   3:      "{area}/{controller}/{action}/{id}",
   4:      new { area = "Common", controller = "Home", action = "Index", id = "" }
   5:  );

2. Der Zugriff auf den richtigen Controller in der richtigen Area muss klappen

Das erreicht man durch eine eigene ControllerFactory:

   1:  public class AreaControllerFactory : DefaultControllerFactory
   2:  {
   3:      protected override Type GetControllerType(string controllerName)
   4:      {
   5:          object areaName;
   6:          if (RequestContext != null && RequestContext.RouteData.Values.
   7:              TryGetValue("area", out areaName))
   8:          {
   9:              string ns = string.Empty;
  10:              switch (areaName.ToString().Trim().ToLower())
  11:              {
  12:                  case "common":
  13:                      ns = "MvcAreas.App.Controllers.Common";
  14:                      break;
  15:                  case "catalog":
  16:                      ns = "MvcAreas.App.Controllers.Catalog";
  17:                      break;
  18:                  case "forum":
  19:                      ns = "MvcAreas.App.Controllers.Forum";
  20:                      break;
  21:              }
  22:              if (ns.Length > 0)
  23:                  return Type.GetType(ns + "." + controllerName + "Controller");
  24:          }
  25:          return base.GetControllerType(controllerName);
  26:      }
  27:  }

3. Die richtige View in der richtigen Area muss gefunden werden

Auch nicht besonders schwierig, da alle nötigen Informationen ja inzwischen bereitstehen. Nötig hierfür ist eine eigene ViewEngine.

   1:  public class AreaViewEngine : WebFormViewEngine
   2:  {
   3:      public override ViewEngineResult FindView(ControllerContext 
   4:          controllerContext, string viewName, string masterName)
   5:      {
   6:          string areaName = controllerContext.RouteData.
   7:              GetRequiredString("area");
   8:          string controllerName = controllerContext.RouteData.
   9:              GetRequiredString("controller");
  10:          string path = string.Format("~/App/Views/{0}/{1}/{2}.aspx", 
  11:              areaName, controllerName, viewName);
  12:          return new ViewEngineResult(CreateView(controllerContext, 
  13:              path, null), this);
  14:      }
  15:  }

4. Registrierung von ControllerFactory und ViewEngine

   1:  protected void Application_Start()
   2:  {
   3:      RegisterRoutes(RouteTable.Routes);
   4:      ControllerBuilder.Current.
   5:          SetControllerFactory(new AreaControllerFactory());
   6:      ViewEngines.Engines.Add(new AreaViewEngine());
   7:  }

That's it. Soweit ich das nun auf die Schnelle beurteilen konnte, funktioniert innerhalb einer Area alles, also auch die Verwendung der Html-Helper wie ActionLink usw. - was natürlich nicht funktioniert ist das "Area-übergreifende" Setzen von dynamischen Links - wie auch, ASP.NET MVC weiß von den Areas ja erst oder nur beim routen der Anfragen, nicht aber beim Erstellen der Links und Rendern der Seiten. Hier muss man sich einstweilen mit festverdrahteten Links begnügen, was meistens auch ausreichen sein sollte. Irgendwann wird uns dann hoffentlich Microsoft erlösen.

Nachfolgend findet sich noch eine Beispielanwendung.

Downloads

Kommentare

  1. Thomas Höhler schrieb am Donnerstag, 6. November 2008 09:09:00 Uhr:

    Siehe Phil's Blog zu dem Thema: http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx

    Thomas
  2. Thomas goes .NET schrieb am Freitag, 7. November 2008 23:25:00 Uhr:

    Ergänzend zu meinem Post "ASP.NET MVC - Controller und Views in Areas aufteilen" seien hier noch zwei Ressourcen zum Thema genannt, die sich nachher aufgetan haben:

    Grouping Controllers with ASP.NET MVC
    App Areas in ASP.NET MVC, take 2

    ...


« Zurück  |  Weiter »