我有一个通用的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();
}
}
我希望在Get()
方法上应用以下属性:
[ProducesResponseType(typeof(TEntity), 200)] //this causes compilation error.
[ProducesResponseType(typeof(Object), 404)]
目前,唯一的解决方法是覆盖派生控制器中的每个方法并在那里添加属性:
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);
}
}
我非常不方便我应该覆盖每个控制器中的每个REST方法,只是为了在属性中使用具体的TEntity
类型。 : - (
有更好的解决方法吗?
答案 0 :(得分:3)
通过我发现无法在ProducesResponseTypeAttribute
中使用泛型类型参数,我找到了另一种方法来实现招摇:
使用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
{
}
注意:如果您只是向ProducesResponseTypeAttribute
添加一个新的ActionModel.Attributes
实例,那么Swagger无法正常工作,可能是swagger或asp.net核心中的错误。这就是为什么我在ProducesResponseStub
中使用EntityController
来修饰操作方法并将其替换为EntityControllerConversion
中的正确类型。
答案 1 :(得分:2)
由于.NET Core 2.1代替了IActionResult,因此可以将ActionResult用作returntype(或Task>),然后招摇也将知道200次调用的返回类型!
答案 2 :(得分:-1)
Microsoft.AspNetCore.Mvc.ApiExplorer包中的DefaultApiDescriptionProvider已得到改进,因此它将选择方法返回类型。
请注意,当指定了其他[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));
}
确认可以在Microsoft.AspNetCore.Mvc.ApiExplorer v2.2.0中使用。
还可以使用StatusCodes.Status201Created。