我需要一个自定义的IHttpControllerSelector,它只应用于特定的路由.所有其他Web api路由应使用IHttpControllerSelector的默认实现.
在研究时我发现以下代码意味着在应用程序启动时替换IHttpControllerSelector,但它完全替换了默认的控制器选择器,这导致应用程序中的所有路由都使用我的自定义控制器选择器:
config.Services.Replace(typeof(IHttpControllerSelector),new CustomControllerSelector(config));
有没有办法为单个路由配置IHttpControllerSelector?
解决方法
您可以为需要使用不同控制器选择逻辑的路由分配每路由消息处理程序.此处理程序将使用标记标记HttpRequestMessage,该标记需要以不同方式处理此请求.
然后只需使CustomControllerSelector继承自DefaultHttpControllerSelector并检查该标志:
>如果已设置,请继续使用自定义逻辑
>如果未设置,则返回base(DefaultHttpControllerSelector)
这是代码:
1)消息处理程序,设置标志
public class RouteSpecificHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken) { request.Properties["UseCustomSelector"] = true; return base.SendAsync(request,cancellationToken); } }
2)仅将每个路由消息处理程序分配给特定路由(不要为其他路由运行)
config.Routes.MapHttpRoute( name: "MyRoute",routeTemplate: "api/dummy/{id}",defaults: new {controller = "Dummy",id = RouteParameter.Optional},constraints: null,handler: new RouteSpecificHandler { InnerHandler = new HttpControllerDispatcher(config) } );
3)尊重旗帜的自定义选择器:
public class CustomSelector : DefaultHttpControllerSelector { public CustomSelector(HttpConfiguration configuration) : base(configuration) { } public override HttpControllerDescriptor SelectController(HttpRequestMessage request) { if (request.Properties.ContainsKey("UseCustomSelector") && request.Properties["UseCustomSelector"] as bool? == true) { //your logic goes here } return base.SelectController(request); } }
4)注册选择器:
config.Services.Replace(typeof(IHttpControllerSelector),new CustomSelector(config));
编辑
如果你不希望从DefaultHttpControllerSelector继承 – 那么直接实现IHttpControllerSelector,而不是调用base.SelectController(request)将旧选择器保存为类中的字段/属性
public class CustomSelector : IHttpControllerSelector { private HttpConfiguration _config; public IHttpControllerSelector PrevIoUsSelector {get; set;} public CustomSelector(HttpConfiguration configuration) { _config = configuration; } public override HttpControllerDescriptor SelectController(HttpRequestMessage request) { if (request.Properties.ContainsKey("UseCustomSelector") && request.Properties["UseCustomSelector"] as bool? == true) { //your logic goes here } return PrevIoUsSelector.SelectController(request); } }
然后只需更改注册:
var prevIoUsSelector = config.Services.GetService(typeof(IHttpControllerSelector)) as IHttpControllerSelector; config.Services.Replace(typeof(IHttpControllerSelector),new CustomSelector(config) { PrevIoUsSelector = prevIoUsSelector});