简体   繁体   English

在属性中使用类型参数以使用带有泛型类型参数的ProducesResponseType的解决方法?

[英]Workaround for using type parameter in attribute for using ProducesResponseType with a generic type argument?

I have a generic ASP.NET Core WebApi controller like: 我有一个通用的ASP.NET Core WebApi控制器,如:

public abstract class EntityController<TEntity> 
{
    public IActionResult Get(string id)
    {
        var entity = ... //load from database by id
        if (entity != null) 
            return new JsonResult(value, this.SerializerSettings()) {StatusCode  200};
        return NotFound();
    }
}

and I want to apply following attributes on the Get() method: 我想在Get()方法上应用以下属性:

[ProducesResponseType(typeof(TEntity), 200)] //this causes compilation error.
[ProducesResponseType(typeof(Object), 404)]

For now, the only work around is to override each method in derived controller and add attributes there: 目前,唯一的解决方法是覆盖派生控制器中的每个方法并在其中添加属性:

public class DerivedController :EntityController<MyEntity>
{
    [ProducesResponseType(typeof(TEntity), (int) HttpStatusCode.OK)]
    [ProducesResponseType(typeof(Object), (int) HttpStatusCode.NotFound)]
    public IActionResult Get(string id)
    {
        return base.Get(id);
    }
}

Ihis is very inconvenient that I should override every REST methods in every controller, just for use the concrete TEntity type in attributes. 我非常不方便我应该覆盖每个控制器中的每个REST方法,只是为了在属性中使用具体的TEntity类型。 :-( :-(

Any better work arounds? 有没有更好的工作?

Althrough I found no way to use generic type parameter in ProducesResponseTypeAttribute , I found another way to make swagger work: 通过我发现无法在ProducesResponseTypeAttribute使用泛型类型参数,我找到了另一种方法来使swagger工作:

Use IApplicationModelConvention to update ApplicationModel , which is used by swagger. 使用IApplicationModelConvention来更新swagger使用的ApplicationModel

public class EntityControllerConversion : IApplicationModelConvention
{
    public void Apply(ApplicationModel application)
    {
        ActionModel action = ... // finds the controller action 
        Type viewModelType = ... // get the view type by reflection from the controller
        SetResponseUsingHack(action, viewModelType, HttpStatusCode.OK);
    }

    private void SetResponseUsingHack(ActionModel actionModel, Type responseType, HttpStatusCode statusCode)
    {
        if (actionModel == null) throw new ArgumentNullException(nameof(actionModel));
        if (responseType == null) throw new ArgumentNullException(nameof(responseType));

        var writable = (IList<object>)(actionModel.Attributes);
        var attribute = FindResponseAttributeUsingHack(writable, statusCode);
        if (attribute != null)
        {
            attribute.Type = responseType;
        }
    }

    private ProducesResponseTypeAttribute FindResponseAttributeUsingHack(IList<object> attributes, HttpStatusCode statusCode)
    {
        if (attributes == null) return null;
        var result = attributes.OfType<ProducesResponseTypeAttribute>()
            .Where(x => x.Type == typeof(ProducesResponseStub))
            .FirstOrDefault(x => x.StatusCode == (int) statusCode);
        return result;
    }
}

public abstract class EntityController<TEntity> 
{
    [HttpGet]
    [ProducesResponseType(typeof(ProducesResponseStub), 200)]
    public IActionResult Get(string id)
    {
    }
}

public static class ProducesResponseStub
{
}

NOTE: Swagger won't work correctly if you just add a new ProducesResponseTypeAttribute instance to ActionModel.Attributes , may be it's a bug in swagger or in asp.net core. 注意:如果您只是向ActionModel.Attributes添加一个新的ProducesResponseTypeAttribute实例,则Swagger将无法正常工作,可能是swagger或asp.net核心中的错误。 That why I use ProducesResponseStub in decorating action methods in EntityController and replace them with correct types in EntityControllerConversion . 这就是为什么我使用ProducesResponseStub在装修中的操作方法EntityController并以正确的类型替换它们EntityControllerConversion

从.NET Core 2.1开始,而不是使用IActionResult,你可以使用ActionResult作为返回类型(或任务>),然后swagger也会知道200个调用的返回类型!

The DefaultApiDescriptionProvider in package Microsoft.AspNetCore.Mvc.ApiExplorer has been improved so that it will pick up method return type. Microsoft.AspNetCore.Mvc.ApiExplorer包中的DefaultApiDescriptionProvider已得到改进,因此它将获取方法返回类型。

Note that the [ProducesResponseType(StatusCodes.Status200OK)] attribute is required when other [ProducesResponseType] attributes are specified as shown below: 请注意,如果指定了其他[ProducesResponseType]属性,则需要[ProducesResponseType(StatusCodes.Status200OK)]属性,如下所示:

    [HttpGet, Route("")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetailsResponse))]
    [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetailsResponse))]
    public async Task<IEnumerable<TResponse>> GetAll(int imoNo)
    {
        var parameters = await _parameterService.GetAllAsync(imoNo);

        return parameters.Select(x => MapToResponse(x));
    }

Confirmed to work in Microsoft.AspNetCore.Mvc.ApiExplorer v2.2.0. 确认可以在Microsoft.AspNetCore.Mvc.ApiExplorer v2.2.0中工作。

Also work with StatusCodes.Status201Created. 也适用于StatusCodes.Status201Created。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM