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

时间:2017-06-02 18:18:11

标签: asp.net-web-api swagger swashbuckle

我希望有一个自定义属性来将数据解析为流,并且可以使用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);
    }
}
  

更新

当我使用Stream创建[FromBody]时,在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";
}

Good Post

所以我希望拥有相同的用户界面,但我的自定义属性让我从内容中获得Stream

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

2 个答案:

答案 0 :(得分:3)

FormatterParameterBinding类继承你的绑定:

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

    //your code
}

答案 1 :(得分:1)

尝试实施界面IValueProviderParameterBinding

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

就我而言,它有所帮助。 此外,它通常更清晰,因为它不会继承FormatterParameterBinding逻辑,这可能不是必需的。