2013-05-10 7 views
12

mi hanno messo in atto una vista del motore multi-tenant simile a quanto descritto qui:proprietà di layout Manipolazione con motore di visualizzazione Razor personalizzato

Il che mi permetta di sovrascrivere le posizioni di ricerca per la visualizzazione come questo:

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

In cui il %1 è sostituito con la cartella corretta per l'inquilino attiva. Questo sta funzionando bene, tranne un problema. Quando ho definire il percorso di layout sul mio punto di vista in questo modo:

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

E 'sorta di sconfigge lo scopo di avere il multi-tenancy dal momento che ho dovuto codificare la posizione esatta della pagina di layout. Voglio essere in grado di fare qualcosa del genere:

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

Se volessi permettere inquilini di avere loro una pagine di layout, come potrei fare per sostenere questo?

Ho provato a giocherellare con i metodi di vista del motore che mi ha calpestato:

  • CreatePartialView
  • CreateView
  • FileExists

Ma nulla sembra indicare se stesso verso l'essere in grado di specificare in modo dinamico la pagina di layout.

Aggiornamento:

Ecco quello che ho a lavorare finora. Ho usato la risposta a questa domanda https://stackoverflow.com/a/9288455/292578 leggermente modificato per creare un aiutante HTML:

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."); 
} 

che è simile a quello che Saravanan suggerito. Allora posso impostare il layout a mio avviso con questo codice:

Layout = Html.GetLayoutPageForTenant("_Home"); 

Purtroppo, questo duplica il lavoro che il motore visualizzazione personalizzata sta facendo, che sembra il modo sbagliato di procedere.

risposta

3

vorrei proporre la seguente idea,

Nel file _ViewStart.cshtml, dove abbiamo allestito le pagine di layout, è possibile utilizzare qualcosa di simile, con l'idea di layout URL inquilino base o il nome della cartella è essere riempito nel controller recuperando dal DB.

@{ 
    Layout = ViewBag.TenantLayoutPageUrl; 
} 

o

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

Se si dispone di alcune rappresentazioni di dati inquilino statica, come un Identity classe statica che non mancherà di tenere traccia della personalizzazione del vostro inquilino, possiamo utilizzare che e ridurre al minimo il viaggio di andata al db .

Si prega di condividere la tua idea su questa implementazione in modo che sarà utile per la comunità

+0

L'unico problema che ho con questo approccio è che non tutti gli inquilini avranno le proprie pagine di layout personalizzate. Continuo comunque a cercare la cartella predefinita nella cartella predefinita se non viene trovata una pagina di layout personalizzata. – Sparafusile

+0

@Sparafusile: In questo caso, possiamo avere un ID fallback nel ViewBag. Quindi, nel Contoller, controlleremo se l'inquilino ha una pagina di layout personalizzata, in tal caso la cartella verrà impostata nella view bag, altrimenti verrà impostato il nome della cartella del tenant. 'ViewBag.TenantFolderName =" defaultPath "; if (tenant Has CustomFolder) { ViewBag.TenantFolderName = tenantFolderName; } ' IMHO, questo sarà sicuro. – Saravanan

+0

Mentre sono d'accordo che questo potrebbe funzionare, questo tipo di sconfigge lo scopo del motore di visualizzazione personalizzato di fare tutto il lavoro nel controller. Continuerò a cercare una soluzione più elegante. – Sparafusile

1

prova,

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

È possibile aggiungere in seguito _ViewStart.cshtml nella inquilino cartella Viste (~/Views/%1/_ViewStart.cshtml). Ogni inquilino può gestire i propri file di layout.

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

Questa è un'idea interessante, ma voglio essere in grado di utilizzare un layout personalizzato con viste predefinite e/o utilizzare il layout predefinito con viste personalizzate. A meno che non fraintenda la tua risposta, non posso farlo con il tuo codice. – Sparafusile

+0

@Sparafusile Puoi farlo, puoi mettere '_ViewStart.cshtml' in tutte le cartelle che devi personalizzare, puoi metterlo anche nella cartella controller o nella cartella predefinita. Di default la cartella del controller di ricerca Razor Engine per la pagina iniziale ('_ViewStart.cshtml') se non riesce a trovare la cartella padre di prova e così via fino alla root dell'applicazione. –