It took a while, but I've found a great solution. Keith's solution works for a lot of people, but in certain situations it's not the best, because sometimes you want your application to go through the process of the controller for rendering the view, and Keith's solution just renders the view with a given model I'm presenting here a new solution that will run the normal process.
General Steps:
- Create a Utility class
- Create a Dummy Controller with a dummy view
- In your
aspx
or master page
, call the utility method to render partial passing the Controller, view and if you need, the model to render (as an object),
Let's check it closely in this example
1) Create a Class called MVCUtility
and create the following methods:
//Render a partial view, like Keith's solution
private static void RenderPartial(string partialViewName, object model)
{
HttpContextBase httpContextBase = new HttpContextWrapper(HttpContext.Current);
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Dummy");
ControllerContext controllerContext = new ControllerContext(new RequestContext(httpContextBase, routeData), new DummyController());
IView view = FindPartialView(controllerContext, partialViewName);
ViewContext viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), httpContextBase.Response.Output);
view.Render(viewContext, httpContextBase.Response.Output);
}
//Find the view, if not throw an exception
private static IView FindPartialView(ControllerContext controllerContext, string partialViewName)
{
ViewEngineResult result = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName);
if (result.View != null)
{
return result.View;
}
StringBuilder locationsText = new StringBuilder();
foreach (string location in result.SearchedLocations)
{
locationsText.AppendLine();
locationsText.Append(location);
}
throw new InvalidOperationException(String.Format("Partial view {0} not found. Locations Searched: {1}", partialViewName, locationsText));
}
//Here the method that will be called from MasterPage or Aspx
public static void RenderAction(string controllerName, string actionName, object routeValues)
{
RenderPartial("PartialRender", new RenderActionViewModel() { ControllerName = controllerName, ActionName = actionName, RouteValues = routeValues });
}
Create a class for passing the parameters, I will call here RendeActionViewModel (you can create in the same file of the MvcUtility Class)
public class RenderActionViewModel
{
public string ControllerName { get; set; }
public string ActionName { get; set; }
public object RouteValues { get; set; }
}
2) Now create a Controller named DummyController
//Here the Dummy controller with Dummy view
public class DummyController : Controller
{
public ActionResult PartialRender()
{
return PartialView();
}
}
Create a Dummy view called PartialRender.cshtml
(razor view) for the DummyController
with the following content, note that it will perform another Render Action using the Html helper.
@model Portal.MVC.MvcUtility.RenderActionViewModel
@{Html.RenderAction(Model.ActionName, Model.ControllerName, Model.RouteValues);}
3) Now just put this in your MasterPage
or aspx
file, to partial render a view that you want. Note that this is a great answer when you have multiple razor's views that you want to mix with your MasterPage
or aspx
pages. (supposing we have a PartialView called Login for the Controller Home).
<% MyApplication.MvcUtility.RenderAction("Home", "Login", new { }); %>
or if you have a model for passing into the Action
<% MyApplication.MvcUtility.RenderAction("Home", "Login", new { Name="Daniel", Age = 30 }); %>
This solution is great, doesn't use ajax call, which will not cause a delayed render for the nested views, it doesn't make a new WebRequest so it will not bring you a new session, and it will process the method for retrieving the ActionResult for the view you want, it works without passing any model
Thanks to Using MVC RenderAction within a Webform