c# httpclient post force single packet - c#

Using Microsoft Message Analyzer, I can see that post data using the HttpClient is being sent in two tcp packets. One for the header, then one for the post data. This data could easily fit into one packet, however it is being split into two. I have explicitly turned on nagling and expect 100 continue off using the ServicePointManager, though, it doesn't seem to help.
ServicePointManager.Expect100Continue = false;
ServicePointManager.UseNagleAlgorithm = true;
5023 (.Net) shows 2 packets are sent to destination, 8170 (Postman) shows 1 packet being sent. Tests were done with the same payload.
Below is some sample code used to generate the request in .net
public void TestRequest()
{
var uri = new Uri("http://www.webscantest.com/");
ServicePointManager.Expect100Continue = false;
ServicePointManager.UseNagleAlgorithm = true;
var p = ServicePointManager.FindServicePoint(uri);
p.Expect100Continue = false;
p.UseNagleAlgorithm = true;
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Connection", "close");
var values = new Dictionary<string, string>
{
{ "thing1", "hello" },
{ "thing2", "world" }
};
var content = new FormUrlEncodedContent(values);
var response = client.PostAsync("http://www.webscantest.com/", content, CancellationToken.None).Result;
}
Is there a way to force the payload into a single packet?
Using .Net Framework 4.7
related question here

So after looking at the dotnet core source code (can only assume the same in other .net versions), I can see in the WinHttpHandler that the Request Header and Request Body are sent at different points.
The request header is sent with Interop.WinHttp.WinHttpSendRequest. Then the request body with Interop.WinHttp.WinHttpWriteData which according to the WinHttp docs, will "Wait until WinHttpSendRequest has completed before calling this function".
I think this issue could be solved, if the request body was sent with the WinHttpSendRequest, which currently sets the body as IntPtr.Zero.
Request Header here
Request Body here

Related

Azure function Error : received an unexpected eof or 0 bytes from the transport stream

I have a requirement where I am calling an API (programmatically PUT Method) from another API.
Both of the APIs are hosted as Azure Function App.
The request has nearly 600 rows.
The below method call is throwing the error: received an unexpected EOF or 0 bytes from the transport stream
If I send a request say 100-150 rows, it processes successfully.
I think that it is nothing to do with the code, it is related to the Azure Function app.
Please let me know if I need to add any configuration to the Azure Function app.
Thanks in Advance.
public async Task<List<CarPricing>> TestMethod(CarPricingModel request, string resourcePath,string token)
{
try
{
using var stream = StreamUtility.GenerateStreamFromString(JsonConvert.SerializeObject(request));
using var data= new StreamContent(stream);
data.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var queryParams = new Dictionary<string, string>()
{
{"id", "XXXXXXXXXXXXXXXXXXXXXX" }
};
var relativeUrl = QueryHelpers.AddQueryString(resourcePath, queryParams);
using var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Put,
Content = content,
RequestUri = new Uri(relativeUrl, UriKind.Relative)
};
var httpResponseMessage = await _httpClient.SendAsync(requestMessage);
httpStatusCode = httpResponseMessage.StatusCode;
var httpResponse = await httpResponseMessage.Content.ReadAsStreamAsync();
using var responseContent = new JsonTextReader(new StreamReader(httpResponse));
var response = new JsonSerializer().Deserialize<List<CarPricing>>(responseContent);
return response;
}
catch (Exception ex)
{
_log.LogError("API error {err_msg}",ex.Message);
throw;
}
}
Check the below steps that might help to fix the issue:
received an unexpected eof or 0 bytes from the transport stream
This error generally occurs during the HTTP Calls of .NET Core Applications.
TLS/SSL binding is supported in the Azure Function App. You can bind it through Azure Portal and using the Code.
If you’re using the HTTPS Protocol, apply this SSL Call before the request made as mentioned in the comments:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
or
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Ssl3| SecurityProtocolType.Tls| SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12
but the above error might come for many causes such as:
Client IP may be restricted, which you can add in Access Restrictions of the Function app API.
Typo Mistake or Incorrect URL of the API that is called programmatically from another Azure Function API.
Refer to this MS Doc for using the TLS/SSL Certificate Programmatically and SO Thread that shows how to use the TLS/SSL Certificate in Azure Function App.

HttpClient.SendAsync sending wrong Content-Type

HttpClient httpClient = new HttpClient();
MyRequest request = new MyRequest (data);
var content = new StringContent(System.Text.Json.JsonSerializer.Serialize(request), System.Text.Encoding.UTF8, "application/json");
HttpRequestMessage httpRequestMessage = new HttpRequestMessage
{
RequestUri = new Uri("http://localhost:8000/api/action"),
Content = content,
Method = HttpMethod.Post
};
httpRequestMessage.SetBrowserRequestMode(BrowserRequestMode.NoCors);
await httpClient.SendAsync(httpRequestMessage);
Using HttpClient in Blazor WebAssembly I am trying to send a request to an API.
However, despite specifying application/json as the content type it sends text/plain;charset=UTF-8 (as viewed in the Chrome Network tab). This results in the API throwing an error.
I think you could check these case:
case1,case2
read this document,and try with PostAsJsonAsync method
I tested as below and worked well:
var weatherforecast = new WeatherForecast() { Date = DateTime.Now, Summary = "testsummary", TemperatureC = 44 };
var response = await Http.PostAsJsonAsync("https://localhost:44385/WeatherForecast", weatherforecast);
Result:
Related post:
Wrong Content-Type being substituted for fetch http request
HttpClient in WebAssembly calls the standard fetch method.
As per the fetch specification when using no-cors only a limited number of content-types can be used:
https://fetch.spec.whatwg.org/#simple-header
"application/x-www-form-urlencoded"
"multipart/form-data"
"text/plain"
The preferred solution would be to correctly configure the end point you are calling to allow cross origin requests and not to use no-cors e.g:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
Access-Control-Allow-Origin: *
If this is not possible (as in my case) and you must use no-cors the only other option would be to change your end point to map "text/plain" to "application/json"
Whilst many may not consider this a bug it is an inconsistency in how HttpClient behaves and is not obvious (though the NoCors option is only available in WebAssembly)

implement cURL command in C# (synchronous, post, TLS 1,2)

Here's a generic cURL command to copy a csv file from a server to c:\temp.
curl.exe --data "ARG1=value&ARG2=value" "https://some.server.com/data.csv" > "c:\temp\data.csv"
How would you code this a synchronous method in C# using a post method and TLS 1.2?
byte[] data;
using (WebClient client = new WebClient()) {
data = client.DownloadData("https://some.server.com/data.csv?arg1=value&ARG2=value");
}
File.WriteAllBytes(#"c:\temp\data.csv", data);
After some fiddling found this to work:
using System.Net.Http;
...
var values = new Dictionary<string, string>() { { "arg1", "value1" }, { "arg2", "value2" } };
var content = new FormUrlEncodedContent(values);
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; // enable TLS 1.2
HttpResponseMessage responseMsg = new HttpClient().PostAsync(#"http://some.server.com/data.csv", content).Result;
if (responseMsg.StatusCode != System.Net.HttpStatusCode.OK) throw new Exception("err msg");
File.WriteAllText(#"c:\temp\data.csv", responseMsg.Content.ReadAsStringAsync().Result);
...
This code worked for me (I can't show the actual site). The site in question is a data vendor who used to accept simple HTTP GET requests but is now switching to POST with SSL and TSL 1.2 in order to comply with EU rules.
I am not claiming that this code is robust, thread safe, or anything like that. Just that I got it working. So that's a start.

Streaming Content constantly updating 8x8 streaming service

I have tried to create a simple console application.
We have a call system from 8x8 that provide a web streaming API but their documentation is very limited and nothing in C#.
The api service streams call statuses in near real time and I would like to get that 'stream' and be able to read and process it in realtime if possible. The response or Content Type is 'text/html'. But the actual body of the response can be declared as json - sample below:
{"Interaction":{"attachedData":{"attachedDatum":[{"attachedDataKey":"#pri","attachedDataValue":100},{"attachedDataKey":"callingName","attachedDataValue":999999999999},{"attachedDataKey":"cha","attachedDataValue":99999999999},{"attachedDataKey":"cnt","attachedDataValue":0},{"attachedDataKey":"con","attachedDataValue":0},{"attachedDataKey":"med","attachedDataValue":"T"},{"attachedDataKey":"pho","attachedDataValue":9999999999},{"attachedDataKey":"phoneNum","attachedDataValue":9999999999},{"attachedDataKey":"tok","attachedDataValue":999999999}]},"event":"InteractionCreated","inboundChannelid":9999999999,"interactionEventTS":9999999,"interactionGUID":"int-15b875d0da2-DJOJkDhDsrh3AIaFP8VkICv9t-phone-01-testist","resourceType":0}}
I have seen several posts concerning httpClient and the GetAsync methods but none of these appear to work as they appear to be for calls when a response is made, not something that constantly has a response.
Using fiddler for the call it does not appear to close so the stream is constantly running, so fiddler does not display any data until a separate user or instance connects.
When I use a browser the content is 'streamed' to the page and updates automatically and shows all the content (as above).
The api contains authentication so when another client connects and retrieves data the connected client closes and finally I am able to see the data that was gathering.
This is the code so and does return the big stream when another client connects but ideally I want a real time response and appears to just get stuck in the GETASYNC method:
var response = await client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead);
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
string responseString = await responseContent.ReadAsStringAsync();
Console.WriteLine(responseString);
}
Hopefully that's enough information for one of you clever people to help me in my predicament.
I was also having an issue consuming their streaming API and the examples I found that worked with the Twitter and CouchBase streaming API's did not work with 8x8. Both Twitter and CouchBase send line terminators in their pushes so the solution relied on ReadLine to pull in the feed. Since 8x8 does not send terminators you'll need to use ReadBlock or better ReadBlockAsync.
The following code shows how to connect using credentials and consume their feed:
private static async Task StreamAsync(string url, string username, string password)
{
var handler = new HttpClientHandler()
{
Credentials = new NetworkCredential {UserName = username, Password = password},
PreAuthenticate = true
};
// Client can also be singleton
using (var client = new HttpClient(handler))
{
client.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Connection.Add("keep-alive");
using (var response = await client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead))
{
using (var body = await response.Content.ReadAsStreamAsync())
{
using (var reader = new StreamReader(body))
{
while (!reader.EndOfStream)
{
var buffer = new char[1024];
await reader.ReadBlockAsync(buffer, 0, buffer.Length);
Console.WriteLine(new string(buffer));
}
}
}
}
}
}

Trouble with HTTP post in Android

I am fairly new at android development. Here is my problem:
I have this endpoint: http://bdzservice.apphb.com/api/Image which accepts POST requests
The body of the request is a String, example:
/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030
Invalid example: {"/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
Invalid example2: {mapHref : "/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
Invalid example3: {"mapHref" : "/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
this is the code I've written so far:
HttpClient client = new DefaultHttpClient();
String message;
HttpPost httpPost = new HttpPost("http://bdzservice.apphb.com/api/Image");
try
{
message = url;
StringEntity se = new StringEntity(message, "UTF8");
se.setContentType("application/json");
httpPost.setEntity(se);
httpPost.setHeader("Content-type", "application/json");
HttpResponse resp = client.execute(httpPost);
if (resp != null)
{
if (resp.getStatusLine().getStatusCode() == 204)
result = true;
}
Log.d("Status line", "" + resp.getStatusLine().getStatusCode());
}
I always get an error when trying to post data, but when I manually (through a REST client) post data I get an OK result.
Can someone help me with this?
EDIT
This is the endpoint, It is written in C# (Web Api)
EDIT 2: Tried modifying the service to return body it recieved (see the comment in the url) and it retruns null, so the problem is it is not getting the body (or just reading it wrong)
I have created a library here for .NET Standard that does POST and PUT. I have tested it thoroughly on Android. There are quick start samples to get going quickly. The sample only has a PUT, but the principle should be the same:
https://bitbucket.org/MelbourneDeveloper/restclient-.net/overview

Categories

Resources