21

I am trying to use the accepted answer from this question.

It seems that it will be exactly what i am looking for, but i have a problem. I don't know how to actually call it. This is what i have so far:

First i am copying the code from the solution i mentioned:

public string ToHtml(string viewToRender, ViewDataDictionary viewData, ControllerContext controllerContext)
{
    var result = ViewEngines.Engines.FindView(controllerContext, viewToRender, null);

    StringWriter output;
    using (output = new StringWriter())
    {
        var viewContext = new ViewContext(controllerContext, result.View, viewData, controllerContext.Controller.TempData, output);
        result.View.Render(viewContext, output);
        result.ViewEngine.ReleaseView(controllerContext, result.View);
    }

    return output.ToString();
}

This is what i have:

string viewToRender = "...";
int Data1 = ...;
int Data2 = ...;

System.Web.Mvc.ViewDataDictionary viewData = new System.Web.Mvc.ViewDataDictionary();
viewData.Add("Data1",Data1);
viewData.Add("Data2",Data2);

string html = ToHtml(viewToRender, viewData, ?????)//Here is my problem.

What should i pass in the controllerContext parameter?

7
  • The controller context is a property of a MVC controller. If you want to get a view of the current Controller you type: this.ControllerContext Commented Aug 26, 2013 at 11:04
  • @Oliver I want to call this method outside of a controller. Is this even possible? If it is, then i would like to define the the controller somehow. How do i do this? Commented Aug 26, 2013 at 11:07
  • I use this helper: public static string RenderPartialViewToString(Controller controller, string viewName, object model) and than I just call controller.ControllerContext. Commented Aug 26, 2013 at 11:17
  • Have you tried to create a new instance of you Controller and than pass the controllerContext to your helper? Commented Aug 26, 2013 at 11:18
  • @Oliver Thanks for the info. If i create a new object it works... Is it possible that i pass it as a string as i do in the ViewToRender? Do i have to use reflection? Commented Aug 26, 2013 at 11:54

3 Answers 3

43

Rather than inherit Controller which means you have to remember to implement this every time, or inherit from a CustomControllerBase, which means you have to remember to inherit every time - simply make an extension method:

public static class ControllerExtensions
{
    public static string RenderView(this Controller controller, string viewName, object model)
    {
        return RenderView(controller, viewName, new ViewDataDictionary(model));
    }

    public static string RenderView(this Controller controller, string viewName, ViewDataDictionary viewData)
    {
        var controllerContext = controller.ControllerContext;

        var viewResult = ViewEngines.Engines.FindView(controllerContext, viewName, null);

        StringWriter stringWriter;

        using (stringWriter = new StringWriter())
        {
            var viewContext = new ViewContext(
                controllerContext,
                viewResult.View,
                viewData,
                controllerContext.Controller.TempData,
                stringWriter);

            viewResult.View.Render(viewContext, stringWriter);
            viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
        }

        return stringWriter.ToString();
    }
}

Then within your Controller you can call like this:

this.RenderView("ViewName", model);
Sign up to request clarification or add additional context in comments.

7 Comments

Nice one I like your approch. Thx mate
And for anyone looking for a partial view, replace FindView with FindPartialView.
How you set viewData? For me, it is null, which throws an error.
Is it possible to call controller action which returns view instead of calling view directly?
@FrenkyB Instead of viewData you can insert controllerContext.Controller.ViewData
|
12

You can create a base controller which obviously extends a controller and use above function in the base controller and other controller which extends this base controller will be able to use it. However the ControllerContext must be used as

Request.RequestContext

And Hence your BaseController will be like

public class BaseController: Controller
{
//your function here
}

And your ToHtml() function will be

protected virtual string ToHtml(string viewToRender, ViewDataDictionary viewData )
{
   var controllerContext=Request.RequestContext;
   var result = ViewEngines.Engines.FindView(controllerContext, viewToRender, null);

   StringWriter output;
   using (output = new StringWriter())
   {
      var viewContext = new ViewContext(controllerContext, result.View, viewData, controllerContext.Controller.TempData, output);
      result.View.Render(viewContext, output);
      result.ViewEngine.ReleaseView(controllerContext, result.View);
   }

   return output.ToString();
}

And on using the base controller

public class MyController: BaseController
{
//ToHtml(...);
}

5 Comments

Thanks! Do you know, how I can add Model object to render view?
I found :) ViewData.Model = obj;.
What to send in viewdata? I'm not getting it.
@CodeRider you can send any object, model, primitive value in ViewData from controller and get its value in view. Make sure you use the SAME key to set and get the value, else Null Exception will occur.
Is it possible to specify the controller? Let's say I'm making the request from "Controller 1", but need to retrieve an Action/Result from "Controller 2". (And both controllers inherit the base controller) Is this possible?
4

This is pretty much a copy of dav_i's post except that you have a model with strong typing and also the ability of producing partial views:

Rather than inherit Controller which means you have to remember to implement this every time, or inherit from a CustomControllerBase, which means you have to remember to inherit every time - simply make an extension method:

public static class ControllerExtensions
{
    public static string RenderView<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
    {
        var controllerContext = controller.ControllerContext;
        controllerContext.Controller.ViewData.Model = model;

        // To be or not to be (partial)
        var viewResult = partial ? ViewEngines.Engines.FindPartialView(controllerContext, viewName) : ViewEngines.Engines.FindView(controllerContext, viewName, null);

        StringWriter stringWriter;

        using (stringWriter = new StringWriter())
        {
            var viewContext = new ViewContext(
                controllerContext,
                viewResult.View,
                controllerContext.Controller.ViewData,
                controllerContext.Controller.TempData,
                stringWriter);

            viewResult.View.Render(viewContext, stringWriter);
            viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
        }

        return stringWriter.ToString();
    }
}

Then within your Controller you can call like this (for a full view):

this.RenderView("ViewName", model);

That means you will get the doctype and the HTML element etc too. For partial view use:

this.RenderView("ViewName", model, true);

Comments

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.