Use body stream parameter in WebApi controller action

I am currently reading the input stream from the body as follows:

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

I would like to specify an input parameter in the method signature due to testing and swag generation.

Is it possible to somehow specify the input parameter as a stream?

public async Task<IActionResult> Post([FromBody]Stream body) ...
+4
source share
2 answers

You need to create a custom attribute and a binding for custom parameters.

Here is my attribute FromContentand ContentParameterBindingbinding implementation :

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

Now you can

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

However, this does not help with swagger: (

+1
source

AS Web Api , . , , Model

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 property with their values accordingly   
    }
}

public ApiActionResult SaveDocument([ModelBinder(typeof(MyModelBinder))]DocumentVM contentDTO)
0

Source: https://habr.com/ru/post/1673473/


All Articles