kvsanagi kvsanagi - 3 months ago 20
ASP.NET (C#) Question

Get string from PartialViewResult WITHOUT .ControllerContext

How can I render a

string
with HTML code from
PartialViewResult
WITHOUT having to use
ControllerContext

(because in my controller object .ControllerContext is
null
, and making fakes nor trying to hack it wasn't working. .ControllerContext isn't
null
from INSIDE of Contorller, but I need to use it OUTSIDE of this Contorller).

public string RenderRazorViewToString(string viewName, object model) {
ViewData.Model = model;
using (var sw = new StringWriter()) {
var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}


(broader explaination)--------------------------------------------------------------------------------

I have tried:


  1. making fakes

  2. trying to call it from anther Controller (success, but I dont have specific .cshtml inside this controller)

  3. trying to make non-null ControllerContext in various, even most stupid ways

  4. just trying to "make plain string" from this
    PartialViewResult
    (.ToString())

  5. Even copy-paste code from 1 Controller to 2nd Controller. It won't work, because I got these controller objects from DependencyRegistrar (IoC), and then I ofc can use them, but they always have null .ControllerContext.



I just have
PartialViewResult
from some
ActionResult
method that have 100% valid and working HTML code.
I had done a hard search toward this topic, but all I found were answers that use ControllerContext (btw. THIS piece
of code is mentioned on at least 20 different websities. I also have this in my project and I have to say, it
works excellent, but I have a
PartialViewResult
outside controller).

Answer

Class ActionFilterAttribute constains a method OnActionExecuted() with one argument of type ActionExecutedContext and name filterContext.

Yes, filterContext already contains initialized and valid .ControllerContext that I was missing.

This attribute can be atached directly to controller, action (only these that returns ActionResult) or indirectly via inheriting IFilterProvider with its one method GetFiltres

public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
    if ((actionDescriptor.ControllerDescriptor.ControllerType == typeof(GemStoneProject.GemStoneController)) &&
        (actionDescriptor.ActionName.Equals("GemStoneAction")) && controllerContext.HttpContext.Request.HttpMethod == "POST")
    {
        return new List<Filter>() { new Filter(this, FilterScope.Action, 0) };
    }

    return new List<Filter>() { };
}


    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
    /*your code, that replaces previous View to new View. 
You have available and valid .ControllerContext inside "filterContext" argument*/
    }

You will need also this line, if you want to all builder.RegisterType().As();

Effect: after execution of GemStoneAction, the OnActionExecuted will be called. With valid .ControllerContext of GemStoneController.

Comments