0

I am trying to send a POST request to a server.The request gets into the Middleware's Invoke method.

However the Content is always null, no matter the type of the object.

Sender

public async Task<string> RunTestAsync(string request)
{
    try
    {
        var content = new StringContent(JsonConvert.SerializeObject(request),Encoding.UTF8,"application/json");

       var response=await this.client.PostAsync("http://localhost:8500/mat",
                              content);

        string str=await response.Content.ReadAsStringAsync();
        stringdata = JsonConvert.DeserializeObject<string>(str);
        return data;     
    }
    catch (Exception ex)
    {
        Console.WriteLine("Threw in client" + ex.Message);
        throw;
    }
}

Server

The server has no service defined ,just a plain middleware that responds on a route. ( The request gets in the Invoke method ! )

Startup

 public class Startup
   {
        public void ConfigureServices(IServiceCollection services) {

        }
        public void Configure(IApplicationBuilder app, IHostingEnvironment env) {

            app.UseDeveloperExceptionPage();
            app.UseBlazor<Client.Startup>();

            app.Map("/mid", a => {
                     a.UseMiddleware<Mware>();
                });
            });
        }
   }

Middleware

public class Mware
{
    public RequestDelegate next{get;set;}

    public Mware(RequestDelegate del)
    {
      this.next=del;
    }
    public async Task Invoke(HttpContext context)
    {

            using (var sr = new StreamReader(context.Request.Body))
            {
                string content = await sr.ReadToEndAsync();//null ,tried other types too , still null ,and the ContentLength is null too
                var request=JsonConvert.DeserializeObject<string>(content);
                if (request == null)
                {
                    return;
                }
            }
    }
}

I have checked my serialization and the object is serialized just fine.

Despite this I am always getting a null on the other side.

P.S

I have also tried using no middleware just a plain delegate like below :

 public void Configure(IApplicationBuilder app, IHostingEnvironment env) {

        app.UseDeveloperExceptionPage();
        app.UseBlazor<Client.Startup>();

        app.Map("/mid",x=>{
            x.Use(async(context,del)=>{
                using (var sr = new StreamReader(context.Request.Body))
                {
                  string content = await sr.ReadToEndAsync();//null ,tried other types too , still null ,and the ContentLength is null too
                  var request=JsonConvert.DeserializeObject<string>(content);
                  if (request == null)
                  {
                    return;
                  }
                }
        });
    }

Even without a dedicated middleware the problem persists.

The problem is not the middleware , its the request that is serialized correctly in the client, sent to the server ,and somehow its body shows up as null.

I would've understood if it failed to deserialize the object , but the HttpContext.Request.Body as a string is received null and its length is null !!

Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152
  • When yoy serialize/deserialize, usually your generic type would be the class you wish to construct and not a string type. You should use same serialization on both ends.. – ilansch Feb 04 '19 at 14:06
  • I have tried with multiple `Type`-s , including primitive types and i still get a `null` content. – Bercovici Adrian Feb 04 '19 at 14:07
  • Check only serialization. With a test. Serialize and deserialize your object before sending over the http. Make sure that part works. Then continue to other parts. – ilansch Feb 04 '19 at 14:08
  • I have checked it and its ok. – Bercovici Adrian Feb 04 '19 at 14:09
  • @BercoviciAdrian This appears to be an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). The question in its current state is also incomplete and therefore unclear. Read [ask] and then edit the question to provide a [mcve] that can be used to reproduce the problem, allowing a better understanding of what is being asked. – Nkosi Feb 04 '19 at 14:09
  • 1
    @BercoviciAdrian What is the `string request` suppose to represent before posting? What is the `Invoke` method on the controller? An action or local method? There are just too many unknowns about what you are asking. – Nkosi Feb 04 '19 at 14:13
  • @BercoviciAdrian so `Invoke` is for a middleware, not a controller? – Nkosi Feb 04 '19 at 14:14
  • I am sorry i think it was a typo.Yes it is a `Middleware`. I updated my post. – Bercovici Adrian Feb 04 '19 at 14:14
  • 2
    @BercoviciAdrian You really need to update this into a [mcve] if you want to attract the attention to get this solved. You did not get it initially because there is just too much details missing about how it is setup and configured, what platform version is being used, etc. – Nkosi Feb 05 '19 at 11:40
  • 1
    @BercoviciAdrian what does `string request` parameter in `RunTestAsync` suppose to contain and why are you serializing a string? – Nkosi Feb 05 '19 at 11:58
  • I mentioned that i have tried with other `types` too . I used `string` in the example for ease of use.But it does not work for any `type` you will try.I am just trying to `PostAsync` an object , be it `string`, `int` or any other `POCO` ,and it does not work.I keep receiveing a `null` `Context.Request.Body`. – Bercovici Adrian Feb 05 '19 at 12:43
  • 1
    To help us understand the question better, first of all, when you call `await this.client.PostAsync("http://localhost:8500/mat", content);`, then the `Invoke` method of the middleware is being called directly? have you tried to debug it to actually see the whole `HttpContext` object and what does it contains? – Paul Karam Feb 05 '19 at 14:24
  • I have updated my answer.I thought it is not important to post the `Startup` class since the request gets in the `middleware`. – Bercovici Adrian Feb 05 '19 at 14:38
  • 1
    @BercoviciAdrian it is a routing issue. Your middleware is registered late in the pipeline and the body would have already been read by the time it reaches your middleware. Check the position of the pointer in the Body stream. I am certain it would be at the end. Which is what why you try to read it in the reader you get nothing. Move the middleware to before `app.UseBlazor();` – Nkosi Feb 05 '19 at 14:54
  • But i have tried it without a `middleware` class just with the `Use` and `Map`.Still could this be the cause ? I was expecting you can access the `Request` content since you have not yet written in the `Response`.And if i have not read the `Body` , who did ? – Bercovici Adrian Feb 05 '19 at 14:56
  • I tried your code without the `app.UseBlazor();` line and it worked smoothly. – Paul Karam Feb 06 '19 at 09:17
  • Using a defined `middleware` or the plain `delegate` at the end of the post ?I need the `Blazor` since that is the client that sends the request. – Bercovici Adrian Feb 06 '19 at 09:21
  • @BercoviciAdrian using the middleware. Try to swap the Blazor line and the mapping like Nkosi suggested. – Paul Karam Feb 06 '19 at 11:38
  • I have deleted the `blazor` line and i get the same thing. – Bercovici Adrian Feb 06 '19 at 20:15

3 Answers3

1

In your example, the client code calls the route "/mat", but the middleware is configured at "/mid". If the code you're running has the same error, the middleware won't get hit, and you'll always get an empty response that, from the client, looks the same as if the middleware received null. Make sure you're also using the right port number--mine was :5000, but it can vary depending on the runtime configuration.

Are you testing with a debugger and breakpoints? If not, I highly recommend trying. I was able to find that error pretty quickly because I set a breakpoint in the server-side code, and observed that it wasn't getting hit. If a debugger isn't an option, consider "failing loudly" by throwing an exception (instead of simply returning) to make it more obvious whether or not you're actually hitting the condition you think you're hitting.

xander
  • 1,689
  • 10
  • 18
1

Not sure what's exactly wrong with your code, but this works:

public class Startup
{
  // This method gets called by the runtime. Use this method to add services to the container.
  // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
  public void ConfigureServices(IServiceCollection services)
  {
  }

  // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  {
    if (env.IsDevelopment())
    {
      app.UseDeveloperExceptionPage();
    }

    app.Run(async (context) =>
    {
      var request = context.Request;
      var body = request.Body;

      request.EnableRewind();
      var buffer = new byte[Convert.ToInt32(request.ContentLength)];
      await request.Body.ReadAsync(buffer, 0, buffer.Length);
      var bodyAsText = Encoding.UTF8.GetString(buffer);
      request.Body = body;
      await context.Response.WriteAsync(bodyAsText);
    });
  }
}

Running this in chrome dev tools:

fetch('http://localhost:39538', {
  method: 'POST',
  body: JSON.stringify({
    title: 'foo',
    body: 'bar',
    userId: 1
  }),
  headers: {
    'Content-type': 'application/json; charset=UTF-8'
  }
})
.then(res => res.json())
.then(console.log)

Yields the following in the browser:

{"title":"foo","body":"bar","userId":1}

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
0

suppose your request is request= @" {"title":"foo","body":"bar","userId":1}";

call RunTestAsync(request); run just this JsonConvert.SerializeObject(request); I'm sure it fails because its not serializable. and if it is it should be
some object of serializable class

(Serializableclass request)

try this var content = new StringContent(request, Encoding.UTF8, "application/json");

public async Task RunTestAsync(string request) { try { var content = new StringContent(JsonConvert.SerializeObject(request),Encoding.UTF8,"application/json");

   var response=await this.client.PostAsync("http://localhost:8500/mat",
                          content);

    string str=await response.Content.ReadAsStringAsync();
    stringdata = JsonConvert.DeserializeObject<string>(str);
    return data;     
}
catch (Exception ex)
{
    Console.WriteLine("Threw in client" + ex.Message);
    throw;
}

}

Jin Thakur
  • 2,711
  • 18
  • 15