【问题标题】:RazorEngine issues with @Html@Html 的 RazorEngine 问题
【发布时间】:2012-01-23 13:45:44
【问题描述】:

我正在使用 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 获得了我的版本)。

在这方面的任何帮助都会很棒。

【问题讨论】:

  • 我提出了这个问题的答案,它作为重复的答案被删除了,因为我也在这里回答了它:stackoverflow.com/questions/23603593... ... 这个答案适用于 MVC 和 RazorEngine。

标签: razorengine


【解决方案1】:

查看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!"

【讨论】:

【解决方案2】:

HtmlUrl 辅助属性是 MVC 在其视图引擎中实现 Razor 的实际功能。开箱即用的 HtmlUrl 当前不受支持,除非专门定制基本模板。

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

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

您可以通过https://github.com/Antaris/RazorEngine了解更多关于 v3 的信息

【讨论】:

  • 感谢您的回复,您是否有示例或链接说明如何定义特殊的基本模板,因为我现在确实需要此选项,以后可以更改以使用内置的以后呢?再次感谢
  • 我看过razorengine.codeplex.com/…,但是我从nuget得到的版本没有SetTemplateBase方法?
  • 目前,我们正在 Nuget 上推送 v3.0.5beta 版本,您可以使用 Install-Package RazorEngine -Version 2.1 安装较旧的 v2.1 版本。 v3 发生了很多变化,这使得您现有的一些代码与旧 v2.1 不兼容
  • @MatthewAbbott RazorEngine.Web 的 nuget 包尚未列出,我找不到任何消息说明您为何从未继续使用它。你能提供一些讨论的链接吗?我真的很想为 MVC 助手替换一个插入式基本模板
  • @MatthewAbbott 在哪里可以找到RazorEngine.Web 版本。 Html.BeginForm 的输出仍然按照stackoverflow.com/questions/41531298/… 中的描述进行编码
【解决方案3】:

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

感谢 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);
            }

        }
    }
}

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

【讨论】:

  • 对于来到这里试图弄清楚如何让 Html.Action 与 RazorEngine 一起使用的可怜的灵魂,您需要添加 RequestContext。 var context = new ViewContext() { RequestContext = HttpContext.Current.Request.RequestContext, Writer = writer, ViewData = this.ViewData };
  • @miketrash:感谢您提供的信息!我记得在某个时候发现了这一点,但没有使用它,因为我需要在任何请求上下文之外离线编译文件。
  • Html.BeginForm 的输出仍然是编码的。是否应该覆盖其他一些 Write 方法或者是否有其他解决方案?它张贴在stackoverflow.com/questions/41531298/…encodedString = TemplateService.EncodedStringFactory.CreateEncodedString(value); 产生编译器警告 Templatebase.TemlateService is obsolete
  • @miketrash 我是那个可怜的灵魂......而且似乎 RequestContext 没有进入它,因为 RazorEngine 在 HtmlTemplateBase 的 Html 属性被调用之前抛出了一个编译错误:'System. Web.Mvc.HtmlHelper' 不包含 'Action' 的定义,并且找不到接受类型为 'System.Web.Mvc.HtmlHelper' 的第一个参数的扩展方法 'Action'(您是否缺少using 指令或程序集引用?)...这是 MVC5,所以如果您碰巧知道允许使用 Html.Action 等的最新更改,我会很高兴听到
【解决方案4】:

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

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

或者只是:

@(new RawString(Model.YourHTMLStrinInModel))

希望对你有帮助。

【讨论】:

  • 这个 - 如果您将其托管在类库/winforms 等中,请在 webconfig 中添加 &lt;add namespace="RazorEngine.Text"/&gt; 以获得智能感知。
  • 使用 RazorEngine v.3.9.3。这对我不起作用。我收到RawString 无法识别错误。
【解决方案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);
        }

【讨论】:

    【解决方案6】:

    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<>)
    };
    

    【讨论】:

    • 谢谢汉内斯。我使用了这个的修改版本,下面是像我这样的傻瓜的完整代码
    【解决方案7】:

    我的回答使用the answer by 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 是我在this page 找到的另一个外部函数)

    string template = System.IO.File.ReadAllText(ResolveConfigurationPath("~/Views/Emails/MAPEmail.cshtml"));
    SendHtmlEmail(template, model);
    

    【讨论】:

      【解决方案8】:

      修改 mao47 对最新 razor 语法的回答,这也将支持部分视图和许多其他辅助方法,因为它使 Microsoft 的辅助方法脱离 System.Web.Mvc.dll 而不仅仅是重新创建它们的一些方法。

          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);
          
                          }
          
                      }
                  }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多