3

Using Razor page as Mail Template I am trying to display the content of the mail (Html Content) using @Html.Raw(Model.Content).

Anytime I run the code I get this error: html does not exist in current context.

I tried this @Html.Raw("<strong>Bold!</strong>") on another razor page to validate RazorEngine is installed and it displayed perfectly well with no error.

codegrid
  • 977
  • 2
  • 13
  • 33
  • 1
    Possible duplicate of ["The name 'Html' does not exist in the current context" exception](http://stackoverflow.com/questions/23354588/the-name-html-does-not-exist-in-the-current-context-exception) – Aaron Hudon Jan 09 '17 at 23:52
  • @AaronHudon Did you read before you mark it as duplicate? What I am doing is different. It might be the same error but their solution won't work for me. – codegrid Jan 09 '17 at 23:56

3 Answers3

15

When doing e-mails, I use the RazorEngineService in RazorEngine.Templating, e.g. in my case, it looks like this:

using RazorEngine.Templating;

RazorEngineService.Create().RunCompile(html, ...) 

Assuming you are using the same assembly, @Html.Raw does NOT exist with this usage. I was finally able to get raw HTML output by doing this in my e-mails:

@using RazorEngine.Text

@(new RawString(Model.Variable))
Kevin Nelson
  • 7,613
  • 4
  • 31
  • 42
  • At what point do I use `RazorEngineService.Create().RunCompile(...) ` ? – codegrid Jan 09 '17 at 23:57
  • @uikrosoft, Sorry for the confusion. If you're not using RazorEngine.Templating, then you would NOT see this. You didn't post what code you are using to turn a .cshtml file into an e-mail. That's why I'm just letting you see what I do and giving one possibility. You can try adding `@using RazorEngine.Text` to your e-mail CSHTML page and then wrapping your HTML in `@(new RawString(Model.Variable))` and see if it works. If you have the same assemblies loaded, that should work. – Kevin Nelson Jan 10 '17 at 00:04
  • Life saver. I would have never figured out the "using". Without that, it does not work. – cdonner Apr 21 '21 at 03:21
4
@using RazorEngine.Text

@(new RawString(Model.Variable))

Use this code in Mail template cshtml view.

Thomas Ayoub
  • 29,063
  • 15
  • 95
  • 142
0

My answer, uses hannes neukermans answer from here.

I needed to use RazorEngine in an MVC project to send emails incorporating html strings stored in a database so that they could be edited by admin users.

The standard RazorEngine config didn't allow @Html.Raw to work.

In my emails class I set up a new Engine.Razor (Engine is static) that incorporates the classes Hannes recommends. I only needed the Raw method, but you can obviously add others :

you will need these:

 using RazorEngine;
 using RazorEngine.Templating; // For extension methods.
 using RazorEngine.Text;
 using RazorEngine.Configuration;

These are the classes to provide the @Html helpers

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)); //you may not need the WebUtility.HtmlEncode here, but I did
    } 
}

I could then use @Html.Raw in my emails template to incorporate the editable 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); 
    }
}

Then I could use it by passing in the string read from the actual .cshtml template and the model holding the email data.

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

ResolveConfigurationPath is another external function I found.

 public static string ResolveConfigurationPath(string configPath)
    {
        if (configPath.StartsWith("~/"))
        {
            // +1 to Stack Overflow:
            // http://stackoverflow.com/questions/4742257/how-to-use-server-mappath-when-httpcontext-current-is-nothing

            // Support unit testing scenario where hosting environment is not initialized.
            var hostingRoot = HostingEnvironment.IsHosted
                              ? HostingEnvironment.MapPath("~/")
                              : AppDomain.CurrentDomain.BaseDirectory;

            return Path.Combine(hostingRoot, configPath.Substring(2).Replace('/', '\\'));
        }
        return configPath;
    }
davaus
  • 1,145
  • 13
  • 16