2013-05-10 16 views
12

Ich habe eine Multi-Tenant-Ansicht-Engine ähnlich wie das umgesetzt, was hier beschrieben wird:Handhabung Layout-Eigenschaften mit benutzerdefinierten Razor Ansicht Motor

die mich Ansicht, die die Suchpositionen lassen außer Kraft setzen, wie dies:

MasterLocationFormats = new[] 
    { 
     "~/Views/%1/{1}/{0}.cshtml", 
     "~/Views/%1/Shared/{0}.cshtml", 
     "~/Views/Default/{1}/{0}.cshtml", 
     "~/Views/Default/Shared/{0}.cshtml", 
    }; 

In dem die %1 mit den richtigen Ordnern für den aktiven Mieter ersetzt wird. Dies funktioniert gut, Ausnahme ein Problem. Wenn ich die Layout-Pfad auf meiner Ansicht wie folgt definieren:

Layout = "~/Views/Default/Shared/_MyLyout.cshtml"; 

Es besiegt Art von dem Zweck, die Multi-Tenancy mit, da ich die genaue Lage der Layoutseite zu hart Code haben müssen. Ich möchte in der Lage sein, so etwas zu tun:

Layout = "~/Views/%1/Shared/_MyLyout.cshtml"; 

Wenn ich wollte Mieter ermöglichen, ihre eine Layoutseiten zu haben, wie würde ich über die Unterstützung dieses gehen?

Ich habe versucht, mit der Ansicht-Engine Methoden Hantieren, die ich overrode:

  • CreatePartialView
  • Create
  • FileExists

Aber nichts scheint mich zu deuten darauf hin, dynamisch in der Lage zu spezifizieren die Layoutseite.

Update:

Hier ist, was ich bisher arbeiten. Früher habe ich die Antwort auf diese Frage leicht einen HTML-Hilfs geändert https://stackoverflow.com/a/9288455/292578 zu erstellen:

public static string GetLayoutPageForTenant(this HtmlHelper html, string LayoutPageName) 
{ 
    var layoutLocationFormats = new[] 
    { 
     "~/Views/{2}/{1}/{0}.cshtml", 
     "~/Views/{2}/Shared/{0}.cshtml", 
     "~/Views/Default/{1}/{0}.cshtml", 
     "~/Views/Default/Shared/{0}.cshtml", 
    }; 

    var controller = html.ViewContext.Controller as MultiTenantController; 
    if(controller != null) 
    { 
     var tenantName = controller.GetTenantSchema(); 
     var controllerName = html.ViewContext.RouteData.Values["Controller"].ToString(); 

     foreach(var item in layoutLocationFormats) 
     { 
      var resolveLayoutUrl = string.Format(item, LayoutPageName, controllerName, tenantName); 
      var fullLayoutPath = HostingEnvironment.IsHosted ? HostingEnvironment.MapPath(resolveLayoutUrl) : System.IO.Path.GetFullPath(resolveLayoutUrl); 
      if(File.Exists(fullLayoutPath)) return resolveLayoutUrl; 
     } 
    } 

    throw new Exception("Page not found."); 
} 

, die ähnlich ist, was saravanan vorgeschlagen. Dann kann ich das Layout meiner Meinung nach mit diesem Code festgelegt:

Layout = Html.GetLayoutPageForTenant("_Home"); 

Leider ist diese dupliziert der Arbeit, die der benutzerdefinierten Ansicht Motor tut, die wie die falsche Art und Weise scheint zu gehen.

Antwort

3

Ich mag folgende Idee vorzuschlagen,

In der _ViewStart.cshtml Datei, wo wir die Layoutseiten gesetzt, Sie so etwas wie diese, mit der Idee der Mieter basierten Layout URL oder der Ordnernamen verwenden in der Steuerung durch Abrufen von der DB gefüllt werden.

@{ 
    Layout = ViewBag.TenantLayoutPageUrl; 
} 

oder

@{ 
    Layout = string.Format("~/Views/{0}/Shared/_MyLyout.cshtml",ViewBag.TenantId); 
} 

Wenn Sie einige statische Tenant Datendarstellungen haben, wie eine statische Identity-Klasse, die den Überblick über Ihre Mieter die Anpassung halten, wir und minimieren die Hin- und Rückfahrt mit dem db verwenden können .

Bitte teilen Sie Ihre Idee auf dieser Implementierung so wird es für die Gemeinde

+0

Das einzige Problem, das ich mit diesem Ansatz habe, ist, dass nicht jeder Mieter ihre eigenen benutzerdefinierten Layout-Seiten haben wird. Ich möchte weiterhin, dass die Suche standardmäßig auf den Standardordner eingestellt wird, wenn keine benutzerdefinierte Layoutseite gefunden wird. – Sparafusile

+0

@Sparafile: In diesem Fall können wir eine Fallback-ID im ViewBag haben. Wir werden also im Contoller überprüfen, ob der Mandant eine benutzerdefinierte Layoutseite hat, wenn wir den Ordner in der Ansichtsliste festlegen, wird der Ordnername des Mandanten festgelegt. 'ViewBag.TenantFolderName =" defaultPath "; if (Mandanten hat customFolder) { ViewBag.TenantFolderName = tenantFolderName; } ' IMHO wird dies ausfallsicher sein. – Saravanan

+0

Während ich zustimme, dass dies funktionieren könnte, vereitelt es den Zweck der benutzerdefinierten Ansichts-Engine, die gesamte Arbeit in der Steuerung zu erledigen. Ich werde weiterhin nach einer eleganteren Lösung suchen. – Sparafusile

1

Versuchen,

public class CustomWebViewPage : WebViewPage 
{ 
    public override void ExecutePageHierarchy() 
    { 
     if (Context.Items["__MainView"] == null) 
     { 
      this.Layout = String.Format("~/Views/Shared/{0}/_Layout.cshtml", ViewContext.Controller.GetType().Namespace); 
      Context.Items["__MainView"] = "Not Null"; 
     } 
     base.ExecutePageHierarchy(); 
    } 

    public override void Execute() 
    { 
    } 
} 

public class CustomWebViewPage<T> : WebViewPage<T> 
{ 
    public override void ExecutePageHierarchy() 
    { 
     if (Context.Items["__MainView"] == null) 
     { 
      this.Layout = String.Format("~/Views/Shared/{0}/_Layout.cshtml", ViewContext.Controller.GetType().Namespace); 
      Context.Items["__MainView"] = "Not Null"; 
     } 
     base.ExecutePageHierarchy(); 
    } 

    public override void Execute() 
    { 
    } 
} 

<system.web.webPages.razor> 
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
    <pages pageBaseType="Mv4App.CustomWebViewPage"> 
0

Sie nützlich sein können folgende _ViewStart.cshtml in der Mieter hinzufügen Ordner Sichten (~/Views/%1/_ViewStart.cshtml). Jeder Mieter kann seine eigenen Layout-Dateien verwalten.

@{ 
    Layout = VirtualPathUtility.GetDirectory(PageContext.Page.VirtualPath) + "Shared/_Layout.cshtml"; 
} 
+0

Das ist eine interessante Idee, aber ich möchte in der Lage sein, ein benutzerdefiniertes Layout mit Standardansichten zu verwenden und/oder das Standardlayout mit benutzerdefinierten Ansichten zu verwenden. Wenn ich deine Antwort nicht falsch verstehe, kann ich das mit deinem Code nicht machen. – Sparafusile

+0

@Sparafusile Sie können das tun, können Sie '_ViewStart.cshtml' in alle Ordner, die Sie anpassen müssen, können Sie es sogar in Controller-Ordner oder in Standardordner. Standardmäßig sucht Razor Engine den Controller-Ordner nach der Startseite ('_ViewStart.cshtml'), wenn er den try-Elternordner nicht finden kann, und so weiter bis zum Anwendungsstammverzeichnis. –