Web api get route pattern from internal handler

I searched a lot before asking questions here, but the more I searched, the more I got confused.

So, I created a handler, and I'm trying to get the route as follows:

public class ExecutionDelegatingHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (securityAuthority.VerifyPermissionToExecute(request.GetRouteData().Route.RouteTemplate, request.Headers)) { return base.SendAsync(request, cancellationToken); } else { httpResponseMessage.StatusCode = HttpStatusCode.Unauthorized; } } } 

GetRouteData returns null, so I cannot get the RouteTemplate property, but I can see the route there in the list at the bottom of the stack. I found so many different ways that you can use to get the route, but these methods are also rated as null. I lost a little how to make something so simple. I use the host itself for development, but I will use IIS for deployment.

UPDATE 1

I forgot to put here what else I tried:

 //NULL request.GetRouteData(); //EMPTY request.GetRequestContext().Configuration.Routes.GetRouteData(request).Route.RouteTemplate; //EMPTY request.GetConfiguration().Routes.GetRouteData(request).Route.RouteTemplate; 

The route works just fine, but if it’s strange, if I try to get the controller to serve this request, I get 404 ... if I just stepping over, I just get to the controller.

 HttpControllerDescriptor httpControllerDescriptor = request.GetRequestContext().Configuration.Services.GetHttpControllerSelector().SelectController(request); IHttpController httpController = httpControllerDescriptor.CreateController(request); 

I use autofac to detect all the routes that I define like this:

 [Route("queries/organization/clients")] [HttpGet] public ClientInitialScreenModel GetClients() { return OrganizationModelsBuilder.GetClientInitialScreen(); } 

UPDATE 2

If I GetRouteData is called after the line above, I can get the route pattern:

 base.SendAsync(request, cancellationToken); var routeData = request.GetRouteData(); 

So, maybe I misunderstood the whole picture, and I can’t get the route pattern before the handler, which decides which controller to execute for the request, does its job ... is that the case?

For reference, this is the handler I'm working on:

 public class ExecutionDelegatingHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var securityAuthority = (ISecurityAuthority) request.GetDependencyScope().GetService(typeof (ISecurityAuthority)); var configuration = (IWebApiConfiguration)request.GetDependencyScope().GetService(typeof(IWebApiConfiguration)); var tsc = new TaskCompletionSource<HttpResponseMessage>(); var httpResponseMessage = new HttpResponseMessage(); if (request.RequestUri.AbsolutePath.Equals(configuration.CommandGatewayUrl, StringComparison.InvariantCultureIgnoreCase)) { var apiMessage = JsonConvert.DeserializeObject<ApiCommandEnvelope>(request.Content.ReadAsStringAsync().Result); if (securityAuthority != null && !securityAuthority.VerifyPermissionToExecute(apiMessage, request.Headers)) { httpResponseMessage.StatusCode = HttpStatusCode.Unauthorized; } else { var messageProcessor = (IWebApiMessageProcessor)request.GetDependencyScope().GetService(typeof(IWebApiMessageProcessor)); var reponse = messageProcessor.HandleRequest(apiMessage); httpResponseMessage.StatusCode = (HttpStatusCode) reponse.StatusCode; if (!string.IsNullOrEmpty(reponse.Content)) { httpResponseMessage.Content = new StringContent(reponse.Content); } } } else { if (securityAuthority != null && !securityAuthority.VerifyPermissionToExecute(request.GetRouteData().Route.RouteTemplate, request.Headers)) { httpResponseMessage.StatusCode = HttpStatusCode.Unauthorized; } else { return base.SendAsync(request, cancellationToken); } } tsc.SetResult(httpResponseMessage); return tsc.Task; } 

UPDATE 3

The code works fine in an environment without self-hosting, so this is more like a problem with the host itself.

+6
asp.net-web-api asp.net-web-api-routing asp.net-web-api2
source share
4 answers

Web Api still has something to improve. It was hard to find a way to make this work, and I just hope it saves the other guys from spending all the time that I did.

  var routeTemplate = ((IHttpRouteData[]) request.GetConfiguration().Routes.GetRouteData(request).Values["MS_SubRoutes"]) .First().Route.RouteTemplate; 
+11
source share

I had a similar problem, but I was able to get the route inside the message handler as follows:

request.GetConfiguration () Routes.GetRouteData (request) .Route.RouteTemplate ;.

+4
source share

The answer from Marco (shown below) is correct if there is no more than one route defined using the same HttpMethod. The first () will capture the 1st route defined in this particular ApiController, but this does not guarantee that it will capture the correct one. If you use ControllerContext to get the route, you can be sure that you want to get the exact endpoint.

Marco:

 var routeTemplate = ((IHttpRouteData[])request.GetConfiguration() .Routes.GetRouteData(request).Values["MS_SubRoutes"]).First().Route.RouteTemplate; 

((IHttpRouteData []) request.GetConfiguration () .Routes.GetRouteData (request) .Values ​​["MS_SubRoutes"]) actually returns an IHttpRouteData collection and contains an entry for each endpoint that has the same HttpMethod (Post, Get and etc.) .... First () does not guarantee that you will receive the one you need.

Guaranteed capture of the correct RouteTemplate endpoint:

 public static string GetRouteTemplate(this HttpActionContext actionContext) { return actionContext.ControllerContext.RouteData.Route.RouteTemplate; } 

I used the extension method, therefore, to call this:

 var routeTemplate = actionContext.GetRouteTemplate(); 

This ensures that you get a specific RouteTemplate from the endpoint that is causing the call.

+2
source share

I think you can get the route Data from request.Properties and easily to unit test.

 /// <summary> /// Gets the <see cref="System.Web.Http.Routing.IHttpRouteData"/> for the given request or null if not available. /// </summary> /// <param name="request">The HTTP request.</param> /// <returns>The <see cref="System.Web.Http.Routing.IHttpRouteData"/> or null.</returns> public static IHttpRouteData GetRouteData(this HttpRequestMessage request) { if (request == null) {`enter code here` throw Error.ArgumentNull("request"); } return request.GetProperty<IHttpRouteData>(HttpPropertyKeys.HttpRouteDataKey); } private static T GetProperty<T>(this HttpRequestMessage request, string key) { T value; request.Properties.TryGetValue(key, out value); return value; } 

Code Link Link

0
source share

All Articles