tags:

views:

26

answers:

2

I want to render some HTML to use in an e-mail. I have a collection of objects that represent rows and columns, so I could be rendering the HTML in pure C# code using a StringBuilder.

But I prefer to have a ViewUserControl or just a ViewPage in a class library, that does the rendering. I want to be able to use the ViewUserControl and the rendering metho*strong text*d from outside an ASP.NET MVC app, e.g. a Windows Service.

How can I render a View from a class library?

I tried this, but the call to RenderPartial throws a NullReferenceException.

[TestMethod]
public void RenderViewToString()
{
string viewName = "EmailTest";
string viewData = "martin";

//Create memory writer 
var sb = new StringBuilder();
var memWriter = new StringWriter(sb);

//Create fake http context to render the view 
var fakeResponse = new HttpResponse(memWriter);
var fakeContext = new HttpContext(new HttpRequest("fake.html", "http://localhost/fake.html", ""), fakeResponse);
var fakeRouteData = new RouteData();
fakeRouteData.Values.Add("Controller", "Fake");
var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeContext), fakeRouteData, new FakeController());

HttpContext.Current = fakeContext;

//Use HtmlHelper to render partial view to fake context 
var html = new HtmlHelper(new ViewContext(fakeControllerContext, new FakeView(), new ViewDataDictionary(), new TempDataDictionary(), memWriter), new ViewPage());

html.RenderPartial(viewName, viewData);

//Flush memory and return output 
memWriter.Flush();

var htmlString = sb.ToString();

}

A: 

Try this:

public static string RenderPartialToString(string controlName, object viewData)
{
    ViewDataDictionary vd = new ViewDataDictionary(viewData);
    ViewPage vp = new ViewPage { ViewData = vd };
    Control control = vp.LoadControl(controlName);

    vp.Controls.Add(control);

    StringBuilder sb = new StringBuilder();
    using (StringWriter sw = new StringWriter(sb))
    {
        using (HtmlTextWriter tw = new HtmlTextWriter(sw))
        {
            vp.RenderControl(tw);
        }
    }
    return sb.ToString();
}
Darin Dimitrov
vp.LoadControl throws the null reference exception now. I guess that is because there's no VirtualPathProvider...
MartinHN
The HostingEnvironment.VirtualPathProvider is null, so I might need to register one?
MartinHN
Where are you running this code? Is it in an ASP.NET MVC application?
Darin Dimitrov
No. Right now I run it from a Test project. I want to run it from a Windows Service.
MartinHN
Ahhh, ok. This should have been made clear in your question because well it changes everything :-) Using WebForms outside of an ASP.NET HttpContext is a PITA.
Darin Dimitrov
Oohh... Sorry :)
MartinHN
I wondered if I could mock the HttpContext, and render the View then? I have some HtmlHelper tests that does that.
MartinHN
Here you don't need to mock it. You need a real one if you want your views to render.
Darin Dimitrov
Ok. I think I'll ditch the idea, and render my HTML in C#.
MartinHN
@MartinHN you can mock it, but you need to start an app domain with certain caractheristics / I'll post code to my answer when I can get back.
eglasius
A: 

The issue you are getting is with the asp.net engine, which is what the default view engine uses.

You can avoid it by using a different view engine, like spark.

Another option is to use similar to your code, but starting an asp.net appdomain / I'll share some code that does so in a couple of days.

eglasius