Why is it so hard to get route values outside cont

2019-02-25 17:40发布

问题:

I don't understand what's the deal behind this, why is it so easy to get route values inside Request of controller but nearly impossible to do the same thing on HttpContext.Current.Request?

Maybe I just don't know a better way and it exists. Can someone confirm that this is the only way to get route data outside controller?

Example

[Route("{id}"), HttpGet]
public IHttpActionResult Test()
{
    // Simple and easy
    var route1 = Request.GetRouteData().Values["id"];

    // Wat. This is also ~6 times slower
    var routeValues = (IHttpRouteData[]) HttpContext.Current.Request.RequestContext.RouteData.Values["MS_SubRoutes"];
    var route2 = routeValues.SelectMany(x => x.Values).Where(x => x.Key == "id").Select(x => x.Value).FirstOrDefault();

    return Ok(route1 == route2); // true
}

回答1:

Part One:

The answer of the question -

Why is it so easy to get route values inside Request of controller but nearly impossible to do the same thing on HttpContext.Current.Request?

I am not going in all the details of class implementation and others. Lets just consider the responsibility of Model, View and Controller in an MVC architecture. And you can see that only the Controller has the responsibility to map routes to views and vice versa. That is the only part of the MVC architecture that needs the routes. So it can readily be understood that why it is so easy to find route values inside Controller.

Now comes the implementation details. Yeah, of course MS folks have done a great deal of work to make it easily accessible inside a controller, just a simple Property. But if you want it outside controllers you can still have it, but it is a hard work. That is considerable, cause unless you are trying to mess up the abstraction layer of the architecture, you are not gonna need the route outside the controller anyway.

Part Two:

Now comes the second answer -

Can someone confirm that this is the only way to get route data outside controller?

Of course there are other ways. In fact I myself can't understand why are you getting route values by doing so hard work? Aren't you writing your action methods in controllers? If so then why not just use it as parameter? -

[Route("{id}"), HttpGet]
public IHttpActionResult Test(int? id) //the easiest way to get route value for {id}
{
    // Simple and easy
    var route1 = Request.GetRouteData().Values["id"];

    // Wat. This is also ~6 times slower
    var routeValues = (IHttpRouteData[]) HttpContext.Current.Request.RequestContext.RouteData.Values["MS_SubRoutes"];
    var route2 = routeValues.SelectMany(x => x.Values).Where(x => x.Key == "id").Select(x => x.Value).FirstOrDefault();

    return Ok(route1 == route2 == id.Value); // true //should be true, and of course you should add null check since it is int? not int. But that is not significant here so I didn't do it.
}


回答2:

Try the code below to get the route data:

var routeValues = Request.GetRouteData().Values["MS_SubRoutes"];

Note:

The type of Request is System.Net.Http.HttpRequestMessage. It is a property of class System.Web.Http.ApiController, or you can get it from eleswhere.

GetRouteData is an extension method in class System.Net.Http.HttpRequestMessageExtensions.