Net Core API:如何将ProducesResponseType设置为全局参数或自动化?

3
我们有100多个API,必须为所有API的顶部编写ProducesResponseType,例如200、500等。是否有一种方法可以使这些全局参数适用于所有get函数,以便我们不必继续重复代码?试图使API遵循DRY原则并成为轻量级控制器。
[HttpGet("[Action]/{id}")]
[ProducesResponseType(typeof(GetBookResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(GetBookResponse), StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<GetBookResponse>> GetByBook(int id)
{
   var book = await bookservice.GetBookById(id);
   return Ok(book);
}

资源:

将一个ProducessResponseType typeof设置为多个HttpStatusCodes的解决方法

Net Core API: ProducesResponseType的目的

2个回答

13
你可以创建一个自定义的 IApplicationModelProvider,并在 OnProvidersExecuting 方法中添加所需的过滤器。 ProduceResponseTypeModelProvider.cs
public class ProduceResponseTypeModelProvider : IApplicationModelProvider
{
    public int Order => 3;

    public void OnProvidersExecuted(ApplicationModelProviderContext context)
    {
    }

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        foreach (ControllerModel controller in context.Result.Controllers)
        {
            foreach (ActionModel action in controller.Actions)
            {
                // I assume that all you actions type are Task<ActionResult<ReturnType>>

                Type returnType = action.ActionMethod.ReturnType.GenericTypeArguments[0].GetGenericArguments()[0];

                action.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status510NotExtended));
                action.Filters.Add(new ProducesResponseTypeAttribute(returnType, StatusCodes.Status200OK));
                action.Filters.Add(new ProducesResponseTypeAttribute(returnType, StatusCodes.Status500InternalServerError));
            }
        }
    }
}

然后你需要将它注册到 IServiceCollection

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    ...   
    services.TryAddEnumerable(ServiceDescriptor.Transient<IApplicationModelProvider, ProduceResponseTypeModelProvider>());
    ...
}

还有,public int Order => 3 是什么意思?我没有在代码中看到它被使用,其他的看起来都很好。 - user12093268
一切都在文档中。Order 属性用于当您有多个 IApplicationModelProvider 时,您可以设置哪一个先运行。3 只是一个随机数! - Kahbazi
1
嗨,有时当我在我的API项目中运行此代码时,会出现以下错误:“System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'” 我查看了对应的API,发现它没有[0]索引,但是API控制器存在。不确定为什么该属性没有显示出来,是否有其他替代方法? - user12093268
1
我认为可以简化,试图找到 typeof(GetBookResponse) 等。 - user12093268
这里有一个关于编程的问题:https://stackoverflow.com/questions/59671768/net-core-find-api-status-codes-for-controller-actionmodel - user12425844
由于我不需要returnType,除了在“200 OK”上使用它并且我在控制器上使用它而不是这里,我已经修改了代码,我的代码看起来像这样: foreach (ControllerModel controller in context.Result.Controllers) { foreach (ActionModel action in controller.Actions) { action.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status204NoContent)); action.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status400BadRequest)); ... } } - SushiDynamite

1
Kahbazi的回答是正确的,我们也使用这行代码。它提供错误处理、动词属性检查和参数存在性检查。
public class ProduceResponseTypeModelProvider : IApplicationModelProvider
    {
        public int Order => 3;

        public void OnProvidersExecuted(ApplicationModelProviderContext context)
        {
        }

        public void OnProvidersExecuting(ApplicationModelProviderContext context)
        {
            foreach (ControllerModel controller in context.Result.Controllers)
            {
                foreach (ActionModel action in controller.Actions)
                {
                    Type returnType = null;
                    if (action.ActionMethod.ReturnType.GenericTypeArguments.Any())
                    {
                        if (action.ActionMethod.ReturnType.GenericTypeArguments[0].GetGenericArguments().Any())
                        {
                            returnType = action.ActionMethod.ReturnType.GenericTypeArguments[0].GetGenericArguments()[0];
                        }
                    }

                    var methodVerbs = action.Attributes.OfType<HttpMethodAttribute>().SelectMany(x => x.HttpMethods).Distinct();
                    bool actionParametersExist = action.Parameters.Any();

                    AddUniversalStatusCodes(action, returnType);

                    if (actionParametersExist == true)
                    {
                        AddProducesResponseTypeAttribute(action, null, 404);
                    }
                    if (methodVerbs.Contains("POST"))
                    {
                        AddPostStatusCodes(action, returnType, actionParametersExist);
                    }
                }
            }
        }

        public void AddProducesResponseTypeAttribute(ActionModel action, Type returnType, int statusCodeResult)
        {
            if (returnType != null)
            {
                action.Filters.Add(new ProducesResponseTypeAttribute(returnType, statusCodeResult));
            }
            else if (returnType == null)
            {
                action.Filters.Add(new ProducesResponseTypeAttribute(statusCodeResult));
            }
        }

        public void AddUniversalStatusCodes(ActionModel action, Type returnType)
        {
            AddProducesResponseTypeAttribute(action, returnType, 200);
            AddProducesResponseTypeAttribute(action, null, 500);
        }

        public void AddPostStatusCodes(ActionModel action, Type returnType, bool actionParametersExist)
        {
            AddProducesResponseTypeAttribute(action, returnType, 201);
            AddProducesResponseTypeAttribute(action, returnType, 400);
            if (actionParametersExist == false)
            {
                AddProducesResponseTypeAttribute(action, null, 404);
            }
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,