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

Sma*_*kid 8 c# asp.net

我有一个通用的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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我想在Get()方法上应用以下属性:

[ProducesResponseType(typeof(TEntity), 200)] //this causes compilation error.
[ProducesResponseType(typeof(Object), 404)]
Run Code Online (Sandbox Code Playgroud)

目前,唯一的解决方法是覆盖派生控制器中的每个方法并在其中添加属性:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我非常不方便我应该覆盖每个控制器中的每个REST方法,只是为了使用TEntity属性中的具体类型.:-(

有没有更好的工作?

Max*_*imc 7

由于您可以使用as (或).NET Core 2.1而不是 using IActionResult,然后也将知道for调用!ActionResult<TEntity>returntypeTask<ActionResult<TEntity>>swaggerreturntype200


Sma*_*kid 4

尽管我找不到在 中使用泛型类型参数的方法ProducesResponseTypeAttribute,但我找到了另一种使 swagger 工作的方法:

用于IApplicationModelConventionupdate ApplicationModel,这是 swagger 使用的。

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
{
}
Run Code Online (Sandbox Code Playgroud)

ProducesResponseTypeAttribute注意:如果您只是向 中添加一个新实例, Swagger 将无法正常工作,ActionModel.Attributes这可能是 swagger 或 asp.net core 中的错误。这就是为什么我ProducesResponseStub在 中使用装饰操作方法EntityController并将其替换为 中的正确类型EntityControllerConversion