I'm facing a problem when using HttpClient. The call works right and I get an answer but I can't get the content properly.
The function I wrote looks like this:
public async Task<string> MakePostRequestAsync(string url, string data, CancellationToken cancel)
{
String res = String.Empty;
using (HttpClient httpClient = new HttpClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
HttpContent content = new StringContent(data, Encoding.UTF8, "application/xml");
httpClient.DefaultRequestHeaders.Authorization = getHeaders();
httpClient.DefaultRequestHeaders.Add("Accept", "application/xml");
httpClient.DefaultRequestHeaders.Add("User-Agent", "C#-AppNSP");
httpClient.DefaultRequestHeaders.ExpectContinue = false;
HttpResponseMessage response = await httpClient.PostAsync(url, content, cancel);
response.EnsureSuccessStatusCode(); // Lanza excepción si no hay éxito
res = await response.Content.ReadAsStringAsync();
if (String.IsNullOrEmpty(res))
{
throw new Exception("Error: " + response.StatusCode);
}
}
return res;
}
The response string I get is similar to this one:
HTTP/1.1 0 nullContent-Type: application/xml;charset=UTF-8
Content-Length: 1263
Date: Tue, 02 Jul 2019 07:48:07 GMT
Connection: close
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SeguimientoEnviosFechasResponse xsi:noNamespaceSchemaLocation="SeguimientoEnviosFechasResponse.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Error>0</Error>
<MensajeError></MensajeError>
<SeguimientoEnvioFecha>
<!-- more XML here -->
</SeguimientoEnvioFecha>
</SeguimientoEnviosFechasResponse>
This string includes headers for some reason, so when I try to deserialize it I get an error.
How can I remove this headers in the response string?
Your server returns headers in the response body. Would be good to fix this on a server side, if it's not possible you should extract body from the response:
var xml = res.Substring(res.IndexOf("<?xml", StringComparison.Ordinal));
You may try this:
using (var receiveStream = response.GetResponseStream())
{
using (var readStream = new StreamReader(receiveStream, Encoding.UTF8))
{
Console.WriteLine (readStream.ReadToEnd ());
}
}
Related
I am calling a super old external webservice which has CSV values inside the response:
--XXXXXXX_0d5d4bd4-93a4-11ec-8139-00000611f70a_END
Content-ID: <payload-621420A61A932740E10080DB995F3244#XXXXXXX.XXX>
Content-Disposition: form-data;filename="MainDocument.bin";name="MainDocument"
Content-Type: application/json
Content-Description: MainDocument
{"mt_csvfile":"csvfile.csv"}
--XXXXXXX_0d5d4bd4-93a4-11ec-8139-00000611f70a_END
Content-ID: <csvfile.csv>
Content-Disposition: form-data;filename="csvfile.csv";name="csvfile.csv"
Content-Type: mimeType text/comma-separated-values;charset="uft-8"
Content-Description: csvfile.csv
"NUMBER","DESCRIPTION",
"00000000001","DESC 1",
"00000000002","DESC 2",
"00000000003","DESC 3",
--XXXXXXX_0d5d4bd4-93a4-11ec-8139-00000611f70a_END--
All I care about is the CSV payload.
How can parse the response?
I am not asking how to parse a CSV file.
I am using httpClient:
var client = new HttpClient();
client.BaseAddress = new Uri("<BASEURL>");
using var content = new MultipartFormDataContent();
var uri = new Uri(client.BaseAddress, "<ENDPOINT>");
var response = await client.PostAsync(uri, content);
response.EnsureSuccessStatusCode();
using (Stream responseStream = await response.Content.ReadAsStreamAsync())
{
// need to get CSV values only
}
In the end I used Http-Multipart-Data-Parser. Credits go to nazarn for giving the hint that there is no default solution and using a package.
var client = new HttpClient();
client.BaseAddress = new Uri("<BASEURL>");
using var content = new MultipartFormDataContent();
var uri = new Uri(client.BaseAddress, "<ENDPOINT>");
var response = await client.PostAsync(uri, content);
response.EnsureSuccessStatusCode();
using (Stream stream = await response.Content.ReadAsStreamAsync())
{
var parser = await MultipartFormDataParser.ParseAsync(stream);
// CSV contents in Last file
var file = parser.Files.Last();
string filename = file.FileName;
Stream data = file.Data;
using (Stream fileStream = File.Create($#"C:\temp\{filename}"))
{
data.Seek(0, SeekOrigin.Begin);
data.CopyTo(fileStream);
}
}
When I run this from a browser manually, it returns a response, that looks like this:
{"value":[{"ID":4}]}
Now, I am POSTing it from a Windows IoT Device, using the following code:
private async Task SendPostRequest(string username, string password, Dictionary<string, string> parameters)
{
try
{
// using Windows.Web.Http
HttpFormUrlEncodedContent formattedData = new HttpFormUrlEncodedContent(parameters);
using (HttpBaseProtocolFilter clientHandler = new HttpBaseProtocolFilter())
{
clientHandler.ServerCredential = GetCredentials(username, password);
using (HttpClient httpClient = new HttpClient(clientHandler))
{
//txtCommand.Text = "PostAsync";
HttpResponseMessage response = await httpClient.PostAsync(postUrl, formattedData);
txtResponse.Text = response.ToString();
response.EnsureSuccessStatusCode();
string responseString = await response.Content.ReadAsStringAsync();
txtResponse.Text += " responseString: " + responseString;
}
}
The result in responseString is an empty string.
The result of response.ToString() looks like this:
StatusCode: 200, ReasonPhrase: 'OK', Version: 2, Content: Windows.Web.Http.HttpStreamContent, Headers:
{
Persistent-Auth: true
Server: Microsoft-IIS/10.0
Transfer-Encoding: chunked
Date: Fri, 27 Aug 2021 15:16:38 GMT
X-Powered-By: ASP.NET
dbgate-version: 1.0
}{
Content-Type: text/plain
}
I am trying to convert the following CURL command:
curl --request POST --url http://localhost:8042/tools/find --data "{\"Level\":\"Study\",\"Query\":{\"Modality\":\"MR\",\"StudyInstanceUID\":\"*\"}}"
to a C# rest client method, using HttpClient without success.
One approach i have been trying is the following:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:8042");
string test = "{\"Level\":\"Study\",\"Query\":{\"Modality\":\"MR\",\"StudyInstanceUID\":\"*\"}}";
var requestContent = new StringContent(test, Encoding.UTF8, "application/x-www-form-urlencoded");
var response = await client.PostAsync("tools/find", requestContent);
HttpContent responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// Write the output.
Console.WriteLine(await reader.ReadToEndAsync());
return await reader.ReadToEndAsync();
}
}
But either i am getting some timeout exceptions or the returned result in NULL.
This is what i am getting when i run the CURL command:
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1...
* TCP_NODELAY set
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8042 (#0)
> POST /tools/find HTTP/1.1
> Host: localhost:8042
> User-Agent: curl/7.55.1
> Accept: */*
> Content-Length: 66
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 66 out of 66 bytes
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Type: application/json; charset=utf-8
< Content-Length: 1023
<
[
"06a5bb05-acf327ff-1b1f7432-543a3572-d0778630",
"0d2858ee-9bb9557f-6779c861-4e55604a-bbd9d561",
"241d9063-668f6d5a-84d5e791-aae25988-cbe330e4",
"2a47771d-a7fed498-2ea74733-6ba5b408-0af517d0",
"2c22461c-2529103d-1c3bbf0e-5c1011b7-ef4c4702",
"2e89270f-77b2368b-ec8f7a47-48922528-6d82a563",
"46151c0f-a92e4ffe-b3964a0b-0a217ff0-e138a9b0",
"4ac07d24-df6720d8-410ded38-80c42f81-029b826d",
"6ae5803f-564d02d6-ce2d03c9-87029ebb-c5f5b783",
"6c4dd689-5dc50cc7-7c0b07e1-231c8f06-10a50343",
"79a0e646-d244dced-2a2ac6d0-e61e6029-38b1e61e",
"7beb9698-c3e13f1a-5449e8c0-06f61be7-0285b222",
"8c35bbfa-1f00d0bb-50fdddea-c8b8f085-20ef243a",
"9a318c16-75a5cae8-3f42dd60-2ab5d0c0-664e78d1",
"a7b43909-4ecfe2fe-12f414ad-dc1d013e-0665e60b",
"b85380e8-e66db7da-d575e3d3-80bce548-71d5c251",
"d07b73c3-77cad4ff-1bf045d9-d8677f33-cd4c79f5",
"ec81b8b0-c6f95b97-2a2299ca-fa4d3f68-d79f0079",
"ec9c971a-e66c350c-f808f182-7716b99c-4c8f6f86",
"efe910b9-3bb0e298-c9ec181b-3985c6be-a6b74a89"
]
* Connection #0 to host localhost left intact
Any ideas about how can i convert this command to working c# code?
don't repeat the full URL in PostAsync if you are setting BaseAddress
using (var client = new HttpClient()){
client.BaseAddress = new Uri("http://localhost:8042");
...
var response = await client.PostAsync("tools/find", requestContent);
...
}
After some research and testing here is the code to make a corresponding to curl:
curl --request POST --url http://localhost:8042/tools/find --data "{\"Level\":\"Study\",\"Query\":{\"Modality\":\"MR\",\"StudyInstanceUID\":\"*\"}}"
post request in C#:
public async System.Threading.Tasks.Task<string> MyMethod(string studyInstanceUID)
{
using (var client = new HttpClient())
{
string data = "{\"Level\":\"Study\",\"Query\":{\"Modality\":\"MR\",\"StudyInstanceUID\":\"" + studyInstanceUID + "\"}}";
var requestContent = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
client.DefaultRequestHeaders.Add("User-Agent", "Anything");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
if (reqAuth)
{
var byteArray = Encoding.ASCII.GetBytes(authString);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
}
HttpResponseMessage response = await client.PostAsync(baseUrl + "tools/find", requestContent);
var responseContent = response.Content;
return responseContent.ReadAsStringAsync().Result;
}
}
If you don't mind using a small wrapper library, Flurl (disclaimer: I'm the author), which wraps HttpClient and Json.NET, makes this about as simple as using cURL.
using Flurl.Http;
var results = await "http://localhost:8042/tools/find"
.PostJsonAsync(new { Level = "Study", Query = new { Modality = "MR", StudyInstanceUID = "*" }})
.ReceiveJson<string[]>();
Note that JSON serializaiton is handled implicitly, so you're only ever dealing with strongly typed C# objects, rather than stringifying/parsing the JSON that goes in and comes out.
This is driving me nuts, I am setting the ContentType header everywhere I can and can't seem to make it stop sending text/plain.
Watching the data in Fiddler, the request is always requesting:
POST http:/domain.com HTTP/1.1
Content-Type: text/plain; charset=utf-8
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post, "http://domain.com");
request.Content = new StringContent(Serialize(obj), Encoding.UTF8, "text/xml");
request.Content.Headers.Clear();
request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
request.Headers.Clear();
request.Headers.Add("Content-Type","text/xml");
var response = await httpClient.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
It looks like you tried to hard :) This should just work.
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post, "http://domain.com");
request.Content = new StringContent(Serialize(obj), Encoding.UTF8, "text/xml");
var response = await httpClient.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
Try settings the default request headers:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
Use "application/xml" instead of "text/xml"
I'm looking for solution to send request with JSON like parameter to server.
I use this code,
var httpClient = new HttpClient();
var tempByteArray = Encoding.UTF8.GetBytes("my valid json");
var stream = new MemoryStream(tempByteArray);
var streamContent = new StreamContent(stream);
var request = new HttpRequestMessage(HttpMethod.Post, Constants.LocalServer);
request.Content = streamContent;
request.Headers.TransferEncodingChunked = true;
HttpResponseMessage response = await httpClient.SendAsync(request);
But in response I get:
{
StatusCode: 501,
ReasonPhrase: 'NotImplemented',
Version: 1.0,
Content: System.Net.Http.StreamContent,
Headers: {
X-Squid-Error: ERR_UNSUP_REQ0X-Cache: MISSfromproxy3.itos.orgX-Cache-Lookup: NONEfromproxy3.companyname.org: portProxy-Connection: closeDate: Thu,
18Apr201309: 17: 53GMTServer: squid/2.6.STABLE21Via: 1.0proxy3.companyname.org: port(squid/2.6.STABLE21)Content-Length: 1099Content-Type: text/htmlExpires: Thu,
18Apr201309: 17: 53GMT
}
}
May be have another way to sent request with json parameter on Win8?
UPDATE I found solution:
public static async Task<string> LoadData(string json, string serverUrl)
{
var request = (HttpWebRequest)WebRequest.Create(new Uri(Constants.LocalServer));
request.ContentType = "application/json";
request.Method = "POST";
using (var requestStream = await request.GetRequestStreamAsync())
{
var writer = new StreamWriter(requestStream);
writer.Write(json);
writer.Flush();
}
using (var resp = await request.GetResponseAsync())
{
using (var responseStream = resp.GetResponseStream())
{
var reader = new StreamReader(responseStream);
return = reader.ReadToEnd();
}
}
}
It's work great, but must exists more simple way(i hope). And I'll try to find it.
When I post data using your two code snippets, I see some differences in the requests.
Here is the raw post for the first code sample (that you say does not work):
POST http://testing.foo.com/api/Values HTTP/1.1
Host: testing.foo.com
Expect: 100-continue
Connection: Keep-Alive
Content-Length: 75
{
id:"1",
title:"title text",
post:"post text",
isDeleted:"False"
}
This is the raw post for the code in your update (code that you say works):
POST http://testing.foo.com/api/Values HTTP/1.1
Content-Type: application/json
Host: testing.foo.com
Content-Length: 75
Expect: 100-continue
{
id:"2",
title:"title text",
post:"post text",
isDeleted:"False"
}
The differences in the two requests are as follows:
In the first request, the content type is never set.
In the first request, the content is UTF8 encoded.
To fix your non-working code, I would suggest you try one or both of the following:
Set the content type to application/json
Not UTF8 encode the request
At that moment this solution is most useful.
public static async Task<string> LoadData(string json, string serverUrl)
{
var request = (HttpWebRequest)WebRequest.Create(new Uri(Constants.LocalServer));
request.ContentType = "application/json";
request.Method = "POST";
using (var requestStream = await request.GetRequestStreamAsync())
{
var writer = new StreamWriter(requestStream);
writer.Write(json);
writer.Flush();
}
using (var resp = await request.GetResponseAsync())
{
using (var responseStream = resp.GetResponseStream())
{
var reader = new StreamReader(responseStream);
return = reader.ReadToEnd();
}
}
}