Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在属性中使用类型参数以将ProducesResponseType与泛型类型参数一起使用的变通方法?_C#_Asp.net - Fatal编程技术网

C# 在属性中使用类型参数以将ProducesResponseType与泛型类型参数一起使用的变通方法?

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

我有一个通用的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(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
,并用正确的类型替换它们的原因n
EntityControllerConversion

由于
.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));
    }