HttpResponseMessage.Content.ToString(); Comes back as System.Net.Http.SteamContent - c#

I am trying to consume an API in C#, this is the code for the request. It should be a simple JSON API, however I'm getting some irregularities here.
public static HttpResponseMessage sendRequest(List<Header> headers, string endpoint, string api_key, string api_secret)
{
using (var client = new HttpClient())
{
List<Header> headerlist = new List<Header>{};
if(headers != null)
headerlist = headers;
List<Header> signed = Helpers.sign(endpoint, api_secret);
foreach (Header header in signed)
{
headerlist.Add(header);
}
client.BaseAddress = new Uri("https://api.coinkite.com");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("X-CK-Key", api_key);
foreach (Header header in headerlist)
{
client.DefaultRequestHeaders.Add(header.Name, header.Data);
}
HttpResponseMessage response = client.GetAsync(endpoint).Result;
return response;
}
}
Which I am calling via
HttpResponseMessage result = Requests.sendRequest(null, "/v1/my/self", api_key, api_secret);
return result.Content.ToString();
However, when I write that to console it looks like:
System.Net.Http.SteamContent
Any clue as to what the issue is? I am not too familiar with the stream content type.

HttpContent does not implement ToString method. So you need to use result.Content.CopyToAsync(Stream) to copy the result content to a Stream.
Then you can use StreamReader to read that Stream.
Or you can use
string resultString = result.Content.ReadAsStringAsync().Result;
to read the result as string directly.This method no need to use StreamReader so I suggest this way.

Call GetResponse() on the HttpResponseMessage
Stream stream = result.GetResponseStream();
StreamReader readStream = new StreamReader(stream, Encoding.UTF8);
return readStream.ReadToEnd();

If you are only interested in the contents, you can get the string directly by changing
HttpResponseMessage response = client.GetAsync(endpoint).Result;
to
string response = client.GetStringAsync(endpoint).Result;
https://msdn.microsoft.com/en-us/library/hh551746(v=vs.118).aspx

Related

PostAsync API giving Bad Gateway

I am invoking a third party POST API from my own API (again POST METHOD). The third party API is having a security key, and it is working fine on the POSTMAN tool. However, when I tries to invoke through code, I am getting error, 'Bad Gateway'. Following is the code which I tried.
public static async Task<string> GetDetailsfromThirdParty(string kszstrng)
{
string contentstring = string.Empty;
using (var client = new HttpClient())
{
string baseURL = "https://abcde.kz.in/b2/vhsearch-all";
string prms = kszstrng;// input parameters to API, in JSON Format- this is JSON String.
try
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Add("key", "value");
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
byte[] messageBytes = System.Text.Encoding.UTF8.GetBytes(prms);
var content = new ByteArrayContent(messageBytes);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
var response = await httpClient.PostAsync(baseURL, content).ConfigureAwait(false);
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
contentstring = result;
}
}
catch (Exception ex)
{
string msg = ex.Message.ToString();
}
return contentstring;
}
}
I am getting error on this line:
var response = await httpClient.PostAsync(baseURL, content).ConfigureAwait(false);
While trying to execute I am getting the below error:
Not able to find out what's the issue? There is no network / Fireawall blockage. I have cross-verified with Systems Team as well.
Please suggest any issue with the code.
First of all, i recommend you to not declare the HttpClient in a using statement since this can cause a socket exhaustion (because the connections will stay open).
(see the docs for details)
Go for a static HttpClient (or use the IHttpClientFactory if you're project is .net Core).
I can't test your code since I'm not able to access this api.
But give it a try using a cleaner approach:
// static HttpClient
private static readonly HttpClient _HttpClient = new HttpClient();
// Can be used to set the baseUrl of the HttpClient from outside
public static void SetBaseUrl(Uri baseUrl)
{
_HttpClient.BaseAddress = baseUrl;
}
public static async Task<string> GetDetailsfromThirdParty(string kszstrng)
{
string contentstring = string.Empty;
string baseURL = "https://abcde.kz.in/b2/vhsearch-all";
string prms = kszstrng; // input parameters to API, in JSON Format- this is JSON String.
try
{
// Be aware of which headers you wanna clean if using the static HttpClient
_HttpClient.DefaultRequestHeaders.Accept.Clear();
_HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_HttpClient.DefaultRequestHeaders.Add("key", "value");
_HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
byte[] messageBytes = Encoding.UTF8.GetBytes(prms);
var content = new ByteArrayContent(messageBytes);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await _HttpClient.PostAsync(baseURL, content).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
contentstring = result;
}
}
catch (Exception ex)
{
// your exception handling
}
return contentstring;
}
Issue resolved. While forming the object to JSON String, there was an opening and closing angle brackets ([,]). Even though this is coming automatically while converting to JSON string, this was not accepted string at the vendor end. So I removed it and works perfectly. Thanks every one for the support.

How to post and receive a file with web api

I have a Api Post method that I want to be able to accept any file type and that looks like this:
[HttpPost]
public async Task<IHttpActionResult> Post()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
if (provider.Contents.Count != 1)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest,
"You must include exactly one file per request."));
}
var file = provider.Contents[0];
var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
var buffer = await file.ReadAsByteArrayAsync();
}
This works in fiddler when I try to post an image to it. However, I'm writing a client library and I have a method that looks like this:
public string PostAttachment(byte[] data, Uri endpoint, string contentType)
{
var request = (HttpWebRequest)WebRequest.Create(endpoint);
request.Method = "POST";
request.ContentType = contentType;
request.ContentLength = data.Length;
var stream = request.GetRequestStream();
stream.Write(data, 0, data.Length);
stream.Close();
var response = (HttpWebResponse) request.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}
Whenever I try to post an image using this, I'm getting a UnsuportedMediaType error. I'm assuming it's because my image isn't Multi Part Content? Is there an easy way to make my request of the correct type?
If I have to change my web api post method, is there an easy way of doing that without writing files to the server and keeping it in memory?
The MultipartFormDataContent from the System.Net.Http namespace will allow you to post multipart form data.
private async Task<string> PostAttachment(byte[] data, Uri url, string contentType)
{
HttpContent content = new ByteArrayContent(data);
content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
using (var form = new MultipartFormDataContent())
{
form.Add(content);
using(var client = new HttpClient())
{
var response = await client.PostAsync(url, form);
return await response.Content.ReadAsStringAsync();
}
}
}

How to make HttpClient ignore Content-Length header

I am using HttpClient to communicate with a server which I don't have access to. Sometimes the JSON response from the server is truncated.
The problem occurs when the Content-Length header is smaller than what it should be (8192 vs. 8329). It seems like a bug on the server which gives a smaller Content-Length header than the actual size of the response body. If I use Google Chrome instead of HttpClient, the response is always complete.
Therefore, I want to make HttpClient to ignore the wrong Content-Length header and read to the end of the response. Is it possible to do that? Any other solution is well appreciated. Thank you!
This is the code of my HttpClient:
var client = new HttpClient();
client.BaseAddress = new Uri(c_serverBaseAddress);
HttpResponseMessage response = null;
try
{
response = await client.GetAsync(c_serverEventApiAddress + "?location=" + locationName);
}
catch (Exception e)
{
// Do something
}
var json = response.Content.ReadAsStringAsync().Result;
var obj = JsonConvert.DeserializeObject<JObject>(json); // The EXCEPTION occurs HERE!!! Because the json is truncated!
EDIT 1:
If I use HttpWebRequest, it can read to the end of the JSON response completely without any truncation. However, I would like to use HttpClient since it has better async/await.
This is the code using HttpWebRequest:
var url = c_serverBaseAddress + c_serverEventApiAddress + "?location=" + "Saskatchewan";
var request = (HttpWebRequest)WebRequest.Create(url);
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "GET";
request.ContentType = "application/x-www-form-urlencoded";
var response = (HttpWebResponse)request.GetResponse();
StringBuilder stringBuilder = new StringBuilder();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string line;
while ((line = reader.ReadLine()) != null)
{
stringBuilder.Append(line);
}
}
var json = stringBuilder.ToString(); // COMPLETE json response everytime!!!
You could try specifying the buffer size of the response content
var client = new HttpClient();
client.MaxResponseContentBufferSize = <your_buffer_size>;
Where the property MaxResponseContentBufferSize means:
Gets or sets the maximum number of bytes to buffer when reading the response content.

Deserialize byte[] from ASP Web Api IHttpActionResult

I am trying work out the correct & best way to deserialize the response from a Asp.Net Web Api method that returns byte[].
The Web Api method looks like this
public IHttpActionResult Get()
{
byte[] content = GetContent();
return Ok(content);
}
I am calling the endpoint
string content;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
HttpResponseMessage response = await client.GetAsync("api/v1/thecorrectpath");
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
}
}
When I read the response into content it is in the format below
<base64Binary xmlns="http://schemas.microsoft.com/2003/10/Serialization/">SfSEjEyNzE9MNgMCD2a8i0xLjcNJeLjzC...R4Cg==</base64Binary>
What would be a best practice way to convert this response into a byte[]?
I would use json.net for this.
Web API:
public string Get()
{
byte[] content = GetContent();
var data = JsonConvert.SerializeObject(content);
return data;
}
Client:
private static async Task GetData()
{
string content;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:23306/");
client.DefaultRequestHeaders.Accept.Clear();
HttpResponseMessage response = await client.GetAsync("home/get");
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<byte[]>(content);
}
}
}
You can return binary data from a Web Api method.
The ms object is a memory stream
You might want to set a more specific ContentType
On the server:
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(ms.ToArray());
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
Then on the client:
response.Content.ReadAsByteArrayAsync();
First, install nuget package Microsoft.AspNet.WebApi.Client ;
Then use the generic extension method of http content:
c#
var result = await response.Content.ReadAsAsync<byte[]>();
It should works!

JSON payload for HttpClient in C#?

How to pass in a JSON payload for consuming a REST service.
Here is what I am trying:
var requestUrl = "http://example.org";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualifiedHeaderValue("application/json"));
var result = client.Post(requestUrl);
var content = result.Content.ReadAsString();
dynamic value = JsonValue.Parse(content);
string msg = String.Format("{0} {1}", value.SomeTest, value.AnotherTest);
return msg;
}
How do I pass something like this as a parameter to the request?:
{"SomeProp1":"abc","AnotherProp1":"123","NextProp2":"zyx"}
I got the answer from here:
POSTing JsonObject With HttpClient From Web API
httpClient.Post(
myJsonString,
new StringContent(
myObject.ToString(),
Encoding.UTF8,
"application/json"));
Here's a similar answer showing how to post raw JSON:
Json Format data from console application to service stack
const string RemoteUrl = "http://www.servicestack.net/ServiceStack.Hello/servicestack/hello";
var httpReq = (HttpWebRequest)WebRequest.Create(RemoteUrl);
httpReq.Method = "POST";
httpReq.ContentType = httpReq.Accept = "application/json";
using (var stream = httpReq.GetRequestStream())
using (var sw = new StreamWriter(stream))
{
sw.Write("{\"Name\":\"World!\"}");
}
using (var response = httpReq.GetResponse())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
Assert.That(reader.ReadToEnd(), Is.EqualTo("{\"Result\":\"Hello, World!\"}"));
}
As a strictly HTTP GET request I don't think you can post that JSON as-is - you'd need to URL-encode it and pass it as query string arguments.
What you can do though is send that JSON the content body of a POST request via the WebRequest / WebClient.
You can modify this code sample from MSDN to send your JSON payload as a string and that should do the trick:
http://msdn.microsoft.com/en-us/library/debx8sh9.aspx

Categories