简体   繁体   中英

Ignore controller in ASP.NET Web API

Our team maintains a self-hosted ASP.NET Web API. The project uses attribute routing and we have dozens of existing controllers. Lets say, the API is exposed via the main path /api/purpose1/... with all the existing controllers being placed as resources underneath.

Now I want to introduce a new parallel main path, eg /api/purpose2/ . It should be possible to activate both main paths independently of each other via a boolean variable in a config file.

Since all the controllers are within one assembly, the attribute routing approach always finds and adds them to both purpose1 and purpose2 . This contradicts the independency of purpose1 and purpose2 . So I used attribute routing for purpose1 and convention-based routing for purpose2 . That at least worked, but I'm not happy with the mixture of two different routing approaches.

So my question is: can I disable certain controller classes with attribute routing?

OnActionExecuting example:

V1 controller

[Route("api/[controller]")]
[ApiController]
public class SampleV1Controller : VersioningAwareControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return new OkObjectResult("V1");
    }
}

V2 controller

[Route("api/[controller]")]
[ApiController]
public class SampleV2Controller : VersioningAwareControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return new OkObjectResult("V2");
    }
}

Versioning aware base controller

public abstract class VersioningAwareControllerBase: ControllerBase, IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        if (!FeatureFlags.ShouldDeprecateV1 ||
            !string.Equals(context.RouteData.Values["controller"].ToString(), "samplev1",
                StringComparison.OrdinalIgnoreCase))
            return;

        context.Result = NotFound();
        context.Canceled = true;
    }

    public void OnActionExecuting(ActionExecutingContext context) { }
}

Peter Csala's answer is fine, however, it has a dependency to System.Web.Mvc . In our case, this dependency wasn't there before and I found a solution that does not require adding it.

I've extended ApiControllerActionInvoker the following way:

internal class CustomHttpActionInvoker : ApiControllerActionInvoker
{
    public CustomHttpActionInvoker(IConfigProvider configProvider)
    {
        ConfigProvider = configProvider;
        InvokeActionFunc = base.InvokeActionAsync;
    }

    /// <summary>FOR AUTOMATED TESTS ONLY</summary>
    internal CustomHttpActionInvoker(IConfigProvider configProvider,
                                     Func<HttpActionContext, CancellationToken, Task<HttpResponseMessage>> invokeActionFunc)
    {
        ConfigProvider = configProvider;
        InvokeActionFunc = invokeActionFunc;
    }

    private IConfigProvider ConfigProvider { get; }

    private Func<HttpActionContext, CancellationToken, Task<HttpResponseMessage>> InvokeActionFunc { get; }

    /// <inheritdoc />
    public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        var isRelevantRequest = actionContext.ControllerContext.Controller is MyRelevantController;
        if (isRelevantRequest && ConfigProvider.IsPurpose1)
        {
            return InvokeActionFunc(actionContext, cancellationToken);
        }

        if (!isRelevantRequest && ConfigProvider.IsPurpose2)
        {
            return InvokeActionFunc(actionContext, cancellationToken);
        }

        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound));
    }
}

The internal constructor was introduced to support easier unit testing.

The following code registers the custom class:

var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Services.Replace(typeof(IHttpActionInvoker), new CustomHttpActionInvoker(MyConfigProvider));

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