How to get hold of Content that is already read

前端 未结 4 1453
小鲜肉
小鲜肉 2020-12-01 06:34

I have a class that inherits from ApiController. It has a Put-method like this:

[PUT(\"user/{UserId}\")]
public HttpResponseMessage Put(string userId, Payme         


        
相关标签:
4条回答
  • 2020-12-01 07:15

    You could read from the underlying request:

    using (var stream = new MemoryStream())
    {
        var context = (HttpContextBase)Request.Properties["MS_HttpContext"];
        context.Request.InputStream.Seek(0, SeekOrigin.Begin);
        context.Request.InputStream.CopyTo(stream);
        string requestBody = Encoding.UTF8.GetString(stream.ToArray());
    }
    
    0 讨论(0)
  • 2020-12-01 07:19

    Don't include the body parameter in the signature and that will allow you to buffer the content and read the content as many times as you like.

    [PUT("user/{UserId}")]
    public HttpResponseMessage Put(string userId)
    {
        Request.Content.LoadIntoBufferAsync().Wait();
        var paymentRequest = Request.Content.ReadAsAsync<PaymentRequest>().Result;
        var requestBody = Request.Content.ReadAsStringAsync().Result;
        // Calling business logic and so forth here
        // Return proper HttpResponseMessage here
    }
    
    0 讨论(0)
  • 2020-12-01 07:27

    My answer is a variation of Darin Dimitrov's above... variant answers should be expected with all the variants of C# (ASP.NET, Core, MVC, etc.)... and perhaps the year of Visual Studio (2017, 2019, etc.)... and if Visual Basic is used rather than C#....

    Similar to Anders Arpi's comment, I was not able to use Darin's answer as provided (though obviously my answer is a direct derivation from his). In my case Request.Properties was not an option, but Request.InputStream was. I suspect this strongly depends on the project's type as mentioned in the first paragraph. My solution worked for me in VS2017.

    Similar answers are also on the page: How to get raw request body in ASP.NET? However, these did not work for me. But, they did provide important clues such as 'The request object is not populated in the BeginRequest event. You need to access this object later in the event life cycle'...

    Skip this next paragraph if you are experienced in HTTPRequests construction/analysis.

    Though it's incredibly obvious in retrospect, Request Body content only appears for certain HTTPRequests. If you are just doing a GET (e.g. clicking on a navigation tab which takes you to a new page), you generally don't have a Request Body. So when testing solutions, make sure that you are looking at a HttpRequest that should contain a RequestBody. In my case, any Submit button that's actually receiving data from the UI will be a Post that contains a RequestBody, and therefore in existence (and of length greater than 0). If you don't have Fiddler or BurpSuite, or are working through Shibboleth (which adds complexity to Fiddler/BurpSuite testing), you can generally see the HTTPRequest in the Firefox developer tool (via F12).... where what I'm calling the Request Body would be called Params and/or the Request Payload.

    N.B. Application_AuthenticateRequest is within Global.asax.cs.

    (in addition to other using statements)
    using System.IO;
    using System.Text;
    using System.Web;  
    
    protected void Application_AuthenticateRequest(object sender, EventArgs e){
    
    HttpApplication app = (HttpApplication)sender;
    // Do a quick check to make sure that we are not on local. 
    // I've had some odd errors on local, though I suspect general implementation will not have this issue.
    // So if we're actually on a 'real' (a.k.a. non-local) website, I do the following.
    
          using (var stream = new MemoryStream())
                    {
                        app.Request.InputStream.Seek(0, SeekOrigin.Begin);
                        app.Request.InputStream.CopyTo(stream);
                        string requestBody = Encoding.UTF8.GetString(stream.ToArray());
                        app.Request.InputStream.Seek(0, SeekOrigin.Begin); 
                        if (requestBody.Length > 0) Response.Write("requestBody: " + requestBody + "<br>");
                    }
    
    }
    

    Please note that I am using the recommendation of 'Reinstate Monica Cellio' to reset the InputStream after copying.

    0 讨论(0)
  • 2020-12-01 07:30

    A very delayed response, but recently I have had the same challenge to overcome.

    I have approached that a bit different without having to get the data from the httpContext (can be quite costly for high volume transaction web application).

    I created a simple interface and made each Controller implementing it:

    public interface IBaseControllerData
    {
        object Entity { get; set; }
    }
    

    I have then set the Controller's Entity property to the Json payload for each post and put action. Finally, I retrieved the Entity data within the ActionFilterAttribute.OnActionExecuted overridden method and serialised it to Json before injecting into MongoDB:

    object entity = ((IBaseControllerData)actionExecutedContext.ActionContext.ControllerContext.Controller).Entity;
                        requestBody = Newtonsoft.Json.JsonConvert.SerializeObject(entity);
    

    Hope that helps !

    Cheers

    0 讨论(0)
提交回复
热议问题