Пользовательский IHttpControllerSelector ASP.NET Web API для одного маршрута
Мне нужен кастом IHttpControllerSelector
который должен применяться только к конкретному маршруту. Все остальные маршруты веб-API должны использовать реализацию по умолчанию IHttpControllerSelector
,
Во время исследования я обнаружил следующий код, предназначенный для замены IHttpControllerSelector при запуске приложения, но он полностью заменяет селектор контроллера по умолчанию, в результате чего все маршруты в приложении используют мой пользовательский селектор контроллера:
config.Services.Replace(typeof(IHttpControllerSelector),
new CustomControllerSelector(config));
Есть ли способ настроить IHttpControllerSelector
для одного маршрута?
1 ответ
Вы можете назначить обработчик сообщений для маршрута для маршрута, который должен использовать другую логику выбора контроллера. Этот обработчик пометит HttpRequestMessage
с флагом, что этот запрос нужно обрабатывать по-разному.
Тогда просто сделай CustomControllerSelector
наследовать от DefaultHttpControllerSelector
и осмотрите этот флаг:
- если он установлен, продолжайте с вашей собственной логикой
- если он не установлен, вернитесь на базу (
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});