2011-12-19 33 views
24

Estoy usando RazorEngine para procesar algunos contenidos básicos (un sistema de gestión de contenido muy tosco).Problemas con RazorEngine con @Html

Funciona muy bien hasta que incluya cualquier sintaxis @Html en el marcado.

Si el marcado contiene un @html me sale el siguiente error:

Unable to compile template. The name 'Html' does not exist in the current context

Esta es la vista que hace que el marcado:

@Model Models.ContentPage 

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

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

que he visto en el sitio Codeplex para la RazorEngine uso de @Html (sé que la versión no está actualizada y obtuve mi versión a través de nuget).

Cualquier ayuda sobre esto sería genial.

+0

Puse una respuesta a esta pregunta, que se ha eliminado como una respuesta duplicado porque yo también respondí aquí: http://stackoverflow.com/questions/23603593/... ... esta respuesta funciona tanto para MVC y RazorEngine. –

Respuesta

17

Las propiedades auxiliares Html y Url son características reales de la implementación de Razor de MVC en su motor de visualización. Fuera de la caja, Html y Url no son compatibles actualmente sin la especialización de una plantilla base personalizada.

La próxima versión v3 irá acompañada de una versión asociada de RazorEngine.Web, que con suerte incluirá una plantilla base compatible MVC3 con soporte Html y Url.

El ejemplo que escribí en la página de inicio del proyecto es puramente un ejemplo del uso de una plantilla base personalizada.

Usted puede encontrar más información sobre v3 en https://github.com/Antaris/RazorEngine

+0

Gracias por la respuesta, ¿tiene un ejemplo o un enlace a cómo puedo definir una plantilla base especial, ya que realmente necesito esta opción disponible ahora, y puedo cambiarla más tarde para usarla más adelante? gracias de nuevo – JamesStuddart

+0

He visto http://razorengine.codeplex.com/wikipage?title=Building%20Custom%20Base%20Templates pero la versión que obtuve de nuget no tiene el método SetTemplateBase? – JamesStuddart

+1

Actualmente, estamos impulsando la versión v3.0.5beta en Nuget, puede instalar la versión anterior v2.1 utilizando 'Install-Package RazorEngine -Version 2.1'. Mucho ha cambiado en v3, lo que hace que algunos de los códigos existentes sean incompatibles con v2.1. –

27

Comprobar https://github.com/Antaris/RazorEngine/wiki/6.-Encoding-Values página. Lo copio/lo paso aquí:

Por defecto, RazorEngine está configurado para codificar como HTML. Esto a veces presenta problemas donde ciertos caracteres están codificados como HTML cuando se quería que el resultado fuera tal como está.

para demostrar algo en formato RAW, utilice el @Raw() método integrado como se muestra en el siguiente ejemplo:

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

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

que debería traducirse en:

My raw double quotes appears here "hello!" 
+0

¡Esto es todo! El método '@Raw (string)' es lo que funcionó para mí, sin necesidad de 'IHtmlString' u otras soluciones. –

+0

Funciona como un encanto, thx ... –

9

esto termine Hace un año, pero como no encontré una copia de trabajo en Internet y la página de github está inactiva, pensé que compartiría mi implementación para agregar la sintaxis de @Html helper a RazorEngine. Aquí está la implementación con la que terminé, usando Abu Haider's implementation como punto de partida.

Cortesía del comentario de miketrash: Si estás tratando de usar @ Html.Action(), necesitarás agregar el RequestContext (puedes usar HttpContext.Current.Request.RequestContext). No incluí el contexto de solicitud porque no siempre está disponible para mi aplicación.

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

     } 
    } 
} 

También tuve que reemplazar el método de TemplateBaseWriteTo, porque de lo contrario será RazorEngine la codificación HTML a los resultados del método de ayuda que significa que va a escapar de la '<', '>', y cotizaciones (ver this question)La anulación agrega un control para el valor que es un IHtmlString antes de recurrir a la realización de una codificación.

+4

Para el pobre alma que viene aquí tratando de averiguar cómo obtener Html.Acción para trabajar con RazorEngine, necesita agregar el RequestContext. 'Var = new contexto ViewContext() { RequestContext = HttpContext.Current.Request.RequestContext, escritor = escritor, ViewData = this.ViewData };' – miketrash

+0

@miketrash: Gracias por la informacion! Recuerdo haberlo averiguado en algún momento, pero no lo usé porque necesito compilar los archivos fuera de línea fuera de cualquier contexto de solicitud. – mao47

+0

La salida de 'Html.BeginForm' todavía está codificada. ¿Debería reemplazarse algún otro método de escritura o existe otra solución? Se publica en http://stackoverflow.com/questions/41531298/how-to-render-html-beginform-output-unescaped. 'encodedString = TemplateService.EncodedStringFactory.CreateEncodedString (value);' produce una advertencia del compilador 'Templatebase.TemlateService obsoleto' – Andrus

4

Mis disculpas, no tengo la reputación requerida de 50 para agregar un comentario, así que tengo que dar una respuesta.

Si alguien se pregunta (como JamesStuddart) el método SetTemplateBase() falta pero puede crear una instancia de configuración para inicializar un servicio con su plantilla base.

De http://razorengine.codeplex.com/discussions/285937 adapté mi código por lo que parece:

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

Es bastante vieja pregunta, pero me pareció buena respuesta en coderwall. La solución es utilizar:

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

o simplemente:

@(new RawString(Model.YourHTMLStrinInModel)) 

espero que sea servicial.

+1

Esto - agregue' 'en el webconfig si está alojando esto en un biblioteca de clases/winforms etc. para obtener intellisense. – GJKH

+0

Usando RazorEngine v.3.9.3. Esto no funciona para mi. Me sale 'RawString' no es un error reconocido. – codeMonkey

0

Modificación de la respuesta de mao47 para la última sintaxis de la afeitadora, esto también admitirá vistas parciales.

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

       } 

      } 
     } 
    } 
}