在WebApi控制器的操作中使用body stream参数

时间:2017-03-29 07:21:03

标签: c# asp.net asp.net-web-api asp.net-core

我目前从正文中读取输入流:

public async Task<IActionResult> Post()
{
    byte[] array = new byte[Request.ContentLength.Value];

    using (MemoryStream memoryStream = new MemoryStream(array))
    {
        await Request.Body.CopyToAsync(memoryStream);
    }

    return Ok();
}

由于测试和swagger的生成,我想在方法签名中指定输入参数。

是否可以以某种方式将输入参数指定为流?

public async Task<IActionResult> Post([FromBody]Stream body) ...

3 个答案:

答案 0 :(得分:2)

您必须创建自定义属性和自定义参数绑定。

以下是FromContent属性和ContentParameterBinding绑定的实现:

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

    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,
                                                HttpActionContext actionContext,
                                                CancellationToken cancellationToken)
    {

    }

    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);
    }
}

现在你可以

    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没有帮助:(

答案 1 :(得分:0)

您必须为流创建模型绑定程序:

public class StreamBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        bindingContext.Result = ModelBindingResult.Success(bindingContext.HttpContext.Request.Body);
        return Task.CompletedTask;
    }
}

然后,您应该为其创建模型联编程序提供程序:

public class StreamBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.Metadata.ModelType == typeof(Stream))
        {
            return new BinderTypeModelBinder(typeof(StreamBinder));
        }

        return null;
    }
}

并注册:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.ModelBinderProviders.Insert(0, new StreamBinderProvider());
    });
}

用法:

public async Task<IActionResult> Post([FromBody]Stream body) ...

答案 2 :(得分:-1)

AS Web Api不要在模型绑定中绑定流,这不会起作用。相反,如果您需要参数流,则可以使用自定义模型绑定

http://10.250.216.195/insert.php

控制器

public class MyModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        // Extract the posted data from the request
        // Convert the base64string to Stream
        // Extract the model from the bindingcontext
        // Assign the model's property with their values accordingly   
    }
}