Подтвердить что ты не робот

ASP.NET MVC 3.0 Razor, загрузить Просмотр из любого места из коробки?

Правда ли, что можно загружать View из любого места без реализация пользовательского VirtualPathProvider в MVC 3.0?

Если это правда, как это сделать?

В принципе, это не проблема для реализации пользовательского VirtualPathProvider, который загружал бы Просмотр из любого места, но моя реализация работает только в MVC 2.0 и не работает с MVC 3.0, но почему-то метод GetFile newer вызывает не существующие представления в MVC 3.0, и в этом случае я получаю "Server Error in '/' Application."

Я выполнил тот же код для моего пользовательского VirtualPathProvider отсюда: http://buildstarted.com/2010/09/28/mvc-3-razor-view-engine-without-a-controller/

ОБНОВЛЕНИЕ 1

ОК, я исправил свою проблему с помощью моего пользовательского VirtualPathProvider после того, как я зарегистрировал первую пользовательскую первую строку поставщика VirtualPathProvider в 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);
    }

Когда регистрация пользовательского VirtualPathProvider в Global.asax.cs после метода AreaRegistration.RegisterAllAreas(); или RegisterRoutes(RouteTable.Routes); метода override VirtualFile GetFile(string virtualPath) не работает для "виртуальных просмотров".

ОБНОВЛЕНИЕ 2

означает ли это, что классы RazorView и RazorViewEngineRender являются ответом?

ОБНОВЛЕНИЕ 3

Если у меня есть строковое представление моего вида бритвы, которого нет в файловой системе (например, я храню виды бритв в базе данных), как я могу сделать это с использованием такого подхода http://buildstarted.com/2010/09/28/mvc-3-razor-view-engine-without-a-controller/

Например, представление строки моего представления выглядит следующим образом:

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

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

ОБНОВЛЕНИЕ 4

Теперь я вижу, чтобы использовать @Html.<something> пользовательский TemplateBase должен быть реализован. Образец реализации HtmlTemplateBase<T> может быть создан здесь http://www.fidelitydesign.net/?p=239, но он не будет работать с RazorEngine v2, я успешно получаю шаблон скомпилирован, то после сборки загружен метод public override void Execute() не будет выполнен. Я получаю сообщение об ошибке: метод или операция не реализованы (stacktrace: http://tinypic.com/r/dcow4/7)

Чтобы сделать "public override T Model", я изменил объявление "public TModel Model" на "public virtual TModel Model" в "public abstract class TemplateBase: TemplateBase, ITemplate". Может быть, есть еще какие-то изменения? Или что-то в HtmlTemplateBase<T> должно быть сделано другим способом?

4b9b3361

Ответ 1

Нет, загрузка представления из базы данных по умолчанию не поддерживается. Вам нужно написать свой собственный VirtualPathProvider.

Обратите внимание, что пост блога Бена фактически не адресует непосредственно проблему, которую вы пытаетесь решить. Следующее сообщение в блоге выглядит намного ближе к тому, что вы хотите: http://rebuildall.umbraworks.net/2009/11/17/ASP_NET_MVC_and_virtual_views. Обратите внимание, что неважно, пытаетесь ли вы хранить в базе данные о бритве или aspx. Поставщики виртуальных путей в Asp.Net - это просто сопоставление пути к потоку байтов, которые являются содержимым файла, представленного этим путем.

Ответ 2

Не путайте код примера Ben (@BuildStarted) в своей статье. Он подробно описывает, как использовать раннюю версию Razor ViewEngine для визуализации шаблонов без использования действия контроллера. Цель состояла в том, чтобы иметь возможность отображать шаблоны в общем виде, а не как конкретные просмотры страниц. (Это то, что превратилось в нашу структуру шаблонов RazorEngine @http://razorengine.codeplex.com).

VirtualPathProvider по-прежнему является основной частью ASP.NET. По-видимому, существует общая путаница в том, что MVC 3 DependencyResolver является заменой VirtualPathProvider, но это не так, вам все же требуется, чтобы провайдер получал доступ к контенту на виртуальном пути (что, кстати, все пути в ASP.NET являются виртуальными).

Возвращая мой первоначальный ответ, вы сможете добиться того, чего хотите, только путем подклассификации RazorViewEngine и использования этого для создания своих представлений.

Посмотрите эту тему: http://coderjournal.com/2009/05/creating-your-first-mvc-viewengine/

Ответ 3

У меня возникла аналогичная проблема с реализацией VirtualPathProvider для встроенных просмотров ресурсов. Решением было внедрение GetFolder, а также GetFile. Механизм просмотра не просто вызывает GetFile, когда вы запрашиваете это представление. По первому запросу он просматривает папку views, чтобы найти все доступные виды. Если этот вызов не включает ваши представления в базу данных в списке, они не будут найдены при попытке загрузить их.

Ответ 4

Все правильно. Мой пост был не тем, как загрузить Razor в качестве замены, а как способ вызова бритвы без использования MVC. Теперь... что вы хотите, скорее всего, связано с моим сообщением здесь Как загрузить Razor View Engine Где я покажу, как создать собственный ViewEngine для размещения страницы бритвы. Он использует тот же движок @Matthew Abbott, и я использую RazorEngine, который вы можете получить из CodePlex. К сожалению, он не завершен, но он должен дать вам представление о том, как это сделать. (Я тоже опубликую его здесь)

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
    }

}