1

Within an MVC project we have an area with a controller SomeController returning a partial view containing EditorFor statements, each with their own template.

Everything works fine if the controller is invoked directly via a route for that area. However, if it's called via another controller outside of the area, i.e. via 'new SomeController().SomeAction()', the templates are not used, even if explicitly specified (the view is returned ok, but shows just default textboxes etc).

What could be the reason for this and how can it be fixed?

7
  • Where are your templates located (in /Views/Shared/EditorTemplates)? Commented Mar 14, 2016 at 7:34
  • Did you actually initialize the controller after new SomeController()? It needs ControllerContext to work correctly Commented Mar 14, 2016 at 7:34
  • @Stephen Muecke: they are in Area//Views/Some/EditorTemplates and found ok if controller is called directly Commented Mar 14, 2016 at 7:40
  • @haim770: what exactly do you mean? The controller in the area is called using 'new SomeController().SomeAction()', should I pass something else? Commented Mar 14, 2016 at 7:42
  • 1
    If you put them in the /Views/Shared/EditorTemplates folder, they should be found by all controllers. Commented Mar 14, 2016 at 7:45

1 Answer 1

1

When your action is invoked merely using ctrl.Action(), the current RouteData will be used (with the current area/controller/action values in it) and when Razor tries to resolve your EditorTemplates paths it consults the ViewContext that is still containing the (now wrong) values of the originating action.

You better use the ControllerFactory in order to mimic the desired behavior:

var ctrlFactory = ControllerBuilder.Current.GetControllerFactory();

var routeData = new RouteData();
routeData.DataTokens.Add("area", "target_area_name");
routeData.Values.Add("controller", "target_controller_name");
routeData.Values.Add("action", "target_action_name");

var requestContext = new RequestContext(this.HttpContext, routeData);
var ctrl = ctrlFactory.CreateController(requestContext, "target_controller_name") as TargetControllerType;

if (ctrl != null)
{
    ctrl.ControllerContext = new ControllerContext(requestContext, ctrl);

    var ctrlDesc = new ReflectedControllerDescriptor(typeof(TargetControllerType));
    var actionDesc = ctrlDesc.FindAction(ctrl.ControllerContext, "target_action_name");

    var result = actionDesc.Execute(ctrl.ControllerContext, new Dictionary<string, object>()) as ActionResult;

    this.RouteData.DataTokens["area"] = "target_area_name";
    this.RouteData.Values["controller"] = "target_controller_name";
    this.RouteData.Values["action"] = "target_action_name";

    return result;
}

See MSDN

Sign up to request clarification or add additional context in comments.

4 Comments

I'm well impressed by this snippet, it works, too, but sadly the result is the same (templates ignored)
@devlock, Did you fill-in the correct values for area, controller and action?
I believe so, the controller action is executed without problems, just the templates not rendered
@devlock, I have updated the answer. It's now a little less elegant but should work.

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.