22

I get an exception when I try to read multi part content from the request saying the content may have already been read by another component.

 if (MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
            {
                // Used to accumulate all the form url encoded key value pairs in the 
                // request.
                var formAccumulator = new KeyValueAccumulator();

                var boundary = Request.GetMultipartBoundary();
                var reader = new MultipartReader(boundary, HttpContext.Request.Body);
                var section = await reader.ReadNextSectionAsync();
                while (section != null)
                {
                    ContentDispositionHeaderValue contentDisposition;
                    var hasContentDispositionHeader =
                        ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
                }
            }

15 Answers 15

39

In asp.net core 3, You have to add factories.RemoveType<FormFileValueProviderFactory>(); to your DisableFormValueModelBindingAttribute attribute.

Code

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var factories = context.ValueProviderFactories;
        factories.RemoveType<FormValueProviderFactory>();
        factories.RemoveType<FormFileValueProviderFactory>();
        factories.RemoveType<JQueryFormValueProviderFactory>();
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

Documentation

Sign up to request clarification or add additional context in comments.

1 Comment

This answer is useful and helped me while working on the DotNet core migration from 2.2 to 3.1. My API worked after added FormFileValueProviderFactory. Thanks :)
24

It turns out that I had to disable form value model binding by using the attribute below.

[HttpPost]
    [Route("")]
    [DisableFormValueModelBinding]
    public async Task<IActionResult> Post()

The attribute implementation is below

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var factories = context.ValueProviderFactories;
        factories.RemoveType<FormValueProviderFactory>();
        factories.RemoveType<JQueryFormValueProviderFactory>();
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

5 Comments

I have like disabled every single factory by using ValueProviderFactories.RemoveType<T>() but its still giving me the Unexpected error
Yep, solved for me. It's because the DisableFormValueModelBinding custom filter allows us to prevent the method from trying to bind and validate the input automatically which would preemptively read the input stream. This allows us to later use MultipartReader to parse the request.Body. Useful reference; blog.bitscry.com/2018/03/12/…
This answer helped me resolve an issue where I try to use bindings with UploadFilesAsync(String cst, String data, String device), before the multipart would throw exceptions due to being preempted by the bindings. Now it works as intended. Thanks!
how we disable DisableFormValueModelBinding while working in middleware startup.cs class . working in .net core 2.2 ?
I used attribute [FromForm] and got the error, which makes sense. Before i reach the line var reader = new MultipartReader(boundary, request.Body);and var section = await reader.ReadNextSectionAsync(); the attribute forced to open stream and exception will be thrown. If i use [FromQuery] same error, but i am a little bit confused why it happens too? But solution worked for me! Thanks!
7

In my specific case, I was using a multipart boundary value which didn't exist in the payload being parsed by the MultipartReader:

// multipartBoundary is not in the contents of httpResponseContentStream.
var multipartBoundary = "batchresponse_63d0e4c7-4d49-4961-a294-3902d1730c44";
var multipartReader = new MultipartReader(multipartBoundary, httpResponseContentStream);
// Unexpected end-of-stream error used to occur here:
var multipartSection = await multipartReader.ReadNextSectionAsync(cancellationToken);

Once the multipartBoundary was updated to reflect an actual boundary value present in the content being parsed, the code worked as expected.

Comments

5

This worked for me for netcore 3.1

You need to add

factories.RemoveType<FormFileValueProviderFactory>();

on this method

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var factories = context.ValueProviderFactories;
        factories.RemoveType<FormValueProviderFactory>();
        factories.RemoveType<FormFileValueProviderFactory>();
        factories.RemoveType<JQueryFormValueProviderFactory>();
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

1 Comment

How this answer is different from @learner answer?
2

I used [DisableFormValueModelBinding] but still got error, then i also use:

if (Request.ContentLength == 0)
                return BadRequest();

Comments

1

Just in case someone else is chasing ghosts regarding this error: using net5 web api I had a controller with

    [HttpPost]
    [Route("api/fileupload/{reportId}")]
    [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
    public async Task<IActionResult> FileUpload(int reportId)

That wasn't a good idea. It gave the abovementionned error and I remembered having to pass on additional data via file attributes. That solved it for me. Just for completeness. This worked off course

    [HttpPost]
    [Route("api/fileupload")]
    [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
    public async Task<IActionResult> FileUpload()

Comments

1

If you are using MultipartFormDataContent to send the file, at the other side you will receive a mediaTypeHeader.Boundary.Value with an escaped " at the start & end (eg "\"BoundaryValue\"").

So by removing it, it started working for me. The fix for me was to add this at receiver side: .Replace("\"", "")

mediaTypeHeader.Boundary.Value.Replace("\"", "")

Comments

1

In my case I had added another filter which was intercepting the file. Even with the filters mentioned above I still got the issue. Removing the honey pot removed the error finally.

            .AddMvc(options =>
            {
                options.Filters.Add(new AuthorizeFilter());
                // .... etc
                options.AddHoneyPot(); // This was causing the problem
            })

Comments

1

I have this error when send invalid form-data from client. This is valid format: NOTE: two minuses and new line in the end

<empty>
------------------------------8dac95867d24bd1
Content-Disposition: form-data; name="user_login"

<data or empty>
------------------------------8dac95867d24bd1
Content-Disposition: form-data; name="user_password"

<data or empty>
------------------------------8dac95867d24bd1
Content-Disposition: form-data; name="user_session"

<data or empty>
------------------------------8dac95867d24bd1--
<empty>

Comments

1

In my case, I had to remove the [ValidateAntiForgeryToken] attribute.

Comments

0

There is bug about that in Microsoft.AspNetCore.App 2.1.4. I updated this package to 2.1.12 version and it resolved.

1 Comment

Could you please provide reference to this issue?
0

In my case it was "postman" issue. I sent the file to the REST endpoint. And at some point I started to get this error, but the code was not changed.

I re-selected this file again in "postman" and everything worked as before.

Comments

0

In my case I forgot IResourceFilter in DisableFormValueModelBindingAttribute. work fine in .Net7

Comments

0

In my case the issue was the payload... the Content-Length of the request was different from the actual length of the payload. The JavaScript code that was creating the HTTP POST was fixed to get rid of this issue.

Background: The original code looked similar to the Next.js code in this question except that it also included a Content-Length header that was different from the length of the body. And it was because the body was corrupted by body parser function. The solution is in that question.

Comments

0

In addition to disabling form value model binding, I had to update the anti-forgery middleware to stop generating the token when using file upload, by leveraging the Http request "Endpoint Feature".

public async Task InvokeAsync(HttpContext context)

{

    var endpoint = context.Features?.Get<Microsoft.AspNetCore.Http.Features.IEndpointFeature>();

    if (context.User?.Identity != null &&

        context.User.Identity.IsAuthenticated &&

        endpoint?.Endpoint?.Metadata.GetMetadata<DisableFormValueModelBindingAttribute>() == null)

    {

        var tokenSet = antiforgery.GetAndStoreTokens(context);

        var requestToken = tokenSet.RequestToken;



        if (requestToken != null)

        {

            context.Response.Cookies.Append(

                "XSRF-TOKEN",

                requestToken,

                new () { HttpOnly = false, Path = "/", Secure = true, SameSite = SameSiteMode.Strict, });

        }

    }



    await next(context);

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.