C# 4.0 web api从内部处理程序获取路由模板
在把问题放在这里之前我搜索了很多,但是搜索得越多,我就越困惑 因此,我创建了一个处理程序,并尝试获得如下路径:C# 4.0 web api从内部处理程序获取路由模板,c#-4.0,asp.net-web-api,asp.net-web-api2,asp.net-web-api-routing,C# 4.0,Asp.net Web Api,Asp.net Web Api2,Asp.net Web Api Routing,在把问题放在这里之前我搜索了很多,但是搜索得越多,我就越困惑 因此,我创建了一个处理程序,并尝试获得如下路径: public class ExecutionDelegatingHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
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;
}
}
}
这个路由运行得很好,但奇怪的是,如果我试图让控制器为这个请求提供服务,我会得到一个404。。。如果我跳过这一步,我会很好地到达控制器
HttpControllerDescriptor httpControllerDescriptor = request.GetRequestContext().Configuration.Services.GetHttpControllerSelector().SelectController(request);
IHttpController httpController = httpControllerDescriptor.CreateController(request);
我使用autofac来发现我定义的所有路线,就像:
[Route("queries/organization/clients")]
[HttpGet]
public ClientInitialScreenModel GetClients()
{
return OrganizationModelsBuilder.GetClientInitialScreen();
}
更新2
如果在上述行之后调用GetRouteData,则我能够获取路由模板:
base.SendAsync(request, cancellationToken);
var routeData = request.GetRouteData();
所以,也许我误解了整个情况,在解析为请求执行哪个控制器的处理程序开始工作之前,我无法获得路由模板。。。是这样吗
作为参考,这是我正在处理的处理程序:
公共类ExecutionDelegatingHandler:DelegatingHandler
{
受保护的覆盖任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
var securityAuthority=(ISecurityAuthority)request.GetDependencyScope().GetService(typeof(ISecurityAuthority));
var配置=(IWebAppConfiguration)request.GetDependencyScope().GetService(typeof(IWebAppConfiguration));
var tsc=new TaskCompletionSource();
var httpResponseMessage=新httpResponseMessage();
if(request.RequestUri.AbsolutePath.Equals(configuration.CommandGatewayUrl、StringComparison.InvariantCultureIgnoreCase))
{
var apiMessage=JsonConvert.DeserializeObject(request.Content.ReadAsStringAsync().Result);
if(securityAuthority!=null&!securityAuthority.VerifyPermissionToExecute(apiMessage,request.Headers))
{
httpResponseMessage.StatusCode=HttpStatusCode.Unauthorized;
}
其他的
{
var messageProcessor=(IWebApiMessageProcessor)request.GetDependencyScope().GetService(typeof(IWebApiMessageProcessor));
var-reponse=messageProcessor.HandleRequest(apiMessage);
httpResponseMessage.StatusCode=(HttpStatusCode)reponse.StatusCode;
如果(!string.IsNullOrEmpty(response.Content))
{
httpResponseMessage.Content=新的StringContent(reponse.Content);
}
}
}
其他的
{
if(securityAuthority!=null&!securityAuthority.VerifyPermissionToExecute(request.GetRouteData().Route.RouteTemplate,request.Headers))
{
httpResponseMessage.StatusCode=HttpStatusCode.Unauthorized;
}
其他的
{
返回base.sendaync(请求、取消令牌);
}
}
tsc.SetResult(httpResponseMessage);
返回tsc任务;
}
更新3
代码在非自托管环境中运行良好,因此这更像是一个自托管问题。Web Api仍有很多改进。找到一种方法使其工作起来很困难,我只是希望这可以避免其他人花费我所有的时间
var routeTemplate = ((IHttpRouteData[]) request.GetConfiguration().Routes.GetRouteData(request).Values["MS_SubRoutes"])
.First().Route.RouteTemplate;
我也遇到了类似的问题,但通过以下方法可以在消息处理程序中获取路由: request.GetConfiguration().Routes.GetRouteData(request.Route.RouteTemplate;来自Marco(如下所示)的答案是正确的,只要使用相同的HttpMethod定义的路由不超过一个。
.First()
将获取在特定的ApiController
中定义的第一条路由,但这并不确保它获取正确的路由。如果使用ControllerContext
获取路由,您可以确保获得了所需的确切端点
马可:
var routeTemplate = ((IHttpRouteData[])request.GetConfiguration()
.Routes.GetRouteData(request).Values["MS_SubRoutes"])
.First().Route.RouteTemplate;
守则:
((IHttpRouteData[])request.GetConfiguration()
.Routes.GetRouteData(request).Values["MS_SubRoutes"])
实际上,返回一个IHttpRouteData
的集合,它包含每个端点的一条记录,这些端点具有相同的HttpMethod(Post、Get等)..First()
不能保证您得到想要的端点
保证获取正确端点的路由模板
:
public static string GetRouteTemplate(this HttpActionContext actionContext)
{
return actionContext.ControllerContext.RouteData.Route.RouteTemplate;
}
我使用了一个扩展方法来调用它,您可以这样做:
var routeTemplate = actionContext.GetRouteTemplate();
这将确保您从进行调用的端点获取特定的
RouteTemplate
。我认为您可以从request.Properties属性和易于单元测试中获取路由数据
/// <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;
}
//
///获取给定请求的值,如果不可用,则为null。
///
///HTTP请求。
///无效或无效。
公共静态IHttpRouteData GetRoutedData(此HttpRequestMessage请求)
{
if(请求==null)
{`在这里输入代码`
抛出错误。ArgumentNull(“请求”);
}
return request.GetProperty(HttpPropertyKeys.HttpRouteDataKey);
}
私有静态GetT属性(此HttpRequestMessage请求,字符串键)
{
T值;
request.Properties.TryGetValue(key,out值);
返回值;
}
还没有测试过这个问题,但至少可以说这很奇怪,但无论如何,很多事情都没有正确完成,我只是希望ASP.Net vNext能够修复。很抱歉,我错过了答案。你的代码可以工作,我指的是@Shivan ahmady的另一个答案。好吧,因为我发现我的代码为什么不能在基本c上工作真的很奇怪ontroller.对我来说非常有用;添加到DelegatingHandler以记录所有正在使用的路由非常有用,因此您可以通过数据驱动决定哪些API终结点可以被淘汰,而不会导致太多破坏性的更改。是的,我也这样做。我还使用委托进行访问验证。角色由多个组成路线,这样我就可以控制对每条路线的访问。
var routeTemplate = actionContext.GetRouteTemplate();
/// <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;
}