35

我正在使用 RazorEngine 渲染一些基本内容(一个非常粗糙的内容管理系统)。

在我将任何 @Html 语法包含到标记中之前,它的效果很好。

如果标记包含@html,我会收到以下错误:

无法编译模板。当前上下文中不存在名称“Html”

这是呈现标记的视图:

@Model Models.ContentPage

@{
    ViewBag.Title = Model.MetaTitle;
    Layout = "~/Views/Shared/Templates/_" + Model.Layout + "Layout.cshtml";

}
@Html.Raw(RazorEngine.Razor.Parse(Model.Markup, Model))

我在 RazorEngine 的Codeplex站点上看到了 @Html 的使用(我知道那里的版本已经过时,我通过 nuget 获得了我的版本)。

对此的任何帮助都会很棒。

4

8 回答 8

31

检查https://github.com/Antaris/RazorEngine/wiki/6.-Encoding-Values页面。我在这里复制/过去:

默认情况下,RazorEngine 配置为编码为 HTML。当您希望输出保持原样时,这有时会出现某些字符被编码为 HTML 的问题。

要以原始格式输出内容,请使用 @Raw() 内置方法,如以下示例所示:

string template = "@Raw(Model.Data)";
var model = new { Data = "My raw double quotes appears here \"hello!\"" };

string result = Razor.Parse(template, model);

这应该导致:

My raw double quotes appears here "hello!"
于 2012-07-30T11:05:37.773 回答
19

HtmlUrlhelper 属性是 MVC 在其视图引擎中实现 Razor 的实际功能。开箱即用,Html如果Url不专门定制基本模板,目前不支持。

即将发布的 v3 版本将伴随一个相关的 RazorEngine.Web 版本,它有望包含一个 MVC3 兼容的基本模板HtmlUrl提供支持。

我在项目主页上写的示例,纯粹是使用自定义基础模板的示例。

您可以在https://github.com/Antaris/RazorEngine找到有关 v3 的更多信息

于 2011-12-19T13:39:53.540 回答
13

这已经有一年多了,但是由于我在 Internet 上的任何地方都没有找到工作副本并且 github 页面处于非活动状态,我想我会分享我的实现以将 @Html 辅助语法添加到 RazorEngine。这是我最终完成的实现,使用Abu Haider 的实现作为起点。

感谢 miketrash 的评论:如果您尝试使用 @Html.Action(),则需要添加 RequestContext(您可以使用HttpContext.Current.Request.RequestContext)。我没有包含请求上下文,因为它并不总是可用于我的应用程序。

[RequireNamespaces("System.Web.Mvc.Html")]
public class HtmlTemplateBase<T>:TemplateBase<T>, IViewDataContainer
{
    private HtmlHelper<T> helper = null;
    private ViewDataDictionary viewdata = null;       

    public HtmlHelper<T> Html
    {
        get
        {
            if (helper == null) 
            {                  
                var writer = this.CurrentWriter; //TemplateBase.CurrentWriter
                var vcontext = new ViewContext() { Writer = writer, ViewData = this.ViewData};

                helper = new HtmlHelper<T>(vcontext, this);
            }
            return helper;
        }
    }

    public ViewDataDictionary ViewData
    {
        get
        {
            if (viewdata == null)
            {
                viewdata = new ViewDataDictionary();
                viewdata.TemplateInfo = new TemplateInfo() { HtmlFieldPrefix = string.Empty };

                if (this.Model != null)
                {
                    viewdata.Model = Model;
                }
            }
            return viewdata;
        }
        set
        {
            viewdata = value;
        }
    }

    public override void WriteTo(TextWriter writer, object value)
    {
        if (writer == null)
            throw new ArgumentNullException("writer");

        if (value == null) return;

        //try to cast to RazorEngine IEncodedString
        var encodedString = value as IEncodedString;
        if (encodedString != null)
        {
            writer.Write(encodedString);
        }
        else
        {
            //try to cast to IHtmlString (Could be returned by Mvc Html helper methods)
            var htmlString = value as IHtmlString;
            if (htmlString != null) writer.Write(htmlString.ToHtmlString());
            else
            {
                //default implementation is to convert to RazorEngine encoded string
                encodedString = TemplateService.EncodedStringFactory.CreateEncodedString(value);
                writer.Write(encodedString);
            }

        }
    }
}

我还必须重写 的WriteTo方法TemplateBase,因为否则 RazorEngine 将对辅助方法的结果进行 html 编码,这意味着您将转义 '<'、'>' 和引号(请参阅此问题)。IHtmlString在诉诸执行编码之前,覆盖添加了对值是否为 an 的检查。

于 2013-10-17T18:10:22.253 回答
13

这是一个很老的问题,但我在coderwall上找到了很好的答案。解决方案是使用:

@(new RawString("<strong>Bold!</strong>"))

要不就:

@(new RawString(Model.YourHTMLStrinInModel))

我希望它会有所帮助。

于 2014-07-31T07:42:35.390 回答
5

抱歉,我没有添加评论所需的 50 声望,所以必须给出答案。

如果有人想知道(就像 JamesStuddart 一样)缺少 SetTemplateBase() 方法,但您可以创建一个配置实例来使用您的基本模板初始化服务。

http://razorengine.codeplex.com/discussions/285937我修改了我的代码,所以它看起来像:

var config = new RazorEngine.Configuration.TemplateServiceConfiguration
        {
            BaseTemplateType = typeof(MyHtmlTemplateBase<>)
        };

        using (var service = new RazorEngine.Templating.TemplateService(config))
        {
            // Use template service.
            Razor.SetTemplateService(service);
            result = Razor.Parse(templateString, model);
        }
于 2013-12-11T15:21:14.383 回答
3

Html.Raw最简单的解决方案!需要3个步骤

第 1 步:从 TemplateBase继承:

public class HtmlSupportTemplateBase<T> : TemplateBase<T>
{
    public HtmlSupportTemplateBase()
    {
        Html = new MyHtmlHelper();
    }

    public MyHtmlHelper Html { get; set; }

}

第 2 步:创建一个对象,使您的模板使用的所有Html 方法都可用。在此示例中,Html.Raw 和 Html.Encode 在 cshtml 中可用。模板

public class MyHtmlHelper
{
    /// <summary>
    /// Instructs razor to render a string without applying html encoding.
    /// </summary>
    /// <param name="htmlString"></param>
    /// <returns></returns>
    public IEncodedString Raw(string htmlString)
    {
        return new RawString(htmlString);
    }

    public string Encode(string value)
    {
        return System.Net.WebUtility.HtmlEncode(value);
    }

    public string Encode(object value)
    {
        return "do whatever";
    }
}

第 3 步:

var config = new TemplateServiceConfiguration
{
    TemplateManager = templateManager,
    BaseTemplateType = typeof(HtmlSupportTemplateBase<>)
};
于 2018-05-09T07:24:39.023 回答
3

我的回答使用了 hannes neukermans 的回答

我需要使用 RazorEngine 发送包含存储在数据库中的 html 字符串的电子邮件,以便管理员用户可以编辑它们。

标准配置不允许 @Html.Raw 工作。

在我的电子邮件课程中,我设置了一个新的 Engine.Razor(引擎是静态的),其中包含 Hannes 推荐的课程。我只需要 Raw 方法,但您显然可以添加其他方法:

    public class HtmlSupportTemplateBase<T> : TemplateBase<T>
{
    public HtmlSupportTemplateBase()
    {
        Html = new MyHtmlHelper();
    }
    public MyHtmlHelper Html { get; set; }
}  

 public class MyHtmlHelper
{
    /// <summary>
    /// Instructs razor to render a string without applying html encoding.
    /// </summary>
    /// <param name="htmlString"></param>
    /// <returns></returns>
    public IEncodedString Raw(string htmlString)
    {
        return new RawString(WebUtility.HtmlEncode(htmlString));
    } 
}

然后我可以在我的电子邮件模板中使用@Html.Raw 来合并可编辑的 html

public class Emails
{
    public static TemplateServiceConfiguration config 
                = new TemplateServiceConfiguration(); // create a new config

    public Emails()
    {   
        config.BaseTemplateType = typeof(HtmlSupportTemplateBase<>);// incorporate the Html helper class
        Engine.Razor = RazorEngineService.Create(config);// use that config to assign a new razor service
    }

    public static void SendHtmlEmail(string template,  EmailModel model)
    {           
        string emailBody 
             = Engine.Razor.RunCompile(template, model.Type.ToString(), typeof(EmailModel), model);

以下不是真正的答案的一部分,但为那些将它用于电子邮件的人提供了有用的代码:)

        var smtpClient = getStaticSmtpObject(); // an external method not included here     
        MailMessage message = new MailMessage();
        message.From = new MailAddress(model.FromAddress);
        message.To.Add(model.EmailAddress); 
        message.Subject = model.Subject;
        message.IsBodyHtml = true;
        message.Body =  System.Net.WebUtility.HtmlDecode(emailBody);
        smtpClient.SendAsync(message, model); 
    }
}

然后我可以通过传入从实际 .cshtml 模板读取的字符串和保存电子邮件数据的模型来使用它。(ResolveConfigurationPath 是我在这个页面找到的另一个外部函数)

string template = System.IO.File.ReadAllText(ResolveConfigurationPath("~/Views/Emails/MAPEmail.cshtml"));
SendHtmlEmail(template, model);
于 2019-01-23T03:33:27.747 回答
1

Modification of mao47's answer for latest razor syntax, this will also support partial views, and many other helper methods since it's getting Microsoft's helpers out of System.Web.Mvc.dll instead of just recreating some of their methods.

    using System;
    using System.Collections.Concurrent;
    using System.IO;
    using System.Linq;
    using System.Web.Hosting;
    using System.Xml.Linq;
    using RazorEngine.Configuration;
    using RazorEngine.Templating;
    public static class DynamicRazorTemplateParser
        {
            private static readonly IRazorEngineService service = RazorEngineService.Create(TemplateServiceConfiguration);
            public static string RunCompile<T>(string template, string placeholder, T model, DynamicViewBag viewBag) where T : class
            {
                var templateSource = new LoadedTemplateSource(template);
                return RunCompile(templateSource, placeholder, model, viewBag);
            }
            public static string RunCompile<T>(ITemplateSource template, string placeholder, T model, DynamicViewBag viewBag) where T : class 
            {            
                    return service.RunCompile(template, placeholder, model.GetType(), model, viewBag);
            }
            public static string RunCompile(ITemplateSource template, string placeholder)
            {
    
                
                    return service.RunCompile(template, placeholder);
                
            }
    
            private static TemplateServiceConfiguration TemplateServiceConfiguration
            {
                get
                {
                    var config = new TemplateServiceConfiguration
                    {
                        BaseTemplateType = typeof(HtmlTemplateBase<>),
                        TemplateManager = new TemplateManager()
                    };
                    //TODO: Is this the best way?
                    var xDocument = XDocument.Load(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "/Views/Web.config");
                    if (xDocument.Root != null)
                    {
                        var sysWeb = xDocument.Root.Element("system.web.webPages.razor");
                        if (sysWeb == null) return config;
                        var pages = sysWeb.Element("pages");
                        if (pages != null)
                        {
                            var namespaces = pages.Element("namespaces");
                            if (namespaces != null)
                            {
                                var namespacesAdd = namespaces.Elements("add")
                                    .Where(x => x.Attribute("namespace") != null)
                                    .Select(x =>
    
                                        x.Attribute("namespace").Value
                                    );
                                foreach (var ns in namespacesAdd)
                                {
                                    config.Namespaces.Add(ns);
                                }
                            }
                        }
                    }
                    return config;
                }
            }
            private class TemplateManager : ITemplateManager
            {
                private readonly ConcurrentDictionary<ITemplateKey, ITemplateSource> _dynamicTemplates = new ConcurrentDictionary<ITemplateKey, ITemplateSource>();
                private readonly string baseTemplatePath;
                public TemplateManager()
                {
                    baseTemplatePath = HostingEnvironment.MapPath("~/Views/");
                }
    
                public ITemplateSource Resolve(ITemplateKey key)
                {
                    ITemplateSource templateSource;
                    if (this._dynamicTemplates.TryGetValue(key, out templateSource))
                        return templateSource;
    
                    string template = key.Name;
                    var ubuilder = new UriBuilder();
                    ubuilder.Path = template;
                    var newURL = ubuilder.Uri.LocalPath.TrimStart('/');
                    string path = Path.Combine(baseTemplatePath, string.Format("{0}", newURL));
    
    
                    string content = File.ReadAllText(path);
                    return new LoadedTemplateSource(content, path);
                }
    
                public ITemplateKey GetKey(string name, ResolveType resolveType, ITemplateKey context)
                {
                    return new NameOnlyTemplateKey(name, resolveType, context);
                }
    
                public void AddDynamic(ITemplateKey key, ITemplateSource source)
                {
                    this._dynamicTemplates.AddOrUpdate(key, source, (k, oldSource) =>
                    {
                        if (oldSource.Template != source.Template)
                            throw new InvalidOperationException("The same key was already used for another template!");
                        return source;
                    });
                }
            }
        }

    using System;
    using System.IO;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using RazorEngine.Templating;
    using RazorEngine.Text;
    // ReSharper disable ClassWithVirtualMembersNeverInherited.Global
    // ReSharper disable MemberCanBePrivate.Global

    namespace Common.Core.Razor
    {
        [RequireNamespaces("System.Web.Mvc.Html")]
        public class HtmlTemplateBase<T> : RazorEngine.Templating.HtmlTemplateBase<T>, IViewDataContainer
        {
            private HtmlHelper<T> helper;
            private ViewDataDictionary viewdata;
            private TempDataDictionary tempdata;
            private AjaxHelper<T> ajaxHelper;
            private ViewContext viewContext;
            private UrlHelper urlHelper;
            private readonly RequestContext _requestContext = HttpContext.Current.Request.RequestContext;
    
    
            public UrlHelper Url => urlHelper ?? (urlHelper = new UrlHelper(_requestContext));
    
            public ViewContext ViewContext
            {
                get
                {
                    if (viewContext != null) return viewContext;
                    viewContext = GetViewContext();
                    return viewContext;
                }
            }
    
            public AjaxHelper<T> Ajax
            {
                get
                {
                    if (ajaxHelper != null) return ajaxHelper;
                    ajaxHelper = new AjaxHelper<T>(ViewContext, this);
                    return ajaxHelper;
                }
            }
    
            public HtmlHelper<T> Html
            {
                get
                {
                    if (helper != null) return helper;
                    helper = new HtmlHelper<T>(ViewContext, this);
                    return helper;
                }
            }
    
            public ViewDataDictionary ViewData
            {
                get
                {
                    if (viewdata == null)
                    {
                        viewdata = new ViewDataDictionary
                        {
                            TemplateInfo = new TemplateInfo() { HtmlFieldPrefix = string.Empty }
                        };
    
                        if (Model != null)
                        {
                            viewdata.Model = Model;
                        }
                    }
                    return viewdata;
                }
                set
                {
                    viewdata = value;
                }
            }
            public TempDataDictionary TempData
            {
                get { return tempdata ?? (tempdata = new TempDataDictionary()); }
                set
                {
                    tempdata = value;
                }
            }
            public virtual string RenderView()
            {
                using (var writer = new StringWriter())
                {
                    ViewContext.View.Render(ViewContext, CurrentWriter);
                    return writer.GetStringBuilder().ToString();
                }
            }
    
    
            private ViewContext GetViewContext()
            {
                if (HttpContext.Current == null) throw new NotImplementedException();
                var requestContext = _requestContext;
                var controllerContext = ControllerContext(requestContext);
    
                var view = GetView(requestContext, controllerContext);
                //Can't check if string writer is closed, need to catch exception
                try
                {
                    var vContext = new ViewContext(controllerContext, view, ViewData, TempData, CurrentWriter);
                    return vContext;
    
                }
                catch
                {
                    using (var sw = new StringWriter())
                    {
                        var vContext = new ViewContext(controllerContext, view, ViewData, TempData, sw);
                        return vContext;
                    }
                }
            }
    
            private IView GetView(RequestContext requestContext, ControllerContext controllerContext)
            {
                if ((string)requestContext.RouteData.DataTokens["Action"] != null)
                {
                    requestContext.RouteData.Values["action"] = (string)requestContext.RouteData.DataTokens["Action"];
                }
    
                var action = requestContext.RouteData.GetRequiredString("action");
                var viewEngineResult = ViewEngines.Engines.FindPartialView(controllerContext, action);
                if (viewEngineResult != null && viewEngineResult.View != null)
                {
                    return viewEngineResult.View;
                }
    
                viewEngineResult = ViewEngines.Engines.FindView(controllerContext, action, null);
                if (viewEngineResult == null)
                {
                    throw new Exception("No PartialView assigned in route");
                }
                return viewEngineResult.View;
    
    
            }
    
            public void SetView(string view)
            {
                _requestContext.RouteData.DataTokens["Action"] = view;
            }
    
    
            private ControllerContext ControllerContext(RequestContext requestContext)
            {
                ControllerBase controllerBase;
                var routeDataValue = "EmptyController";
                if (requestContext.RouteData.Values["controller"] != null && (string)requestContext.RouteData.Values["controller"] != routeDataValue)
                {
                    var controllerName = (string)requestContext.RouteData.Values["controller"];
                    IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(requestContext, controllerName);
                    controllerBase = controller as ControllerBase;
                }
                else
                {
    
                    var controller = new EmptyController();
                    controllerBase = controller; //ControllerBase implements IController which this returns
                    requestContext.RouteData.Values["controller"] = routeDataValue;
                }
                var controllerContext =
                    new ControllerContext(requestContext.HttpContext, requestContext.RouteData, controllerBase);
                return controllerContext;
            }
            private class EmptyController : Controller { }
            public override void WriteTo(TextWriter writer, object value)
            {
                if (writer == null)
                    throw new ArgumentNullException("writer");
    
                if (value == null) return;
    
                //try to cast to RazorEngine IEncodedString
                var encodedString = value as IEncodedString;
                if (encodedString != null)
                {
                    writer.Write(encodedString);
                }
                else
                {
                    //try to cast to IHtmlString (Could be returned by Mvc Html helper methods)
                    var htmlString = value as IHtmlString;
                    if (htmlString != null) writer.Write(htmlString.ToHtmlString());
                    else
                    {
                        //default implementation is to convert to RazorEngine encoded string
                        base.WriteTo(writer, value);
    
                    }
    
                }
            }
        }
    }
于 2017-05-12T15:18:20.037 回答