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
可能不需要的逻辑。
我想要一个自定义属性来将数据解析为流并可使用 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
可能不需要的逻辑。