Send asp.net mvc action result inside email

First, you’ll still probably want to return a view from your action, so returning an EmptyResult isn’t the best; but you’ll figure that out when you’re dealing with the page flow in your registration process.

I’m assuming that you wish to create an HTML email using a View you have already created. That means you wish to take the result of something that looks like the following:

public ActionResult CreateEmailView(RegistrationInformation info)
{
  var userInformation = Membership.CreateNewUserLol(info);
  return View(userInformation)
}

and send that as the body of the email. You get to reuse your views and all that fun stuff.

You can take advantage of the framework by creating a custom ActionResult and using this to generate your text.

Here is some c#-like pseudocode that might actually compile and work. First, the custom ActionResult:

public class StringResult : ViewResult
{
    public string Html { get; set; }
    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (string.IsNullOrEmpty(this.ViewName))
        {
            this.ViewName = 
                 context.RouteData.GetRequiredString("action");
        }
        ViewEngineResult result = null;
        if (this.View == null)
        {
            result = this.FindView(context);
            this.View = result.View;
        }
        ViewContext viewContext = new ViewContext(
                context, this.View, this.ViewData, this.TempData);
        using (var stream = new MemoryStream())
        using (var writer = new StreamWriter(stream))
        {
            // used to write to context.HttpContext.Response.Output
            this.View.Render(viewContext, writer);
            writer.Flush();
            Html = Encoding.UTF8.GetString(stream.ToArray());
        }
        if (result != null)
        {
            result.ViewEngine.ReleaseView(context, this.View);
        }
    }
}

This overrides the base method’s ExecuteResult (this is the code from the base method I’m overriding; may have changed in RC1) to render to a stream that I control instead of the Output stream of the Response. So it pulls out the text exactly how it would be rendered to the client machine.

Next, how you would use this in a controller action:

public ActionResult CreateEmailView(RegistrationInformation info)
{
  var userInformation = Membership.CreateNewUserLol(info);
  // grab our normal view so we can get some info out of it
  var resultView = View(userInformation);

  // create our string result and configure it
  StringResult sr = new StringResult();
  sr.ViewName = resultView.ViewName;
  sr.MasterName = resultView.MasterName;
  sr.ViewData = userInformation;
  sr.TempData = resultView.TempData;
  // let them eat cake
  sr.ExecuteResult(this.ControllerContext);
  string emailHtml = sr.Html;
  // awesome utils package, dude
  Utils.SendEmailKThx(userInformation, emailHtml);

  return resultView;
}

I’m rendering the same view twice; the first time I render it to a stream and the second time I render it normally. It might be possible to sneak into the call chain of ViewResult somewhere else and change how Render operates, but a cursory glance at the code doesn’t reveal anything. While the framework is pretty good, the call stack for parts of the process are just not fine grained enough to make it easy to change a single step in the process. If they broke ExecuteResult into a few different overridable methods, we could have changed it from rendering to the output stream to rendering to our stream without overriding the entire ExecuteResult method. Oh well….

Leave a Comment