Подтвердить что ты не робот

Проблемы с RazorEngine с @Html

Я использую 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))

Я видел на сайте Codeplex для RazorEngine использование @Html (я знаю, что версия устарела и Я получил свою версию через nuget).

Любая помощь по этому поводу была бы большой.

4b9b3361

Ответ 1

Свойства-помощники Html и Url являются актуальными функциями реализации MVC Razor в их механизмах просмотра. Из коробки Html и Url в настоящее время не поддерживаются без специализированного базового шаблона.

Предстоящая версия v3 будет сопровождаться соответствующим выпуском RazorEngine.Web, который, мы надеемся, будет содержать базовый шаблон, совместимый с MVC3, с поддержкой Html и Url.

Пример, который я написал на главной странице проекта, является просто примером использования настраиваемого базового шаблона.

Вы можете узнать больше о v3 на https://github.com/Antaris/RazorEngine

Ответ 2

Откроется страница 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!"

Ответ 3

Это довольно старый вопрос, но я нашел хороший ответ на coderwall. Решение состоит в том, чтобы использовать:

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

или просто:

@(new RawString(Model.YourHTMLStrinInModel))

Надеюсь, это поможет.

Ответ 4

Это больше года, но поскольку я не нашел рабочую копию в любом месте в Интернете, а страница github неактивна, я решил поделиться своей реализацией с добавлением синтаксиса @Html helper для 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, прежде чем прибегать к выполнению кодирования.

Ответ 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

Мой ответ использует ответ Ханнеса Нукерманса.

Мне нужно было использовать RazorEngine для отправки электронных писем, содержащих строки HTML, хранящиеся в базе данных, чтобы их могли редактировать пользователи-администраторы.

Стандартная конфигурация не позволяла @Html.Raw работать.

В моем классе электронной почты я установил новый Engine.Razor(Engine является статическим), который включает в себя классы, которые рекомендует Ханнес. Мне был нужен только метод 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);

Ответ 8

Модификация ответа 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);

                }

            }
        }
    }
}