RazorEngine issues with @Html
我正在使用RazorEngine渲染一些基本内容(一个非常粗糙的内容管理系统)。
直到我将任何@Html语法包含在标记中之前,它的效果都很好。
如果标记包含@html,则会出现以下错误:
Unable to compile template. The name 'Html' does not exist in the
current context
这是呈现标记的视图:
1 2 3 4 5 6 7 8 | @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获得版本的)。
任何帮助都会很棒。
检查https://github.com/Antaris/RazorEngine/wiki/6.-Encoding-Values页面。我在这里复制/粘贴它:
默认情况下,RazorEngine配置为编码为HTML。当您希望按原样输出时,有时会出现某些字符编码为HTML的问题。
要以原始格式输出内容,请使用@Raw()内置方法,如以下示例所示:
1 2 3 4 | string template ="@Raw(Model.Data)"; var model = new { Data ="My raw double quotes appears here \"hello!\"" }; string result = Razor.Parse(template, model); |
这应导致:
1 | My raw double quotes appears here"hello!" |
即将发布的v3版本将与相关的RazorEngine.Web版本一起发布,该版本将有望包含具有
我在项目主页上编写的示例纯粹是使用自定义基本模板的示例。
您可以在https://github.com/Antaris/RazorEngine上找到有关v3的更多信息。
这是一个很老的问题,但是我在coderwall上找到了很好的答案。解决方案是使用:
1 | @(new RawString("Bold!")) |
要不就:
1 | @(new RawString(Model.YourHTMLStrinInModel)) |
希望对您有所帮助。
这已经一年多了,但是由于我没有在互联网上的任何地方找到工作副本,并且github页面处于非活动状态,所以我想我会分享我的实现,以向RazorEngine添加@Html帮助器语法。这是我最后得到的实施,以Abu Haider的实施为起点。
感谢miketrash的评论:如果尝试使用@ Html.Action(),则需要添加RequestContext(可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | [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); } } } } |
我还必须重写
抱歉,我没有50条信誉才能添加评论,因此必须提出答案。
如果有人想知道(就像JamesStuddart一样),则缺少SetTemplateBase()方法,但是您可以创建一个配置实例以使用基本模板初始化服务。
来自http://razorengine.codeplex.com/discussions/285937,我修改了代码,如下所示:
1 2 3 4 5 6 7 8 9 10 11 | 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); } |
我的答案使用了hannes neukermans的答案。
我需要使用RazorEngine发送包含存储在数据库中的html字符串的电子邮件,以便管理员用户可以对其进行编辑。
标准配置不允许@ Html.Raw工作。
在我的电子邮件课程中,我设置了一个新的Engine.Razor(Engine是静态的),其中包含了Hannes建议的课程。我只需要Raw方法,但是您显然可以添加其他方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); |
以下内容并不是答案的真正组成部分,但为使用它发送电子邮件的人提供了有用的代码:)
1 2 3 4 5 6 7 8 9 10 | 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是我在此页面中找到的另一个外部函数)
1 2 | string template = System.IO.File.ReadAllText(ResolveConfigurationPath("~/Views/Emails/MAPEmail.cshtml")); SendHtmlEmail(template, model); |
HTML.Raw最简单的解决方案!需要3个步骤
步骤1:从TemplateBase继承:
1 2 3 4 5 6 7 8 9 10 | public class HtmlSupportTemplateBase< T > : TemplateBase< T > { public HtmlSupportTemplateBase() { Html = new MyHtmlHelper(); } public MyHtmlHelper Html { get; set; } } |
步骤2:创建一个对象,使模板使用的所有Html方法可用。
在此示例中,Html.Raw和Html.Encode在cshtml中可用。模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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"; } } |
第三步:
1 2 3 4 5 | var config = new TemplateServiceConfiguration { TemplateManager = templateManager, BaseTemplateType = typeof(HtmlSupportTemplateBase<>) }; |
修改mao47答案以获取最新的剃刀语法,这也将支持部分视图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | 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); } } } } } |