2011-01-19 12 views
12

Czy to prawda, że ​​można załadować View z dowolnego miejsca bez implementacji niestandardowej VirtualPathProvider w MVC 3.0?Brzytwa ASP.NET MVC 3.0, ładowanie Widok z dowolnego miejsca po wyjęciu z pudełka?

Jeśli to prawda, jak to zrobić?

W zasadzie to nie jest problem do realizacji niestandardowych VirtualPathProvider które załadować Widok z dowolnego miejsca, ale moja implementacja działa tylko w MVC 2.0 i nie działa wih MVC 3.0, dziobowy jakiegoś sposobu powodu GetFile nowsze nazwie dla nie istniały widoków w MVC 3,0 i w tym przypadku jestem coraz "Server Error in '/' Application."

Śledziłem ten sam kod dla mojego zwyczaju VirtualPathProvider stąd: http://buildstarted.com/2010/09/28/mvc-3-razor-view-engine-without-a-controller/

UPDATE 1

OK id id rozwiązać mój problem z moim zwyczajem VirtualPathProvider po kładę rejestrację mojego zwyczaj VirtualPathProvider dostawcy pierwszej linii w Application_Start()

protected void Application_Start() 
    { 
     //Should be first line before routes and areas registration. 
     HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider()); 

     AreaRegistration.RegisterAllAreas(); 

     RegisterGlobalFilters(GlobalFilters.Filters); 
     RegisterRoutes(RouteTable.Routes); 
    } 

Po rejestracji niestandardowej VirtualPathProvider w Global.asax.cs folowing po AreaRegistration.RegisterAllAreas(); lub RegisterRoutes(RouteTable.Routes); METODA override VirtualFile GetFile(string virtualPath) przyzwyczajenie praca dla " widoki wirtualne ".

UPDATE 2

nie oznacza to, że zajęcia RazorView i RazorViewEngineRender jest odpowiedź?

UPDATE 3

Jeśli mam ciąg znaków reprezentujący moim zdaniem brzytwa, który nie istnieje w systemie plików (np przechowywać widoki brzytwa w bazie danych) jak mogę uczynić to za pomocą tego rodzaju podejścia http://buildstarted.com/2010/09/28/mvc-3-razor-view-engine-without-a-controller/

Na przykład ciąg znaków z moim zdaniem wygląda następująco:

"@{ 
    ViewBag.Title = ""About Us""; 
} 

<h2>About</h2> 
<p> 
    Put content here. 
</p>" 

UPDATE 4

teraz widzę, aby móc użyć @Html.<something>, należy zaimplementować niestandardową bazę szablonów. Przykładowa implementacja HtmlTemplateBase<T> może być tutaj źródłem http://www.fidelitydesign.net/?p=239, ale nie będzie działać z RazorEngine v2, pomyślnie otrzymuję szablon skompilowany, a następnie po załadowaniu zestawu metoda public override void Execute() nie zostanie wykonana Otrzymuję błąd: Metoda lub operacja nie jest zaimplementowana (stacktrace: http://tinypic.com/r/dcow4/7)

Aby uzyskać "publiczny nadpisanie modelu T", zmieniłem deklarację "publicznego modelu TModel" na "publiczny wirtualny model TModel" w "publicznej klasie abstrakcyjnej TemplateBase: TemplateBase, ITemplate" . Może być jeszcze kilka innych zmian? Lub coś w HtmlTemplateBase<T> należy zrobić w inny sposób?

+0

Również spojrzeć na http://stackoverflow.com/questions/3367106/pulling-a-view-from-a-database-rather-than-a-file – Buildstarted

Odpowiedz

2

Nie, ładowanie widoku z bazy danych nie jest obsługiwane domyślnie. Musisz napisać własną VirtualPathProvider.

Uwaga: blog Bena nie rozwiązuje bezpośrednio problemu, który próbujesz rozwiązać. Poniższy wpis na blogu wygląda znacznie bliżej tego, co chcesz: http://rebuildall.umbraworks.net/2009/11/17/ASP_NET_MVC_and_virtual_views.Zauważ, że nie ma znaczenia, czy próbujesz zapisać widoki brzytwy lub aspx w bazie danych. Dostawcy wirtualnych ścieżek w Asp.Net to po prostu mapowanie ścieżki do strumienia bajtów, które są zawartością pliku reprezentowanego przez tę ścieżkę.

+0

OK, ale jeśli przeczytałeś moje pytanie do końca opisałem pewne szczegóły/problemy, które mój dostawca nie będzie pracował z MVC 3.0. – Kuncevic

+0

@bigb zobacz aktualizację – marcind

6

Nie należy mylić kodu przykładowego Bena (@BuildStarted) w jego artykule. Wyszczególnia, jak użyć wczesnej wersji Razor ViewEngine do renderowania szablonów bez użycia akcji kontrolera. Celem było umożliwienie renderowania szablonów w ogólny sposób, a nie jako określone widoki strony. (To właśnie rozwinęło się w naszą strukturę szablonów RazorEngine @http://razorengine.codeplex.com).

Numer VirtualPathProvider nadal stanowi rdzeń ASP.NET. Wydaje się, że ogólne zamieszanie związane z tym, że MVC 3 DependencyResolver jest zamiennikiem VirtualPathProvider, ale tak nie jest, wciąż potrzebujesz dostawcy, aby mieć dostęp do treści na wirtualnej ścieżce (która, nawiasem mówiąc, wszystkie ścieżki w ASP.NET są wirtualny).

Powracając do mojej oryginalnej odpowiedzi, powinieneś być w stanie osiągnąć to, czego chcesz, poprzez podklasy RazorViewEngine i za pomocą tego, aby utworzyć swoje poglądy.

Wystarczy popatrzeć na ten temat: http://coderjournal.com/2009/05/creating-your-first-mvc-viewengine/

2

wpadłem na podobnym problemie wdrożono VirtualPathProvider wbudowanych widoków zasobów. Rozwiązaniem było wdrożenie GetFolder oraz GetFile. Mechanizm wyświetlania nie tylko wywołuje GetFile, gdy żądasz tego widoku. Na pierwsze żądanie przegląda folder widoków, aby znaleźć wszystkie dostępne widoki. Jeśli to połączenie nie uwzględnia widoków bazy danych na liście, nie zostaną znalezione podczas próby ich załadowania.

1

Wszyscy mają rację. Mój post nie dotyczył ładowania Razora jako zamiennika, ale sposobu na wywoływanie maszynki do golenia bez użycia MVC. Teraz ... to, co chcesz, jest najprawdopodobniej związane z moim postem tutaj. How to Download Razor View Engine Gdzie pokazuję, jak stworzyć własny ViewEngine do obsługi strony brzytwy. Używa tego samego silnika @Matthew Abbott i używam go do RazorEngine - który można uzyskać od CodePlex. Niestety nie jest kompletny, ale powinien dać ci pomysł, jak to zrobić. (Ja to pisać tutaj zbyt)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Hosting; 
using System.IO; 
using System.Text.RegularExpressions; 
using System.Xml.Linq; 

namespace RazorViewEngine { 
    /// <summary> 
    /// ViewEngine for the RazorView. Provides basic file handling to load views. 
    /// </summary> 
    public class RazorViewEngine : IViewEngine { 

     string[] SearchLocations { get; set; } 
     Tuple<string, string, RazorView> Cache { get; set; } 
     VirtualPathProvider VirtualPathProvider { get; set; } 

     public RazorViewEngine() { 
      //{1} == Controller name 
      //{0} == View name 
      SearchLocations = new string[] { 
       "~/Views/{1}/{0}.cshtml", 
       "~/Views/Shared/{0}.cshtml", 
      }; 

      VirtualPathProvider = HostingEnvironment.VirtualPathProvider; 
     } 

     #region IViewEngine Members 

     public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) { 
      return CreateView(controllerContext, partialViewName, null, null, useCache); 
     } 

     public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) { 
      return CreateView(controllerContext, viewName, masterName, GetLayoutPath(controllerContext), useCache); 
     } 

     /// <summary> 
     /// Meat of the FindView methods. 
     /// </summary> 
     /// <param name="controllerContext">The current controller context for this request.</param> 
     /// <param name="viewName">The requested view name. </param> 
     /// <param name="masterName">The master page view name (currently unused)</param> 
     /// <param name="layoutPath">The layout path location (Replaces the masterpage in other view engines)</param> 
     /// <param name="useCache">Cache the viewpage?</param> 
     /// <remarks>The layout path is currently hardcoded to "Layout" and will look in the SearchLocations for that path</remarks> 
     /// <returns>Returns a ViewEngineResult with the requested view</returns> 
     public ViewEngineResult CreateView(ControllerContext controllerContext, string viewName, string masterName, string layoutPath, bool useCache) { 
      //grab the current controller from the route data 
      string controllerName = controllerContext.RouteData.GetRequiredString("controller"); 

      //for proper error handling we need to return a list of locations we attempted to search for the view 
      string[] SearchedLocations; 

      //get the actual path of the view - returns null if none is found 
      string viewPath = GetViewPath(viewName, controllerName, out SearchedLocations); 

      if (viewPath != null) { 
       RazorView view = new RazorView(this, controllerContext, viewPath, layoutPath); 
       return new ViewEngineResult(view, this); 
      } 

      //we couldn't find the view - return an array of all locations we've looked in 
      return new ViewEngineResult(SearchedLocations); 
     } 

     /// <summary> 
     /// Look for the view in the current file system 
     /// </summary> 
     /// <param name="viewName">The name of the View you're looking for</param> 
     /// <param name="controllerName">Current controller name</param> 
     /// <param name="SearchedLocations">out a list of locations searched</param> 
     /// <returns>A string value of the relative path</returns> 
     public string GetViewPath(string viewName, string controllerName, out string[] SearchedLocations) { 
      return FindPath(viewName, controllerName, out SearchedLocations); 
     } 

     /// <summary> 
     /// Look for the view in the current file system 
     /// </summary> 
     /// <param name="viewName">The name of the View you're looking for</param> 
     /// <param name="controllerName">Current controller name</param> 
     /// <param name="SearchedLocations">out a list of locations searched</param> 
     /// <returns>A string value of the relative path</returns> 
     public string FindPath(string viewName, string controllerName, out string[] SearchedLocations) { 
      SearchedLocations = new string[SearchLocations.Length]; 

      for (int i = 0; i < SearchLocations.Length; i++) { 
       string virtualPath = string.Format(SearchLocations[i], viewName, controllerName); 

       SearchedLocations[i] = virtualPath; 

       //check the active VirtualPathProvider if the file exists 
       if (VirtualPathProvider.FileExists(virtualPath)) { 
        //add it to cache - not currently implemented 
        return VirtualPathProvider.GetFile(virtualPath).VirtualPath; 
       } 
      } 

      return null; 
     } 

     /// <summary> 
     /// Get the layout virtual path 
     /// </summary> 
     /// <param name="controllerContext">The current Controller context for this request</param> 
     /// <returns>A string virtual path</returns> 
     public string GetLayoutPath(ControllerContext controllerContext) { 
      //This should probably be added to a list of locations - I'm not sure exactly 
      //what I need to do with this yet. 
      string[] locations; 

      return FindPath("Layout", controllerContext.RouteData.GetRequiredString("controller"), out locations); 
     } 

     /// <summary> 
     /// Current irrelevant 
     /// </summary> 
     /// <param name="controllerContext">The active controller context</param> 
     /// <param name="view">View to release</param> 
     public void ReleaseView(ControllerContext controllerContext, IView view) { 
      IDisposable disposable = view as IDisposable; 
      if (disposable != null) { 
       disposable.Dispose(); 
      } 
     } 

     #endregion 
    } 

    /// <summary> 
    /// Implements IView and renders a Razor 
    /// </summary> 
    public class RazorView : IView { 

     ControllerContext ControllerContext; 
     string ViewPath; 
     string LayoutPath; 
     RazorViewEngine Engine; 

     public RazorView(RazorViewEngine engine, ControllerContext controllerContext, string viewPath, string layoutPath) { 
      //load the file 
      this.ControllerContext = controllerContext; 
      this.ViewPath = viewPath; 
      this.LayoutPath = layoutPath; 
      this.Engine = engine; 
     } 

     #region IView Members 

     /// <summary> 
     /// Converts Razor to html and writes it to the passed in writer 
     /// </summary> 
     /// <param name="viewContext"></param> 
     /// <param name="writer"></param> 
     public void Render(ViewContext viewContext, System.IO.TextWriter writer) { 
      //View contents 
      string contents = new StreamReader(VirtualPathProvider.OpenFile(ViewPath)).ReadToEnd(); 
      string layoutContents = LayoutPath == null 
       ? null 
       : new StreamReader(VirtualPathProvider.OpenFile(LayoutPath)).ReadToEnd(); 

      contents = Parse(contents); 

      string output; 
      output = contents; 

      writer.Write(output); 
     } 

     /// <summary> 
     /// Converts Razor to html 
     /// </summary> 
     /// <param name="Razor">Razor text</param> 
     /// <returns>Html formatted Razor text</returns> 
     string Parse(string Razor) { 

      //Where do I get the model From 

      return RazorEngine.Razor.Parse(Razor); 
     } 

     #endregion 
    } 

} 
+0

@BuildStarted Reading updated @Matthew Abbott answer Myślałem, że muszę coś takiego zrobić, dziękuję za wszystkie szczegóły. – Kuncevic

+0

Najpierw zrobiłem to, aby dodać niestandardowy silnik (twoją implementację), tak jak jest, po uruchomieniu aplikacji sieciowej MVC 3.0 pojawia się błąd Nie można skompilować szablonu. Sprawdź listę błędów, aby uzyskać szczegółowe informacje. Wtedy znalazłem, że używam nie zaktualizowanej wersji RazorEngine, a następnie po pobraniu v 2.0 otrzymuję ten sam błąd. Też czytałem ten wątek http://razorengine.codeplex.com/Thread/View.aspx?ThreadId=235751, mam Microsoft.CSharp i System.Core odniesienia w mojej aplikacji, a także System.Web.Razor.dll i ustawić true to Copy Local. Szablon, który go nie skompiluje jest po prostu domyślnym widokiem Home/Index MVC3.0. – Kuncevic

+0

Niż do odwołania do RazorEngine jako projektu do kroku ... tutaj jest printscrin z więcej szczegółów na temat błędu http://tinypic.com/r/rlx8cj/7, A także znalazłem ten błąd w wynikach. Błędy: CompiledAssembly = "results.CompiledAssembly" rzucił wyjątek typu "System.IO.FileNotFoundException" Czy jest w jakiś sposób związany z pełnym zaufaniem? – Kuncevic

Powiązane problemy