2

I need to generate html (for the body of an email message) specific to a Customer object
I thought of making a View that gets a Customer object and renders the appropriate text.

Is there a way to call a view and get the rendered output without associating it to a controller action?

Ideally in pseydocode I would do something like this

customer = new Customer();
view = new GetCustomerEmailBodyView(customer);
string htmlBody = view.SomeFunctionToRenderViewAndGetOutput()

I have found a solution to get the HTML of a view here that has an action returning a StringResult (inherits from ViewResult) instead of ActionResult which exposes an Html property.
However I still have to make a custom action to call it, and I don't like the fact that it depends on the ControllerContext making it hard to test it.

Is what I am requesting against the MVC principals? How should my code be structured for this scenario?

2 Answers 2

3

Original code from here

protected string RenderPartialViewToString(string viewName, object model) {
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");
    ViewData.Model = model;
    using (StringWriter sw = new StringWriter()) {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
        ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Are you saying that you want some program to be able to leverage a View without being in a controller context at all, or are you saying that you want to be able to render a view into a string from within a controller, without calling some other controller?

For the former, I can't be of much assistance, but for the latter, we have this method in the base controller type that we inherit with all our other controllers:

    /// <summary>
    /// Generates a string based on the given PartialViewResult.
    /// </summary>
    /// <param name="partialViewResult"></param>
    /// <returns></returns>
    protected internal string RenderPartialViewToString(ViewResultBase partialViewResult)
    {
        Require.ThatArgument(partialViewResult != null);
        var context = ControllerContext;
        Require.That(context != null);
        using (var sw = new StringWriter())
        {
            if (string.IsNullOrEmpty(partialViewResult.ViewName))
            {
                partialViewResult.ViewName = context.RouteData.GetRequiredString("action");
            }
            ViewEngineResult result;
            if (partialViewResult.View == null)
            {
                result = partialViewResult.ViewEngineCollection.FindPartialView(context, partialViewResult.ViewName);
                Require.That(result.View != null,
                             () => new InvalidOperationException(
                                       "Unable to find view. Searched in: " +
                                       string.Join(",", result.SearchedLocations)));
                partialViewResult.View = result.View;
            }

            var view = partialViewResult.View;
            var viewContext = new ViewContext(context, view, partialViewResult.ViewData,
                                              partialViewResult.TempData, sw);
            view.Render(viewContext, sw);
            return sw.ToString();
        }
    }

Usage:

public ActionResult MyAction(...) 
{
    var myModel = GetMyModel(...);
    string viewString = RenderPartialViewToString(PartialView("MyView", myModel));
    // do something with the string
    return someAction;
}

We actually use this in an event-based AJAX model, where most of our actions actually just return an AJAX-encoded list of client-side events, and some of those client-side events may be to update a particular DOM element with the string produces by rendering this partial view.

6 Comments

I like the Require.That() syntax - is that something you wrote yourself, or is it part of a (publicly available) library?
We wrote the "Require" class ourselves. I wanted to use Contract.Requires, but it adds a lot of overhead. I copied most of this code out of RenderPartial using the .NET Reflector, and then tweaked it to fit our needs.
Wow, I never thought I'd get so much response from Require.That. Should I see if I can convince my boss to make an open-source library out of it?
At the very least, could the relevant portions of it be placed here? Without them, the code above isn't integratable without writing our own routines to replace it.
@vapcguy: Require.That() is really simple, and could be replaced with a simple if(!...) throw new Exception(...) statement.. gist.github.com/j2jensen/11377210
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.