问题
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