You can assign a per-route message handler to the route that needs to use a different controller selection logic. This handler would mark the HttpRequestMessage
with a flag that this request needs to be treated differently.
Then simply make the CustomControllerSelector
inherit from DefaultHttpControllerSelector
and inspect that flag:
- if it's set, continue with your custom logic
- if it's not set, return to base (
DefaultHttpControllerSelector
)
Here is the code:
1) message handler, setting the flag
public class RouteSpecificHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Properties["UseCustomSelector"] = true;
return base.SendAsync(request, cancellationToken);
}
}
2) assigning per route message handler to the specific route only (do not run for other routes)
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) custom selector respecting the flag:
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) registering the selector:
config.Services.Replace(typeof(IHttpControllerSelector), new CustomSelector(config));
edit
If you wish to not inherit from DefaultHttpControllerSelector
- then implement IHttpControllerSelector
directly, and instead of calling the base.SelectController(request)
save the old selector as a field/property in your class
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);
}
}
Then just change the registration:
var previousSelector = config.Services.GetService(typeof(IHttpControllerSelector)) as IHttpControllerSelector;
config.Services.Replace(typeof(IHttpControllerSelector), new CustomSelector(config) { PreviousSelector = previousSelector});