RazorEngine与@Html问题
我正在使用RazorEngine来呈现一些基本内容(一个非常粗糙的内容pipe理系统)。
直到我将任何@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))
我已经在Codeplex网站上看到了RazorEngine使用@Html(我知道那里的版本过时了,我通过nuget得到了我的版本)。
任何帮助,这将是伟大的。
Html
和Url
帮助属性是MVC在其视图引擎中实现Razor的实际function。 开箱即用, Html
和Url
目前不支持专门定制的基本模板。
即将发布的v3版本将附带一个关联的RazorEngine.Web版本,该版本将包含一个兼容Html
和Url
的MVC3兼容基本模板。
我在项目主页上写的例子纯粹是使用自定义基本模板的例子。
检查https://github.com/Antaris/RazorEngine/wiki/6.-Encoding-Values页面。; 我在这里复制/过去:
默认情况下,RazorEngine被configuration为编码为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!"
这已经一年多了,但因为我没有在互联网上的任何地方find工作副本,并且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); } } } }
我也不得不重写TemplateBase
的WriteTo
方法,否则RazorEngine会对helper方法的结果进行html编码,这意味着你将会逃避“<”,“>”和引号(见这个问题 )。 覆盖在执行编码之前添加对作为IHtmlString
的值的检查。
这是一个相当古老的问题,但我在编码器墙上find了很好的答案。 解决scheme是使用:
@(new RawString("<strong>Bold!</strong>"))
要不就:
@(new RawString(Model.YourHTMLStrinInModel))
我希望这是有帮助的。
我的道歉,我没有所需的50声望添加评论,所以不得不作出答复。
如果有人想知道(像JamesStuddart那样),那么SetTemplateBase()方法就会丢失,但是你可以创build一个configuration实例来用你的基本模板初始化一个服务。
从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); }
修改最新的剃刀语法的mao47答案,这也将支持部分视图。
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); } } } } }