Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

ModelBindingContext.HttpContext.Request.Body already consumed! #7251

Closed
ans-ashkan opened this issue Jan 17, 2018 · 5 comments
Closed

ModelBindingContext.HttpContext.Request.Body already consumed! #7251

ans-ashkan opened this issue Jan 17, 2018 · 5 comments

Comments

@ans-ashkan
Copy link

Request.Body is already consumed in CustomModelBinder or in an Action that contains some parameters.

[ModelBinder(typeof(CustomModelBinder))]
public class StreamModel
{
    public MemoryStream Stream
    {
        get;
        set;
    }
}

public class CustomModelBinder : IModelBinder
{
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var request = bindingContext.HttpContext.Request;
        var ms = new MemoryStream();
        request.Body.CopyTo(ms);
        bindingContext.Result = ModelBindingResult.Success(new StreamModel
        {
            Stream = ms
        });
    }
}

Value of ms.Length always equals to 0.

the action with parameters code:

public class TestController : Controller
{
    [HttpPost]
    public IActionResult Test(string data)
    {
        var ms = new MemoryStream();
        request.Body.CopyTo(ms);
        return OK(ms.Length);
    }
}

Also this always returns 0. but if you drop the paramter string data, it returns the actual body length.

by using the following middleware, it works. but I consider this a workaround.

app.Use(next => context => { context.Request.EnableRewind(); return next(context); });

Shouldn't this happen internally (in mvc)?

(link to stack overflow question: https://stackoverflow.com/questions/48297331/using-request-body-in-custom-modelbinder)
(another related question on stack overflow: https://stackoverflow.com/questions/31389781/read-request-body-twice)

@davidfowl
Copy link
Member

Why should it happen in MVC? By default the http request body isn't rewindable.

@ans-ashkan
Copy link
Author

Because it's being used by mvc (not me) and I can't care to add a middleware for it?
If the body is available in the action or more important ModelBinder, I consider it to be usable (as it was in non-core asp.net mvc)

@davidfowl
Copy link
Member

@ans-ashkan that means buffering the request body by default, which has performance implications. I think it should be opt-in (if we do it at all). You can easily write a filter to allow this for your specific action. It's rare that you read the body twice during a request.

@ans-ashkan
Copy link
Author

@davidfowl I agree, performance matters. the option to enable buffered request body can be useful though.
Another question, when/where that read happens (in MVC).
Would you please show me the code for the filter you mentioned?

@mkArtakMSFT
Copy link
Member

Hi @ans-ashkan. What you're looking for can be achieved using Resource Filters, as they execute before Model Binding consumes the request body. You can get more details about Resource Filters at: https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters.

As for baking this functionality into ASP.NET Core, we don't want to do that as we haven't heard much need of it, given the easy filters-based solution can be implemented.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants