views:

446

answers:

3

Is it possible for an ASP.NET MVC controller to create a new instance of a different controller and effectively delegate resonsibility to that?

Let's say for example that I have two controllers in the /Controllers/ directory:

public class HomeController : Controller
{
    public ActionResult Index()
    {
            var otherController = new OtherController();
            return otherController.ShowNumberOfThings(100);
    }
}

public class OtherController : Controller
{
        public ActionResult ShowNumberOfThings(int index)
        {
            return View(index);
        }
}

...and a View called Views/Other/ShowNumberOfThings.aspx:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="ViewPage<int>" %>
Number of things: <%= Model.ToString() %>

When I hit the url:

http://localhost/Home/Index

I want to be presented with a page that reads:

"Number of things: 100"

I would like to be able to persist temporary data between controller redirections without being forced to use the session object (TempData[""] uses the session object for cross-controller redirections). My real world case has a complex object which needs passing (not just an int) so using a URL/Cookie is out of the question, and session state is a no-no.

In WebForms at least we could use Server.Transfer and maintain any state in the HttpContext.Items collection. In MVC the only option I can see is to call the controller method directly passing in required arguments.

At the moment it's having trouble trying to resolve the view folder as the "context" is still running under the HomeController.

I guess where I am going with this is trying to cludge ASP.NET MVC into acting like a FrontContoller.

Any ideas?

EDIT

In the end we had to serialise everything into a session and use that. A shame, but I have heard that MVC2 will support serialising objects into a ViewState.

+1  A: 

I think it would be preferred to use.

return RedirectToAction("Controller", "Action")

However I'm guessing you want to maintain the Url Home/Index. If you're looking at the FrontController pattern then you should investigate writing a Custom ControllerFactory which inherits from DefaultControllerFactory then Override the CreateController method. You can register your factory using the code below.

    protected void Application_Start()
    {
        ControllerBuilder.Current.SetControllerFactory(new MyCustomControllerFactory();
        RegisterRoutes(RouteTable.Routes);
    }

In the Controller factory you have access to the RequestContext so you can change the RouteData as needed and delegate to the correct controller.

You could of course just set a a Custom route for Home/Index which goes to OtherController.ShowNumberOfThings()

routes.MapRoute("Home", "Home/Index/{id}",
                            new {controller = "Other", action = "ShowNumberOfThings", id = 100});
willbt
I can't use RedirectToAction as this results in two HTTP requests.In my situation I need to pass a complex object, not an int, so I can't really serialise it into a querystring (route) parameter.Nice answer though.
Codebrain
+2  A: 

If you want to be presented with "Number of things: 100" when you hit the Index action why not directly render the corresponding view:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View("~Views/Other/ShowNumberOfThings.aspx", 100);
    }
}
Darin Dimitrov
+1  A: 

a different approach would be the use of partial views

instead of ~Views/Other/ShowNumberOfThings.aspx

you could put your view in ~Views/shared/ShowNumberOfThings.ascx

have both views ~Views/Other/ShowNumberOfThings.aspx and ~Views/Home/Index.aspx implement the partial view

public class HomeController : Controller
{
    public ActionResult Index()
    {
            return View(100);
    }
}

public class OtherController : Controller
{
        public ActionResult ShowNumberOfThings(int index)
        {
            return View(index);
        }
}

and in both views implement the partial view

<% Html.RenderPartial("~Views/shared/ShowNumberOfThings.ascx", ViewData.Model); %>

you can change the int for any object that will be passed to the model

freddoo