简体   繁体   中英

Calling MVC view from asp.net class throws exception

I would like to get HTML of the MVC view. Call is being made from ASCX.CS class. (I am trying to inject MVC View to ASPX page). My ASPX page is created dynamically (controls are added from code behind).

I've found part of the answer here . The only problem is that this extension method is made for MVC controller class.

What I do in my call from ASCX.CS:

 fCatEve.Controllers.ASPXTestController test = new Controllers.ASPXTestController();
      string htmlView = test.RenderView("Index", null);

In this action the only problem I have is ControllerContext . I don't know how to set this class, so it will find partial view that I am looking for.

Here are methods I am using (from page mentioned above):

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)
    {
        RouteData routeData = new RouteData();
  routeData.Values.Add("controller", controller);
  var controllerContext = new ControllerContext { Controller = controller, RouteData = routeData };

  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();
    }
}

The exception is:

The RouteData must contain an item named 'controller' with a non-empty string value.

After trying first answer, here is stack trace of exception:

at System.Web.HttpContextBase.get_Items() at System.Web.WebPages.DisplayModeProvider.GetDisplayMode(HttpContextBase context) at System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations) at System.Web.Mvc.VirtualPathProviderViewEngine.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache) at System.Web.Mvc.ViewEngineCollection.<>c__DisplayClass6.b__4(IViewEngine e) at System.Web.Mvc.ViewEngineCollection.Find(Func`2 lookup, Boolean trackSearchedPaths) at System.Web.Mvc.ViewEngineCollection.FindView(ControllerContext controllerContext, String viewName, String masterName) at fCatEve.Helpers.ControllerExtensions.RenderView(Controller controller, String viewName, ViewDataDictionary viewData) in C:\\ProjectsG_Test - KOPIJA\\fCatEve03\\Solution \\fCatEve\\fCatEve\\Helpers\\ControllerExtensions.cs:line 43 at fCatEve.Controls.KoledarReception.PutValuesToTabControlEVEBEVEN(Panel paControl, REFields REField) in C:\\ProjectsG_Test - KOPIJA\\fCatEve03\\Solution\\fCatEve\\fCatEve\\wf\\Controls\\KoledarReception.ascx.cs:line 2747 at fCatEve.Controls.KoledarReception.PutValuesToTabControl() in C:\\ProjectsG_Test - KOPIJA\\fCatEve03\\Solution\\fCatEve\\fCatEve\\wf\\Controls\\KoledarReception.ascx.cs:line 2710 at fCatEve.Controls.KoledarReception.Page_Load(Object sender, EventArgs e) in C:\\ProjectsG_Test - KOPIJA\\fCatEve03\\Solution\\fCatEve\\fCatEve\\wf\\Controls\\KoledarReception.ascx.cs:line 817 at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequ estMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

Here is a sample code I use for one of my unit test that is supposed to generate a PDF file, not sure if it has any benefits to you.

var controller = new MyAwesomePdfController();

var httpRequest = new HttpRequest("", "http://mySomething", "");
var stringWriter = new StringWriter();
var httpResponse = new HttpResponse(stringWriter);
var routeData = new RouteData();
routeData.Values.Add("Controller", "MyAwesomePdf");  //must match your Controller name
routeData.Values.Add("Action", "Receipt");  //must match your Action name

var httpContextMock = new HttpContext(httpRequest, httpResponse)
{
    //this is probably irrelevant to you, can set user principal here
    //User = new GenericPrincipal(
    //  new GenericIdentity(username),
    //  userRoles //new string[0]
    //)
};

controller.ControllerContext = new ControllerContext(new HttpContextWrapper(httpContextMock), routeData, controller);

var receiptId = 1234;
var pdfResult = await controller.Receipt(receiptId) as ViewAsPdf;  //should return a pdf file

I rewrote the call (most important: HttpContext.Current, which is later used in MVC):

fCatEve.Controllers.ASPXTestController test = new Controllers.ASPXTestController();
      string htmlView = test.RenderView("Index", null, HttpContext.Current);

I also slightly rewrote both methods:

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


    public static string RenderView(this Controller controller, string viewName, ViewDataDictionary viewData, HttpContext currentContext)
    {
      var routeData = new RouteData();
      routeData.Values.Add("Controller", "ASPXTest");  //must match your Controller name
      routeData.Values.Add("Action", "Test");  //must match your Action name

      HttpContextWrapper wrapper = new HttpContextWrapper(currentContext);
      controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
      var viewResult = ViewEngines.Engines.FindView(controller.ControllerContext, viewName, null);

      StringWriter stringWriter;
      viewData = new ViewDataDictionary();


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

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

      return stringWriter.ToString();
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM