模型绑定在asp.net核心webapi控制器操作方法中不使用Stream类型参数。(即使使用自定义streaminputformatter)

时间:2016-12-27 13:29:45

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

我想将文件上传到asp net core web api controller动作方法。我发送内容类型为“application / octet-stream”。我创建了名为StreamInputFormatter的自定义输入格式化程序。 streaminputformatter被调用,但控制器中的action方法没有被调用?和我的错误

“InvalidOperationException:此流不支持超时。”

StreamInputFormatter:

public class StreamInputFormatter : IInputFormatter
    {
        public bool CanRead(InputFormatterContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            var contentType = context.HttpContext.Request.ContentType;
            if (contentType == "application/octet-stream")
            {
                return true;
            }
            return false;
        }

        public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }


            var memoryStream = new MemoryStream();
            context.HttpContext.Request.Body.CopyTo(memoryStream);

            return InputFormatterResult.SuccessAsync(memoryStream);
        }
    }

控制器操作方法:

        [HttpPost("{documentType}")]
        public async Task<IActionResult> CreateJob(string documentType, [FromBody]Stream template)
        {

        }

2 个答案:

答案 0 :(得分:2)

由于DefaultObjectValidator迭代了不受支持的Stream属性,因此听到您收到此错误(有关详细信息,请参阅此issue)。

要跳过流模型验证,您可以添加

        services.AddMvc(options =>
        {
            ...

            options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Stream)));
        });

到你的配置。

答案 1 :(得分:1)

对于正在寻找完整示例的任何人,以下内容可能会有所帮助:

Startup.cs

services.AddMvc(options =>
{
    options.InputFormatters.Add(new StreamInputFormatter());
    options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Stream)));
}

StreamInputFormatter.cs

public class StreamInputFormatter : IInputFormatter
{
    // enter your list here...
    private readonly List<string> _allowedMimeTypes = new List<string>
        { "application/pdf", "image/jpg", "image/jpeg", "image/png", "image/tiff", "image/tif", "application/octet-stream" };


    public bool CanRead(InputFormatterContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }
        var contentType = context.HttpContext.Request.ContentType;
        if (_allowedMimeTypes.Any(x => x.Contains(contentType)))
        {
            return true;
        }

        return false;
    }

    public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        // enable stream rewind or you won't be able to read the file in the controller   
        var req = context.HttpContext.Request;
        req.EnableRewind();

        var memoryStream = new MemoryStream();
        context.HttpContext.Request.Body.CopyTo(memoryStream);
        req.Body.Seek(0, SeekOrigin.Begin);
        return InputFormatterResult.SuccessAsync(memoryStream);
    }
}

然后是控制器:

public class FileController : BaseController
{
    [HttpPost("customer/{customerId}/file", Name = "UploadFile")]
    [SwaggerResponse(StatusCodes.Status201Created, typeof(UploadFileResponse))]
    [Consumes("application/octet-stream", new string[] { "application/pdf", "image/jpg", "image/jpeg", "image/png", "image/tiff", "image/tif"})]
    public async Task<IActionResult> UploadFile([FromBody] Stream file, [FromRoute] string customerId, [FromQuery] FileQueryParameters queryParameters)
    {
        // file processing here
    }
}