user107986
user107986

Reputation: 1541

No need for separate controllers or actions for each view solution - understanding the code

There are two things I can't grasp in this article. It explains the way to use ASP.NET MVC without the need for separate controllers or actions for each view.

1) In DispatchRequest method:

private void DispatchRequest(IControllerFactory controllerFactory, string controller, string action)
    {
        var route = GetRoute(controller, action);
        _requestContext.RouteData.Values["x-action"] = action;
        _requestContext.RouteData.Values["x-controller"] = controller;

        if (route != null)
        {
            _requestContext.RouteData.Values["controller"] = route.Controller;
            _requestContext.RouteData.Values["action"] = route.Action;

            if (route.Area != string.Empty)
            {
                _requestContext.RouteData.DataTokens["area"] = route.Area;
            }

            controller = route.Controller;

the action and controller strings are stored under "x-action" and "x-controller" keys. A few lines below the controller and action are stored under "controller" and "action" keys.

Both pairs (controller and action) are strings, aren't these pairs the same? It looks to me like they are. Why duplicate the data unnecessarily?

2) In the controller, ControllerLessController :

public virtual ActionResult Index()
    {
        var action = RouteData.Values["x-action"].ToString();
        var controller = RouteData.Values["x-controller"].ToString();
        RouteData.Values["action"] = action;
        RouteData.Values["controller"] = controller;
        if (RouteData.Values["area"] != null)
        {
            RouteData.DataTokens["area"] = RouteData.Values["area"].ToString();
        }

        return View(action);
    }
}

Notice the first two lines in the body. Why invoke toString on string objects? Moreover, why somebody decided to store them in action and controller variables and overwrite the data under "action" and "controller" keys (line 3,4)?

Upvotes: 1

Views: 253

Answers (1)

rism
rism

Reputation: 12132

  1. Both pairs (controller and action) are strings, aren't these pairs the same? It looks to me like they are. Why duplicate the data unnecessarily?

No. The intent is to store the original request values in "x-action", "x-controller" and then overwrite "action", "controller" as necessary while still having access to the original values at a later stage in processing. "x-action", "x-controller" are simply being used as temp vars. They are being stored in RouteData because once the dispatch method completes any local vars will go out of scope.

  1. Notice the first two lines in the body. Why invoke toString on string objects?

RouteData.Values returns an object via a string indexer hence the ToString. i.e. RouteData.Values["MyValue"] returns an object not a string.

Moreover, why somebody decided to store them in action and controller variables and overwrite the data under "action" and "controller" keys (line 3,4)?

This goes back to the TempData idea in 1. An action request comes in. Normally in MVC that would translate to a controller with a view but here in this controller-less example controller-less actions need to be mapped to the controllerless-handler.

So in DispatchRequest these are overridden to point at the controllerless handler class ControllerLessController : Controller.

Note this is happening prior to controller selection.

Then MVC processes the request in the normal fashion but because of the switching around in Dispatch MVC doesn't go looking for the originally requested controller (since there wasn't one) instead it uses the injected controller-less controller:

_requestContext.RouteData.Values["action"] = _configuration.DefaultAction;
controller = _configuration.DefaultController;

So then the normal request processing carries on and lands within the controllerless controller. At that point we need to reach back and find which view was originally requested.

public virtual ActionResult Index()
    {
        var action = RouteData.Values["x-action"].ToString();
        var controller = RouteData.Values["x-controller"].ToString();
        RouteData.Values["action"] = action;
        RouteData.Values["controller"] = controller;
        if (RouteData.Values["area"] != null)
        {
            RouteData.DataTokens["area"] = RouteData.Values["area"].ToString();
        }

        return View(action);
    }

This info was stored in the "x-action" routes values so they pull that out and return a view for the original request:

return View(action);

where

var action = RouteData.Values["x-action"].ToString();

Basically you just have a layer of re-direction/interception. We re-direct all actions without controllers to some handler, in this case the ControllerLessController. Before we do that we need to store the original request params in "x-action" vars. Then once in the ControllerLessController handler we pull those original values back out so we can produce a view for the original controller request.

Upvotes: 1

Related Questions