How to get content that has already been read

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

[PUT("user/{UserId}")] public HttpResponseMessage Put(string userId, PaymentRequest paymentRequest) { // Calling business logic and so forth here // Return proper HttpResponseMessage here } 

The method works fine, as it is higher. Now I need to verify the signature of the method call, but here I ran into a problem. A signature is essentially a combination of the + url + body method. The method that I can get by calling Request.Method and the url that I can get by calling Request.RequestUri.ToString (), but I can’t grab the body since it was before , it was automatically deserialized into the PaymentRequest object using the infrastructure asp.net MVC4.

My first attempt: As I now understand Request.Content.ReadAsStringAsync (). The result does not return anything. This is because the content can only be read once.

My second attempt: I tried converting it to a JSON string.

 var serializer = new JavaScriptSerializer(); var paymentRequestAsJson = serializer.Serialize(paymentRequest); 

The problem is that the formatting is a little different from the main part of the signature. It has the same data, but a few more gaps.

I cannot change what the caller of my Put method does, since this is a third-party component. What should I do?

+15
c # asp.net-web-api
Aug 10 2018-12-12T00:
source share
3 answers

You can read from the main 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()); } 
+27
Aug 10 '12 at 13:00
source share

Do not include the body parameter in the signature, and this will allow you to buffer the contents and read the contents 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 } 
+13
Aug 10 2018-12-18T00:
source share

A very delayed answer, but lately I had to overcome the same problem.

I approached a little differently without getting data from httpContext (it can be quite expensive for a web application with large transaction volumes).

I created a simple interface and made each of its controllers:

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

Then I set the Controller Entity property to a Json payload for each message and put the action. Finally, I got the Entity data in the ActionFilterAttribute.OnActionExecuted overridden method and serialized it in Json before injecting it into MongoDB:

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

Hope this helps!

Greetings

0
Oct 30 '16 at 5:48
source share



All Articles