0

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.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

3
  • Can you try to initialize controllerContext using constructor: controller.ControllerContext = new ControllerContext(new HttpContextWrapper(httpContextMock), routeData, controller); Commented Apr 8, 2017 at 10:09
  • That code is from my unit test, which is working fine. But probably not exactly what you are looking for. Commented Apr 8, 2017 at 10:11
  • Can you provide code for httpContextMock, please. I would like to try this out. Commented Apr 8, 2017 at 10:11

2 Answers 2

1

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
Sign up to request clarification or add additional context in comments.

5 Comments

I am receiving 'The method or operation is not implemented'. Although the 'Action' with name given is implemented on controller.
Post your stacktrace
I've pasted into my question.
Thanks for answer. It helped me find a solution.
Yes, it works now. The trick was in passing HttpContext.Current from ASP to MVC.
0

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

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.