title: Generate Email HTML using Razor in an ASP.NET MVC Project
body: <p>I have an ASP.NET MVC project that uses Razor for rendering HTML using the built-in engine.</p>
  
  <p>I would like to create Email Templates using the same process.  Usually, these templates are created as part of a Action Context (for instance, when a user has completed a purchase, a notification would be sent).  However, there are some instances where there is no context available.  For instance, sending a log when the application is restarting.</p>
  
  <p>This is what I have come up with so far:</p>
  
  <pre><code>public static string RenderRazor(ViewTemplateType TemplateType, string ViewName, PageController Controller = null, object Model = null)
  {
      try
      {
          ControllerContext Context;
  
          if (Controller != null)
          {
              Context = Controller.ControllerContext;
          }
          else
          {
              if (HttpContext.Current == null)
              {
                  throw new InvalidOperationException("Cannot render a razor template if the current context is null (See DEV-1669).");
              }
              var RouteData = new RouteData();
              RouteData.Values.Add("controller", "Pseudo");
              Controller = new PseudoController(Model);
              Context = new ControllerContext(new HttpContextWrapper(HttpContext.Current), RouteData, Controller);
              // If this isn't set, an error occurs when calling FindView/FindViewPartial.
              Controller.ControllerContext = Context;
          }
  
          // I'm not really sure what the point of this is...
          // Further, it was actually causing an exception to occur since the Controller may not actually be populated?
          // Without this, the Notification Debug wasn't working - so apparently it is required in some circumstances for notifications.
          if (Controller != null &amp;&amp; Controller.ViewData != null &amp;&amp; Model != null) { Controller.ViewData.Model = Model; }
  
          var ViewResult = ViewName.StartsWith("_")
              ? ViewEngines.Engines.FindPartialView(Context, string.Format("~/Views/Template/{0}/{1}.cshtml", TemplateType, ViewName))
              : ViewEngines.Engines.FindView(Context, string.Format("~/Views/Template/{0}/{1}.cshtml", TemplateType, ViewName), string.Format("~/Views/Template/{0}/_Shared/{1}.cshtml", TemplateType, "_Layout"));
  
          if (ViewResult.View == null)
          {
              StringBuilder LocationBuilder = new StringBuilder();
              string[] SearchedLocations = ViewResult.SearchedLocations.ToArray();
              for (int i = 0; i &lt; SearchedLocations.Length; i++)
              {
                  LocationBuilder.Append(string.Format("({0}) {1} ", i, SearchedLocations[i]));
              }
  
              throw new InvalidOperationException(string.Format("Could not find the {0} Template named {1} using the {2} Master. Locations Searched: {3}", TemplateType, ViewName, "_Layout", LocationBuilder));//
          }
          using (var Writer = new StringWriter())
          {
              //ViewResult.View.Render(new ViewContext(
              //  Context,
              //  ViewResult.View,
              //  (Controller != null) ? Controller.ViewData : (Model != null) ? new ViewDataDictionary(Model) : new ViewDataDictionary(),
              //  (Controller != null) ? Controller.TempData : new TempDataDictionary(), Writer), Writer);
  
              ViewResult.View.Render(new ViewContext(
                  Context,
                  ViewResult.View,
                  Controller.ViewData,
                  Controller.TempData, Writer), Writer);
  
              ViewResult.ViewEngine.ReleaseView(Context, ViewResult.View);
  
              // This must remove Tabs (\t) Returns (\r) and Newlines (\n)
              // Always making the quotes single makes sense for statically generated stuff - the only time when it wouldn't make sense is for more complex stuff or if it includes JS which i don't think
              // a statically generated one should ever?
  
              string result = Regex.Replace(Writer.GetStringBuilder().ToString().Replace("\"", "\'"), "(\\t|\\r|\\n)", string.Empty);
  
              // Currently, this process does not work well when initiated outside of a request (e.g. in the startup method or purely within a
              // hangfire task). This serves as a warning if it ever is (since it will return an empty string).
  
              if (result.Blank()) { throw new InvalidOperationException("There was an error rendering the " + ViewName + " template. This can happen if the template was initialized outside of the context of an actual request."); }
              else
              {
                  return result;
              }
          }
      }
      catch (Exception ex)
      {
          // This could indicate an error in the underlying template
          // If there is an error on any of the underlying templates in a given class,
          // this can be called.
          Logging.Error(ex);
          return string.Empty;
      }
  }
  </code></pre>
  
  <p>This works pretty well except for when I am trying to generate a template when I don't have a reference to a Controller.</p>
  
  <p>I have also started looking into applying the third-party RazorEngine (<a href="https://antaris.github.io/RazorEngine" rel="nofollow noreferrer">https://antaris.github.io/RazorEngine</a>) - but is this overkill?  Is it even feasible to implement this in a project that also utilizes the built-in razor engine?</p>