Swagger 无法识别具有自定义属性 [FromContent] 的 WebAPI 控制器参数

Swagger does not recognize WebAPI controller parameter with custom attribute [FromContent]

我想要一个自定义属性来将数据解析为流并可使用 Swagger 进行测试。

所以我创建了从 POST body:

读取的控制器
[SwaggerOperation("Create")]
[SwaggerResponse(HttpStatusCode.Created)]
public async Task<string> Post([FromContent]Stream contentStream)
{
    using (StreamReader reader = new StreamReader(contentStream, Encoding.UTF8))
    {
        var str = reader.ReadToEnd();
        Console.WriteLine(str);
    }
    return "OK";
}

如何定义流以便它在 Swagger 中可见 UI?

这是我对 FromContent 属性和 ContentParameterBinding 绑定的实现:

public class ContentParameterBinding : HttpParameterBinding
{
    private struct AsyncVoid{}
    public ContentParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor)
    {

    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,
                                                HttpActionContext actionContext,
                                                CancellationToken cancellationToken)
    {
        var binding = actionContext.ActionDescriptor.ActionBinding;

        if (binding.ParameterBindings.Length > 1 ||
            actionContext.Request.Method == HttpMethod.Get)
        {
            var taskSource = new TaskCompletionSource<AsyncVoid>();
            taskSource.SetResult(default(AsyncVoid));
            return taskSource.Task as Task;
        }

        var type = binding.ParameterBindings[0].Descriptor.ParameterType;

        if (type == typeof(HttpContent))
        {
            SetValue(actionContext, actionContext.Request.Content);
            var tcs = new TaskCompletionSource<object>();
            tcs.SetResult(actionContext.Request.Content);
            return tcs.Task;
        }
        if (type == typeof(Stream))
        {
            return actionContext.Request.Content
            .ReadAsStreamAsync()
            .ContinueWith((task) =>
            {
                SetValue(actionContext, task.Result);
            });
        }

        throw new InvalidOperationException("Only HttpContent and Stream are supported for [FromContent] parameters");
    }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public sealed class FromContentAttribute : ParameterBindingAttribute
{
    public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
    {
        if (parameter == null)
            throw new ArgumentException("Invalid parameter");

        return new ContentParameterBinding(parameter);
    }
}

Update

当我使用 [FromBody] 创建 Stream 时,在 Swagger 中正确显示,但是 Stream 未启动并且 ==null

[SwaggerOperation("Create")]
[SwaggerResponse(HttpStatusCode.Created)]
public async Task<string> Post([FromBody]Stream contentStream)
{
    using (StreamReader reader = new StreamReader(contentStream, Encoding.UTF8))
    {
        var str = reader.ReadToEnd();
        Console.WriteLine(str);
    }
    return "OK";
}

所以我想拥有相同的 UI 但我的自定义属性让我从内容中获得 Stream

使用我的自定义属性,它显示的参数没有 TextArea,但可以使用 Postman 进行测试并正常工作,并且 Stream 可用

继承您的绑定 FormatterParameterBinding class:

public class ContentParameterBinding : FormatterParameterBinding
{
    public ContentParameterBinding(HttpParameterDescriptor descriptor)
            : base(descriptor, 
                   descriptor.Configuration.Formatters, 
                   descriptor.Configuration.Services.GetBodyModelValidator())
    {
    }

    //your code
}

尝试实现接口 IValueProviderParameterBinding:

public class ContentParameterBinding
    : HttpParameterBinding, IValueProviderParameterBinding
{
    public IEnumerable<ValueProviderFactory> ValueProviderFactories
    {
        get
        {
            return this.Descriptor.Configuration.Services.GetValueProviderFactories();
        }
    }
}

就我而言,它有所帮助。 而且它通常更干净,因为它不继承 FormatterParameterBinding 可能不需要的逻辑。