C# 在属性中使用类型参数以将ProducesResponseType与泛型类型参数一起使用的变通方法?
我有一个通用的ASP.NET核心WebApi控制器,如:C# 在属性中使用类型参数以将ProducesResponseType与泛型类型参数一起使用的变通方法?,c#,asp.net,C#,Asp.net,我有一个通用的ASP.NET核心WebApi控制器,如: public abstract class EntityController<TEntity> { public IActionResult Get(string id) { var entity = ... //load from database by id if (entity != null) return new JsonResult(val
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();
}
}
目前,唯一的解决方法是重写派生控制器中的每个方法并在其中添加属性:
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);
}
}
公共类派生控制器:EntityController
{
[产品响应类型(类型(tenty),(int)HttpStatusCode.OK)]
[ProductsResponseType(typeof(Object),(int)HttpStatusCode.NotFound]
公共IActionResult Get(字符串id)
{
返回base.Get(id);
}
}
Ihis非常不方便,我应该覆盖每个控制器中的每个REST方法,只是为了使用具体的tenty
输入属性:-(
有更好的解决方法吗?尽管我在
productsResponseTypeAttribute
中找不到使用泛型类型参数的方法,但我找到了另一种让招摇过市有效的方法:
使用iaapplicationmodelconversation
更新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
{
}
公共类EntityController Conversion:IAApplicationModelConversion
{
公共无效应用(应用程序模型应用程序)
{
ActionModel action=…//查找控制器操作
类型viewModelType=…//通过从控制器反射获取视图类型
SetResponseUsingHack(操作、viewModelType、HttpStatusCode.OK);
}
私有void SetResponseUsingHack(ActionModel ActionModel,类型responseType,HttpStatusCode statusCode)
{
如果(actionModel==null)抛出新的ArgumentNullException(nameof(actionModel));
如果(responseType==null)抛出新的ArgumentNullException(nameof(responseType));
var writeable=(IList)(actionModel.Attributes);
var attribute=FindResponseAttributeUsingHack(可写,状态码);
if(属性!=null)
{
attribute.Type=responseType;
}
}
私有产品响应类型属性FindResponseAttributeUsingHack(IList属性,HttpStatusCode状态码)
{
如果(attributes==null)返回null;
var result=attributes.OfType()
其中(x=>x.Type==typeof(productsResponseStub))
.FirstOrDefault(x=>x.StatusCode==(int)StatusCode);
返回结果;
}
}
公共抽象类EntityController
{
[HttpGet]
[产品响应类型(类型(产品响应桶),200)]
公共IActionResult Get(字符串id)
{
}
}
公共静态类ProducesResponseStub
{
}
注意:如果您只是将新的
ProducesResponseTypeAttribute
实例添加到ActionModel.Attributes
中,Swagger将无法正常工作,这可能是Swagger或asp.net core中的一个错误。这就是为什么我在EntityController
中的装饰操作方法中使用ProducesResponseStub
,并用正确的类型替换它们的原因nEntityControllerConversion
由于.NET Core 2.1
没有使用IActionResult
,您可以使用ActionResult
作为返回类型
(或任务
)然后,swagger
还将知道200
调用的returntype
。包Microsoft.AspNetCore.Mvc.ApiExplorer中的DefaultApisDescriptionProvider已经过改进,因此它将选择方法返回类型
请注意,当指定其他[ProductsResponseType]属性时,需要[ProductsResponseType(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));
}
[HttpGet,Route(“”)
[产品响应类型(StatusCodes.Status200OK)]
[ProductsResponseType(StatusCodes.Status400BadRequest,Type=typeof(ProblemDetailsResponse))]
[产品响应类型(StatusCodes.Status404NotFound,Type=typeof(ProblemDetailsResponse))]
公共异步任务GetAll(int-imoNo)
{
var parameters=wait_parameterService.GetAllAsync(IMNO);
返回参数。选择(x=>MapToResponse(x));
}
已确认在Microsoft.AspNetCore.Mvc.ApiExplorer v2.2.0中工作
还可以使用StatusCodes.Status201Created。我能想到的唯一原因是泛型类型参数在运行时解析。但是,属性参数必须在编译时解析。因此,您不能将泛型类型参数用作属性的参数。您可以查看并了解更多信息。对于解决方法,我尝试推送如果可以的话。你的回答节省了我的时间。另外,我花了大约20-30分钟才找到有关如何在asp.net core startup中注册IAApplicationModelConversation实例的信息。因为只是将实现添加到web项目中并没有得到结果。
[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));
}