Manually pass a url through the modelbinder to obtain the RouteData parameters

一个人想着一个人 提交于 2020-01-24 13:07:43

问题


I have a complex ASP.NET MVC routing scenario and I want to be able to parse a URL that I pull from the 'Referrer' request header using the existing routes.

I have incoming requests that look like this:

http://hostname/{scope}/{controller}/{action}

With corresponding route mapping:

routes.MapRoute( name: "scoped", url: "{scope}/{controller}/{action}/{id}", defaults: new { controller = "Equipment", action = "Index", id = UrlParameter.Optional, scope = "shared" } );

In the OnActionExecuting method of the base class of my controllers I pull the resulting scope from the RouteData:

var scope= (filterContext.RouteData.Values["scope"] as string).ToLower();

I then use the scope to construct some filters for my database queries. It all worked perfectly fine until I moved all my Json-returning methods to a separate set of WebApi2 controllers. I now also have a route:

config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}" );

All ajax requests are now made to the api controllers, which means that I do not have the scope value available. I want to solve this by using the 'Referrer' URL from the request header, which is is usually a URL that does include the scope.

What I would like to do is something like this when the ApiController initializes:

public void PullCurrentScopeDomainFromRequestHeader(System.Net.Http.Headers.HttpRequestHeaders headers) {
    var refererUrl = headers.GetValues("Referer").First();

    //do some magic to get the scope

}

The difficulty is that the scope can also have a default value ("shared"), in case a url like "http://hostname/controller/action" get's passed in. The best (and DRYest) way to get the scope from any URL, would be by somehow using the "scoped" route that I mapped in the routing config to parse the URL somehow. I just have no idea how to do that. Can anyone help?


回答1:


You just need to build up a fake HTTP context based on your URL and then use the static RouteTable to parse the URL into a RouteValueDictionary.

// Create a fake HttpContext using your URL
var uri = new Uri("http://hostname/controller/action", UriKind.Absolute);
var request = new HttpRequest(
    filename: string.Empty,
    url: uri.ToString(),
    queryString: string.IsNullOrEmpty(uri.Query) ? string.Empty : uri.Query.Substring(1));

// Create a TextWriter with null stream as a backing stream 
// which doesn't consume resources
using (var nullWriter = new StreamWriter(Stream.Null))
{
    var response = new HttpResponse(nullWriter);
    var httpContext = new HttpContext(request, response);
    var fakeHttpContext = new HttpContextWrapper(httpContext);

    // Use the RouteTable to parse the URL into RouteData
    var routeData = RouteTable.Routes.GetRouteData(fakeHttpContext);
    var values = routeData.Values;

    // The values dictionary now contains the keys and values
    // from the URL.

    // Key          | Value
    //
    // controller   | controller
    // action       | action
    // id           | {}

}

Note that you can also use a specific route from the RouteTable by specifying its name.

var routeData = RouteTable.Routes["scoped"].GetRouteData(fakeHttpContext);


来源:https://stackoverflow.com/questions/34977352/manually-pass-a-url-through-the-modelbinder-to-obtain-the-routedata-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!