18

我认为如果我可以使用新的 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/

4

2 回答 2

17

警告

这是一些丑陋的代码,除了让它正常工作之外,未经测试就被黑客攻击在一起。

虚拟路径提供者

由于我们不处理服务器上的实际视图,我们必须添加我们自己的路径提供程序来告诉 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)]));
        }
    }
}

渲染类

此类将您的模板作为构造函数参数并将其添加到静态 Dictionary 中,然后由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();

    }
}

全球.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" } 并抛出错误。我不知道为什么,也没有真正深入研究它。

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

于 2010-09-28T17:02:12.210 回答
5

Razor 的设计考虑了独立操作。目前还没有太多关于该模式的文档(因为它仍在开发中),但请查看 Andrew Nurse 的这篇博客文章:http: //vibrantcode.com/blog/2010/7/22/using-the- razor-parser-outside-of-aspnet.html

于 2010-09-28T05:46:37.277 回答