aspnet / AspNetWebStack

ASP.NET MVC 5.x, Web API 2.x, and Web Pages 3.x (not ASP.NET Core)
Other
858 stars 354 forks source link

HttpClient issue when calling older ASP.Net webAPIs from net core #232

Closed Tratcher closed 5 years ago

Tratcher commented 5 years ago

From @chrizy on Friday, 08 February 2019 19:13:17

I’m having an issue when calling an ASP.Net 5.2.3 WebAPI (framework 4.7.2) when using net core as the client. The issue does not happen If compile the test console app using framework 4.7.2. The issue is that the message body does not get serialized in the API controller and will always by null.

network traces below for the same code running against each runtime. It looks like some extra bytes is being added in net core. Thanks

.net core 2.2 (fails)

POST http://croy201703/CrmServer/api/v1/login HTTP/1.1
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Host: croy201703

48
{"username":"Admin","password":"Admin","installID":"test","force":false}
0

.net framework 4.7.2 (works OK)

POST http://croy201703/CrmServer/api/v1/login HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: croy201703
Content-Length: 72

{"username":"Admin","password":"Admin","installID":"test","force":false}

Application calling code used for both tests

            var baseURL = "http://croy201703/CrmServer/";
            var username = "Admin";
            var password = "Admin";

            // Login
            var httpClient = new HttpClient()
            {
                BaseAddress = new Uri(baseURL)
            };
            var loginRequest = new { Username = username, Password = password, InstallID = "test", Force = false };
            var loginResponse = await httpClient.PostAsJsonAsync("api/v1/login", loginRequest);

also tried with not passing as an anonymous type

Copied from original issue: dotnet/corefx#35181

Tratcher commented 5 years ago

From @geoffkizer on Sunday, 10 February 2019 22:43:43

.NET Core is sending the body as chunked, whereas framework is sending using Content-Length. Both are legal. I don't see a problem here.

Tratcher commented 5 years ago

From @davidsh on Sunday, 10 February 2019 23:57:19

The issue is that the message body does not get serialized in the API controller and will always by null.

Perhaps the bug is in your ASP.NET layer. Maybe it assumes 'Content-Length' encoding only for request body? And if it gets 'Transfer-Encoding: chunked' then it might fail with serializing to null?

Tratcher commented 5 years ago

From @davidsh on Monday, 11 February 2019 00:00:16

Also, this code from your client example:

var loginResponse = await httpClient.PostAsJsonAsync("api/v1/login", loginRequest);

where is "loginRequest" defined? I assume it is an HttpContent derived class?

As @geoffkizer mentioned:

.NET Core is sending the body as chunked, whereas framework is sending using Content-Length.

there is a difference in how .NET Framework and .NET Core will transmit a request body in cases where it is ambiguous. If neither 'Content-Length' nor 'Transfer-Encoding: chunked' appear for the request body, each of the frameworks makes a choice. However, you can ensure that a specific choice is made for you by specifically setting either 'Content-Length' or 'Transfer-Encoding: chunked' semantics yourself.

Tratcher commented 5 years ago

From @chrizy on Monday, 11 February 2019 09:56:55

Thanks for the feedback, I suspect the chunked is the issue. The problem as I see it is by default no net core application can talk to older asp net 5.2.3 as asp.net doesn't support or understand the data sent, and does not give an clear indication as to the problem. It seems like an odd default position to be in. Also changing each http request (talking about over 70 apis here) in my net core application to disable chunked is not easy, Unless there is some global setting which can control this? or is there a way to get asp.net to support it?

Tratcher commented 5 years ago

From @davidsh on Monday, 11 February 2019 16:01:27

The root cause here still hasn't been determined but based on your scenario the problem is in ASP.NET and not the client-side HTTP stack (HttpClient).

Unless there is some global setting which can control this? or is there a way to get asp.net to support it?

I suggest you follow up with the ASP.NET core team on this. @Tratcher Can you comment on this?

Tratcher commented 5 years ago

From @Tratcher on Monday, 11 February 2019 16:23:14

@dougbu any thoughts on why MVC 5.2.3 would care about the difference between chunked and content-length? It shouldn't.

@davidsh this can be moved to https://github.com/aspnet/AspNetWebStack.

Tratcher commented 5 years ago

From @davidsh on Monday, 11 February 2019 16:26:12

@davidsh this can be moved to https://github.com/aspnet/AspNetWebStack.

@Tratcher I know there is a tool that does that. But I don't have it installed. Can you move this please and also let me know where the tool is?

dougbu commented 5 years ago

I suspect this is a duplicate of #197. @chrizy could you please check if the problem goes away after upgrading the web site to MVC 5.2.7?

chrizy commented 5 years ago

Hi, Yes issue fixed with 5.2.7. Thanks

dougbu commented 5 years ago

Thank you for your feedback. We're closing this issue as you have confirmed it is fixed in the latest release.

chkeita commented 5 years ago

I am getting the exact same issue when referencing Microsoft.AspNet.WebApi.Client 5.2.7

This code

var httpClient = new HttpClient();
var loginRequest = new { Username = "test", Password = "test", InstallID = "test", Force = false };
httpClient.PostAsJsonAsync("http://postman-echo.com/post", loginRequest).Wait();

Generates this request when targetting .netcoreapp2.2

POST http://postman-echo.com/post HTTP/1.1
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Host: postman-echo.com

46
{"Username":"test","Password":"test","InstallID":"test","Force":false}
0
Tratcher commented 5 years ago

@chkeita That's the expected output. Note the fix was on the server side to accept this format, did you update the server to 5.2.7?

chkeita commented 5 years ago

@Tratcher I am calling an external website that does not seem to support this format. Is it possible to for HttpClient to use the old format? I already tried settings DefaultRequestHeaders.TransferEncodingChunked to false without any success.

Tratcher commented 5 years ago

Not while using PostAsJsonAsync. You'll have to generate the JSON text another way and then use StringContent.