Игнорировать контроллер в ASP. NET Web API - PullRequest
1 голос
/ 08 мая 2020

Наша команда поддерживает собственный ASP. NET веб-API. В проекте используется маршрутизация атрибутов, и у нас есть десятки существующих контроллеров. Допустим, API предоставляется через основной путь /api/purpose1/..., а все существующие контроллеры размещаются как ресурсы внизу.

Теперь я хочу представить новый параллельный основной путь, например /api/purpose2/. Должна быть возможность активировать оба основных пути независимо друг от друга с помощью логической переменной в файле конфигурации.

Поскольку все контроллеры находятся в одной сборке, подход маршрутизации атрибутов всегда находит и добавляет их к обоим purpose1 и purpose2. Это противоречит независимости purpose1 и purpose2. Поэтому я использовал маршрутизацию по атрибутам для purpose1 и маршрутизацию на основе соглашений для purpose2. Это, по крайней мере, сработало, но меня не устраивает сочетание двух разных подходов к маршрутизации.

Итак, мой вопрос: могу ли я отключить определенные классы контроллеров с помощью маршрутизации по атрибутам?

Ответы [ 2 ]

1 голос
/ 08 мая 2020

Пример выполнения 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 голосов
/ 11 мая 2020

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

Конструктор internal был введен для поддержки более простого модульного тестирования.

Следующий код регистрирует настраиваемый класс:

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