我在搜索问题之前进行了大量搜索,但搜索的越多,我得到的就越混乱。
所以我创建了一个处理程序,我试图得到这样的路径:
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 返回null,所以我无法访问RouteTemplate属性,但我可以 在堆栈深处的列表中查看路径。我找到了许多可以用来获取路径的不同方法,但这些方法也评估为null。我对如何完成如此简单的事情感到有点迷茫。我使用自托管进行开发,但将使用IIS进行部署。
更新1
我忘了把我尝试过的其他东西放在这里:
//NULL
request.GetRouteData();
//EMPTY
request.GetRequestContext().Configuration.Routes.GetRouteData(request).Route.RouteTemplate;
//EMPTY
request.GetConfiguration().Routes.GetRouteData(request).Route.RouteTemplate;
路线工作得很好,但奇怪的是,如果我试图让控制器为这个请求提供服务,我会得到一个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();
所以也许我误解了整个图片,我无法在处理程序之前得到路径模板,该处理程序解决了为请求执行哪个控制器的工作......就是这样吗?
作为参考,这是我正在处理的处理程序:
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;
}
更新3
代码在非自托管环境中运行正常,因此这更像是自托管问题。
答案 0 :(得分:13)
Web Api仍有很多需要改进的地方。找到一种让这种方法发挥作用的方法很棘手,我只希望这可以节省其他人花费我所有时间。
var routeTemplate = ((IHttpRouteData[]) request.GetConfiguration().Routes.GetRouteData(request).Values["MS_SubRoutes"])
.First().Route.RouteTemplate;
答案 1 :(得分:4)
我遇到了类似的问题,但是能够通过以下方式获取消息处理程序中的路径:
request.GetConfiguration()Routes.GetRouteData(请求).Route.RouteTemplate;
答案 2 :(得分:3)
Marco的答案(如下所示)是正确的,只要使用相同的HttpMethod定义的路线不超过一条。 .First()
将获取在该特定ApiController
中定义的第一条路线,但这并不能确保它获得正确的路线。如果您使用ControllerContext
获取路线,则可以确定您拥有所需的确切端点。
Marco的:
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()
不保证你得到一个你想要的。
保证获取正确的端点RouteTemplate
:
public static string GetRouteTemplate(this HttpActionContext actionContext)
{
return actionContext.ControllerContext.RouteData.Route.RouteTemplate;
}
我使用了一种扩展方法,所以你要这样做:
var routeTemplate = actionContext.GetRouteTemplate();
这将确保您从发起呼叫的端点获得特定的RouteTemplate
。
答案 3 :(得分:0)
我认为你可以从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;
}