I have MVC controller with action that returns partial view. Action contains a lot of logic and sends data in view through ViewBag object.
I need to render result of this action into string and then send as email. All solutions that I found render view without action calling.
Is it possible to init controller somewhere in my code, call action method and transform ActionResult (that is partial view) into string?
Thx
I did it. With a lot of pain.
At first we need to init controller without context. For this I use Rick Strahl's method called CreateController
public static T CreateController<T>(RouteData routeData = null)
where T : Controller, new()
{
// create a disconnected controller instance
T controller = new T();
// get context wrapper from HttpContext if available
HttpContextBase wrapper = null;
if (HttpContext.Current != null)
wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
else
throw new InvalidOperationException(
"Can't create Controller Context if no active HttpContext instance is available.");
if (routeData == null)
routeData = new RouteData();
// add the controller routing if not existing
if (!routeData.Values.ContainsKey("controller") && !routeData.Values.ContainsKey("Controller"))
routeData.Values.Add("controller", controller.GetType().Name
.ToLower()
.Replace("controller", ""));
controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
return controller;
}
But if you call this method when HttpContext it will throw exception. To prevent I init fake context using this code: https://stackoverflow.com/a/19709225/1850880.
Then I init controller and call action. Result of this action contain viewData with all data passed from action. We can get it with reflection (like a ninja). And then we can render view to string with passed model.
var controller = CreateController<ControllerName>();
var result = controller.ActionName(param1, param2);
object viewData = result.GetType().GetProperty("ViewData").GetValue(result);
object values = viewData.GetType().GetProperty("Values").GetValue(viewData);
var str = ec.RenderRazorViewToString("ViewName", values);
return str;
This method render view to string:
public static string RenderRazorViewToString(this Controller controller, string viewName, object model)
{
controller.ViewData.Model = model;
controller.ViewBag.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
Looks like it's not the best way but it works. So if you have any ideas be sure to write.