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

Использование механизма просмотра Razor по-другому

Я подумал, что было бы интересно, если бы я мог использовать новый механизм MVC Razor View в качестве технологии слияния. Он все еще может быть частью веб-сайта MVC и не должен быть автономным консольным приложением.

Пример:

string  myTemplate = "Hello @Name,  How are you today?";
ViewModel.Name = "Billy Boy";
string output = RazorViewEngineRender( myTemplate, ViewModel );

Тогда string output = "Hello Billy Boy, How are you today?"

Главное, что я хочу, чтобы шаблон управлялся из строки, а не из вида или частичного просмотра.

Кто-нибудь знает, возможно ли это?

UPDATE:

Бен и Мэтт сделали проект на codeplex: http://razorengine.codeplex.com/

4b9b3361

Ответ 1

Предупреждение

Это какой-то уродливый уродливый код, который был взломан вместе, не тестируя его, кроме как заставить его работать правильно.

VirtualPathProvider

Поскольку мы не имеем дело с фактическими представлениями на сервере, мы должны добавить наш собственный поставщик путей, чтобы сообщить MVC, где можно получить наши динамически сгенерированные шаблоны. Там должно быть больше тестов, таких как проверка строк Словарь, чтобы увидеть, было ли добавлено представление.

public class StringPathProvider : VirtualPathProvider {
    public StringPathProvider()
        : base() {
    }

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) {
        return null;
    }

    public override bool FileExists(string virtualPath) {
        if (virtualPath.StartsWith("/stringviews") || virtualPath.StartsWith("~/stringviews"))
            return true;

        return base.FileExists(virtualPath);
    }

    public override VirtualFile GetFile(string virtualPath) {
        if (virtualPath.StartsWith("/stringviews") || virtualPath.StartsWith("~/stringviews"))
            return new StringVirtualFile(virtualPath);

        return base.GetFile(virtualPath);
    }

    public class StringVirtualFile : System.Web.Hosting.VirtualFile {

        string path;

        public StringVirtualFile(string path)
            : base(path) {
            //deal with this later
                this.path = path;
        }

        public override System.IO.Stream Open() {
            return new System.IO.MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(RazorViewEngineRender.strings[System.IO.Path.GetFileName(path)]));
        }
    }
}

Класс рендеринга

Этот класс принимает ваш шаблон в качестве параметра конструктора и добавляет его в статический словарь, который затем считывается с помощью VirtualPathProvider выше. Затем вы вызываете Render, и вы можете дополнительно передать модель. Это добавит полный тип модели к @inherits и добавит к содержимому файла.

public class RazorViewEngineRender {
    internal static Dictionary<string, string> strings { get; set; }

    string guid;

    static RazorViewEngineRender() {
        strings = new Dictionary<string, string>();
    }

    public RazorViewEngineRender(string Template) {
        guid = Guid.NewGuid().ToString() + ".cshtml";
        strings.Add(guid, Template);
    }

    public string Render() {
        return Render(null);
    }

    public string Render(object ViewModel) {
        //Register model type
        if (ViewModel == null) {
            strings[guid] = "@inherits System.Web.Mvc.WebViewPage\r\n" + strings[guid];
        } else {
            strings[guid] = "@inherits System.Web.Mvc.WebViewPage<" + ViewModel.GetType().FullName + ">\r\n" + strings[guid];
        }

        CshtmlView view = new CshtmlView("/stringviews/" + guid);

        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        System.IO.TextWriter tw = new System.IO.StringWriter(sb);

        ControllerContext controller = new ControllerContext();

        ViewDataDictionary ViewData = new ViewDataDictionary();
        ViewData.Model = ViewModel;

        view.Render(new ViewContext(controller, view, ViewData, new TempDataDictionary(), tw), tw);
        //view.ExecutePageHierarchy();

        strings.Remove(guid);

        return sb.ToString();

    }
}

Global.asax

В вашем файле global.asax вам нужно добавить следующее в Application_Start

System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new Controllers.StringPathProvider());

Вызов кода

string Template = "Hello, @Model.Name";
Models.User user = new Models.User() { Name = "Billy Boy" };
RazorViewEngineRender view = new RazorViewEngineRender(Template);
string Results = view.Render(user); //pass in your model

Примечания

Этот только работает с типизированными моделями. Я попытался передать новый {Name = "Billy Boy" }, и он бросает ошибки. Я не уверен, почему и на самом деле не смотрел слишком глубоко.

Это было весело, спасибо, что задали этот вопрос.

Ответ 2

Бритва была разработана с учетом автономной работы. До сих пор не так много документации об этом режиме (поскольку все еще находится в разработке), но посмотрите на это сообщение в блоге Andrew Nurse: http://vibrantcode.com/blog/2010/7/22/using-the-razor-parser-outside-of-aspnet.html