【问题标题】:Ignore controller in ASP.NET Web API忽略 ASP.NET Web API 中的控制器
【发布时间】:2020-05-08 06:22:21
【问题描述】:

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

现在我想介绍一个新的并行主路径,例如。 G。 /api/purpose2/。应该可以通过配置文件中的布尔变量相互独立地激活两个主路径。

由于所有控制器都在一个程序集中,因此属性路由方法总是会找到并将它们添加到purpose1purpose2。这与purpose1purpose2 的独立性相矛盾。所以我对purpose1 使用属性路由,对purpose2 使用基于约定的路由。这至少有效,但我对两种不同路由方法的混合不满意。

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

【问题讨论】:

  • 请检查IControllerActivatorIControllerFactory 接口。实现这些可以让您完全控制控制器的创建。
  • 或者您可以覆盖控制器的OnActionExecuting 方法来检查功能标志。
  • @PeterCsala 谢谢,我会看看这个。我必须实现这两个接口吗?
  • IControllerFactory 应该足够了。我举个例子。
  • 您使用的是哪个 .net core 或 .net framework 版本?

标签: c# asp.net asp.net-web-api asp.net-routing


【解决方案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) { }
}

【讨论】:

  • 看起来不错,我试试这个。但是,我很好奇 IControllerActivatorIControllerFactory 的示例会是什么样子
  • 请查看这两篇文章以获得更好的见解:IControllerActivator, IControllerFactory
【解决方案2】:

Peter Csala's answer 很好,但是它依赖于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));
    }
}

引入了internal 构造函数以支持更轻松的单元测试。

以下代码注册自定义类:

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

【讨论】:

  • 请将此标记为答案以关闭线程。
猜你喜欢
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-23
  • 1970-01-01
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多