简体   繁体   中英

ASP.NET Web API custom IHttpControllerSelector for a single route

I need a custom IHttpControllerSelector which should be applied to a specific route only. All other web api routes should use the default implementation of IHttpControllerSelector .

While researching I found the following code that is meant to replace the IHttpControllerSelector at application start, but it replaces the default controller selector completely, which causes that all routes in the application use my custom controller selector:

config.Services.Replace(typeof(IHttpControllerSelector), 
                                                    new CustomControllerSelector(config));

Is there a way to configure the IHttpControllerSelector for a single route?

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});  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM