Search code examples
asp.net-mvcrazorengine

RazorEngine is slow


I have MVC5 application that uses the RazorEngine to generate emails. Each email is in a cshtml template. The templates have data being passed to them so caching them does not really help even though I am doing it. Is there anything else that I can do to decrease the time it takes to render? Takes several seconds on a Azure server to render.

@{
    ViewBag.Title = "_EmailResetPassword";
}

@{ var PasswordToken = Model.token; }
@{ var URLpath = Model.URLpath; }
@{ string link = string.Format("http://{0}/Account/ResetPassword/?tokenid={1}", URLpath, PasswordToken); }

<html>

<head>
<title></title>
<style type="text/css">
.auto-style1 {
    text-align: center;
}
.auto-style2 {
    background: white;
    text-align: left;
    font-size: 11.0pt;
    font-family: Helvetica, sans-serif;
    color: #4D4D4D;
}
</style>
</head>

    <body>
        <div class="auto-style1">

        <h3 class="auto-style2">Dear @Model.FirstName,</h3>

        <h3 class="auto-style2">We have reset your password at Eph Apparel for the username: @Model.UserName</h3>

        <h3 class="auto-style2">Please click on the following link to create a new password:</h3>

        <h3 style='text-align:center;background:white'><span lang=EN-CA
        style='font-size:11.0pt;font-family:"Helvetica","sans-serif"'>
        <a href="@link">Reset Password</a></span></h3>

        <h3 style='text-align:center;background:white'><span lang=EN-CA
        style='font-size:11.0pt;font-family:"Segoe UI","sans-serif";color:#4D4D4D'>LIKE US ON </span>
        <span> <a href="https://www.facebook.com/ephapparel" target="_blank"><img alt="" width=25 height=22
        src="http://ephoms-prod.azurewebsites.net/images/eph_graphics/fb_icon.png" ></a></span>
        &nbsp;<span lang=EN-CA style='font-size:11.0pt;font-family:"Segoe UI","sans-serif";
        color:#4D4D4D'>&nbsp;FOLLOW US ON </span><span lang=EN-CA></span>
        <span><a href="https://www.twitter.com/ephApparel" target="_blank"><img alt="" width=25 height=23
        src="http://ephoms-prod.azurewebsites.net/images/eph_graphics/twitter_icon.png"></a></span></h3>
        <br>
        <img alt="" src="http://ephoms-prod.azurewebsites.net/images/eph_graphics/eph_logo.png">
        </div>

    </body>

</html>

Code behind:

private string ResetPassword(Customer oCustomer, string oToken)
{
    string oURLpath = GetConfigSettingById(3);

    string template = System.IO.File.ReadAllText(HostingEnvironment.MapPath("/bin/EmailTemplates/_EmailResetPassword.cshtml"));
    string message = Razor.Parse(template, new { FirstName = oCustomer.FirstName, UserName = oCustomer.Email, token = oToken, URLpath = oURLpath }, "Reset");
    return message;
}

Solution

  • private string ResetPassword(Customer oCustomer, string oToken)
    {
        string oURLpath = GetConfigSettingById(3);    
        string template = System.IO.File.ReadAllText(HostingEnvironment.MapPath("/bin/EmailTemplates/_EmailResetPassword.cshtml"));
        string message = Razor.Parse(template, new { FirstName = oCustomer.FirstName, UserName = oCustomer.Email, token = oToken, URLpath = oURLpath });
        return message;
    }
    

    I'm going to go out on a limb and say this is where your slowdown is occurring... These kinds of operations are quite costly on a site, especially if it is being run elsewhere (I.E. Azure). What this operation is doing is literally loading the entire file, then populating it every time you reset the password.

    There are generally 3 options you can do with e-mails.

    1. Leave it as you have it now (it works, but slow)
    2. Take the templating/caching approach (which I will put in a few seconds, and will cause significant slowdown on startup, but it becomes much better than this while running)
    3. Try a 3rd party api (I found Postal to be quite nice in terms of speed when i did something similar on my last site)

    In order to template it, do the following:

    1. First, make the Razor Elements into a new class. IE:

      public class ResetPassword
      {
          public string FirstName { get; set; }
          public string Email { get; set; }
          public string Token { get; set; }
          public string UrlPath { get; set; }
      }
      
    2. Then change your html to use the new class as its model:

      @model Your.Namespace.ResetPassword
      @{
          ViewBag.Title = "_EmailResetPassword";
          string link = string.Format("http://{0}/Account/ResetPassword/?tokenid={1}", Model.URLpath, Model.token); 
      }
      <html>   
       <head>
            <title></title>
            <style type="text/css">
            .auto-style1 {
               text-align: center;
            }
            .auto-style2 {
               background: white;
               text-align: left;
               font-size: 11.0pt;
               font-family: Helvetica, sans-serif;
               color: #4D4D4D;
            }
            </style>
      </head>
      <body>
          <div class="auto-style1">
      
          <h3 class="auto-style2">Dear @Model.FirstName,</h3>
      
          <h3 class="auto-style2">We have reset your password at Eph Apparel for the username: @Model.UserName</h3>
      
          <h3 class="auto-style2">Please click on the following link to create a new password:</h3>
      
          <h3 style='text-align:center;background:white'><span lang=EN-CA
          style='font-size:11.0pt;font-family:"Helvetica","sans-serif"'>
          <a href="@link">Reset Password</a></span></h3>
      
          <h3 style='text-align:center;background:white'><span lang=EN-CA
          style='font-size:11.0pt;font-family:"Segoe UI","sans-serif";color:#4D4D4D'>LIKE US ON </span>
          <span> <a href="https://www.facebook.com/ephapparel" target="_blank"><img alt="" width=25 height=22
          src="http://ephoms-prod.azurewebsites.net/images/eph_graphics/fb_icon.png" ></a></span>
          &nbsp;<span lang=EN-CA style='font-size:11.0pt;font-family:"Segoe UI","sans-serif";
          color:#4D4D4D'>&nbsp;FOLLOW US ON </span><span lang=EN-CA></span>
          <span><a href="https://www.twitter.com/ephApparel" target="_blank"><img alt="" width=25 height=23
          src="http://ephoms-prod.azurewebsites.net/images/eph_graphics/twitter_icon.png"></a></span></h3>
          <br>
          <img alt="" src="http://ephoms-prod.azurewebsites.net/images/eph_graphics/eph_logo.png">
          </div>
      
      </body>
      

    3. Finally, back to your code, try the following:

        private string ResetPassword(Customer oCustomer, string oToken)
        {    
            string template = HostingEnvironment.MapPath("/bin/EmailTemplates/_EmailResetPassword.cshtml");
            ResetPassword password = new ResetPassword
            {
                FirstName = oCustomer.FirstName, 
                UserName = oCustomer.Email, 
                token = oToken, 
                URLpath = GetConfigSettingById(3)
            };
            var templateService = new TemplateService(); 
            return templateService.Parse(File.ReadAllText(template), password, null, "Reset");
        }
      

    Give either this, or a 3rd party api a try, and let us know the results! (If you need help with Postal, make a new question on it, and i'll be happy to put in some input)