忽略ASP.NET Web API中的控制器

问题描述 投票:0回答:1

我们的团队维护着一个自托管的ASP.NET Web API。该项目使用属性路由,我们有几十个现有的控制器。比方说,API是通过主路径暴露的 /api/purpose1/... 与所有现有的控制器作为资源放在下面。

现在,我想引入一个新的平行主路径,例如。/api/purpose2/. 应该可以通过配置文件中的一个布尔变量来独立激活两个主路径。

由于所有的控制器都在一个装配体中,属性路由方法总是能找到并将它们添加到两个 purpose1purpose2. 这就违背了 purpose1purpose2. 因此,我使用属性路由的 purpose1 和基于惯例的路由选择 purpose2. 这至少是可行的,但我对两种不同的路由方式的混合不满意。

所以我的问题是:我可以用属性路由禁用某些控制器类吗?

c# asp.net asp.net-web-api asp.net-routing
1个回答
1
投票

OnActionExecuting的例子。

V1控制器

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

V2控制器

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

版本感知基础控制器

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

0
投票

Peter Csala的回答 是不错的,但是,它有一个对 System.Web.Mvc. 在我们的案例中,这个依赖关系之前并不存在,我找到了一个不需要添加它的解决方案。

我扩展了 ApiControllerActionInvoker 办法如下:

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 构造函数的引入是为了支持更简单的单元测试。

下面的代码注册了这个自定义类。

var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Services.Replace(typeof(IHttpActionInvoker), new CustomHttpActionInvoker(MyConfigProvider));
© www.soinside.com 2019 - 2024. All rights reserved.