Access Raw Request Body

后端 未结 4 1404
北恋
北恋 2021-01-04 12:59

I\'m trying to access a request\'s raw input body/stream in ASP.net 5. In the past, I was able to reset the position of the input stream to 0 and read it into a memory strea

相关标签:
4条回答
  • 2021-01-04 13:21

    I just had this same issue. Remove the parameters from the method signature, and then read the Request.Body Stream how you want to.

    0 讨论(0)
  • 2021-01-04 13:23

    You need to call Request.EnableRewind() to allow the stream to be rewound so you can read it.

    string bodyAsString;
    Request.EnableRewind();
    using (var streamReader = new StreamReader(Request.Body, Encoding.UTF8))
    {
        bodyAsString = streamReader.ReadToEnd();
    }
    
    0 讨论(0)
  • 2021-01-04 13:29

    The exceptions you see in your three last snippets are the direct consequence of trying to read the request body multiple times - once by MVC 6 and once in your custom code - when using a streamed host like IIS or WebListener. You can see this SO question for more information: Read body twice in Asp.Net 5.

    That said, I'd only expect this to happen when using application/x-www-form-urlencoded, since it wouldn't be safe for MVC to start reading the request stream with lengthy requests like file uploads. If that's not the case, then it's probably a MVC bug you should report on https://github.com/aspnet/Mvc.

    For workarounds, you should take a look at this SO answer, that explains how you can use context.Request.ReadFormAsync or add manual buffering: Read body twice in Asp.Net 5

    app.Use(next => async context => {
        // Keep the original stream in a separate
        // variable to restore it later if necessary.
        var stream = context.Request.Body;
    
        // Optimization: don't buffer the request if
        // there was no stream or if it is rewindable.
        if (stream == Stream.Null || stream.CanSeek) {
            await next(context);
    
            return;
        }
    
        try {
            using (var buffer = new MemoryStream()) {
                // Copy the request stream to the memory stream.
                await stream.CopyToAsync(buffer);
    
                // Rewind the memory stream.
                buffer.Position = 0L;
    
                // Replace the request stream by the memory stream.
                context.Request.Body = buffer;
    
                // Invoke the rest of the pipeline.
                await next(context);
            }
        }
    
        finally {
            // Restore the original stream.
            context.Request.Body = stream;
        }
    });
    
    0 讨论(0)
  • 2021-01-04 13:42

    The implementation of Request.Body depends on the controller action.

    If the action contains parameters it's implemented by Microsoft.AspNet.WebUtilities.FileBufferingReadStream, which supports seeking (Request.Body.CanSeek == true). This type also supports setting the Request.Body.Position.

    However, if your action contains no parameters it's implemented by Microsoft.AspNet.Loader.IIS.FeatureModel.RequestBody, which does not support seeking (Request.Body.CanSeek == false). This means you can not adjust the Position property and you can just start reading the stream.

    This difference probably has to do with the fact that MVC needs to extract the parameters values from the request body, therefore it needs to read the request.

    In your case, your action does not have any parameters. So the Microsoft.AspNet.Loader.IIS.FeatureModel.RequestBody is used, which throws an exception if you try to set the Position property.


    Solution: either do not set the position or check if you actually can set the position first:

    if (Request.Body.CanSeek)
    {
        // Reset the position to zero to read from the beginning.
        Request.Body.Position = 0;
    }
    
    var input = new StreamReader(Request.Body).ReadToEnd();
    
    0 讨论(0)
提交回复
热议问题