以不同的方式使用Razor视图引擎

时间:2010-09-27 21:34:05

标签: c# asp.net-mvc 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?"

主要的是我希望模板是从字符串而不是视图或部分视图中驱动的。

有人知道这是否可行?

更新:

Ben和Matt在codeplex上做了一个项目:http://razorengine.codeplex.com/

2 个答案:

答案 0 :(得分:17)

警告

这是一些丑陋丑陋的代码,除了让它正常工作外,没有经过测试而被黑客攻击。

的VirtualPathProvider

由于我们没有处理服务器上的实际视图,我们必须添加自己的路径提供程序来告诉MVC从哪里获取动态生成的模板。应该有更多的测试,例如检查字符串Dictionary以查看是否已添加视图。

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”}并且它正在抛出错误。我不确定为什么,也不太了解它。

这很有趣,谢谢你提出这个问题。

答案 1 :(得分:5)

Razor的设计考虑了独立操作。关于该模式的文档还不多(因为它仍处于开发阶段),但请查看Andrew Nurse撰写的这篇博文:http://vibrantcode.com/blog/2010/7/22/using-the-razor-parser-outside-of-aspnet.html