7

I want to use MVC views to create the body for an email and I have come across this (http://www.brightmix.com/blog/renderpartial-to-string-in-asp-net-mvc/) but it doesn't seem to work with strongly typed views (ViewContext is null). But I was after something the would render a full view including a masterpage.

I thought that if there was a way of just invoking a view with out redirecting and just writing to a different stream and sending the email within the controller that might do it, but I can't work out how to invoke a view.

Any suggestions would be great!

Thanks in advance.

Gifster

Andy
  • 305
  • 1
  • 4
  • 14
  • possible duplicate of [Render a view as a string](http://stackoverflow.com/questions/483091/render-a-view-as-a-string) – Matt Hinze Nov 12 '10 at 11:15

2 Answers2

15

The question has been asked (and answered) already:

Render View as a String

This is the bit that I use:

protected string RenderViewToString<T>(string viewPath, T model, System.Web.Mvc.ControllerContext controllerContext) {
        using (var writer = new StringWriter()) {
            var view = new WebFormView(viewPath);
            var vdd = new ViewDataDictionary<T>(model);
            var viewCxt = new ViewContext(controllerContext, view, vdd, new TempDataDictionary(), writer);
            viewCxt.View.Render(viewCxt, writer);
            return writer.ToString();
        }
    }

Best place for this method is in a class library project that your mvc project has a reference to. Mainly because that way you can easily reuse it in all your apps. But also because it is neither Application logic (so doesn't belong in the controller) nor does it belong in the model. Some things are just utilities.

Note that to get this to work, the viewPath parameter HAS to be the PHYSICAL PATH to the file, complete with the .aspx extension. You can't use a route as WebFormView class requires a physical path in its constructor.

This will render the full view and take account of the master page.


HEALTH WARNING FOR HTML EMAILS:

HTML emails and the devices where you read them are even more difficult and restrictive to design for than websites and browsers. What works in one, will not work in another. So with html emails, you really have to Keep It Simple! Your lovely page with menus and relative images and whatever else, JUST WON'T WORK in all email devices. Just as an example, the images src attribute needs to be absolute and include the domain:

This won't work:

<img src="/Images/MyImage.gif" ... /> 

Bit this will:

 <img src="http://www.mywebsite.com/Images/MyImage.gif" ... /> 

With those caveats, it works fine and I use it. Just don't try to send them the full gimmickry of your website, cos that won't work!

Even more important:

All CSS must be INLINE and just for basic styling: colours, borders, padding. But no floating and positioning. CSS layouts won't work consistently across devices!

Community
  • 1
  • 1
awrigley
  • 13,481
  • 10
  • 83
  • 129
  • Yeh Cheers, Pretty well up on email html, just new to MVC... I have an EmailController that has a Welcome action, would this method sit in that controller? or elsewhere?? – Andy Nov 12 '10 at 11:38
  • @Andy: the health warning is also there for anyone coming later to this. Strictly speaking, this is not application logic so shouldn't be in the Controller. Its not part of the model either. As it is reusable functionality, I would make the method static and put it in a static class in a library project. That way it is reusable across all your applications, just by dropping the dll into the bin folder. – awrigley Nov 12 '10 at 11:48
  • So here I will need to pass through the ControllerContext?? new ViewContext(ControllerContext, view, vdd, new TempDataDictionary(), writer); – Andy Nov 12 '10 at 11:49
  • 1
    At least if you're using Razor, you can do: var view = new RazorViewEngine().FindView(controllerContext, viewName, masterPageName) and then when creating your ViewContext pass view.View in as your second argument, to avoid the physical path issue in finding the view and master page. – DaveD Dec 11 '13 at 17:35
  • so where do you get the controllerContext from if you are using this in a dos application and not an mvc application? – johnstaveley Feb 17 '22 at 05:24
4

You can use MvcView NuGet package to do this! Its simple, just install using install-package MvcMailer and you are done! Use full power of view engine to template, master page, view model and send html emails neatly!

Sohan
  • 3,757
  • 2
  • 24
  • 24