Get Response with HttpClient - c#

I'm trying to use HttpClient to read the response content from a 3rd party API (Rackspace Cloud Files). Here's what I have so far. I can't seem to get the content.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Auth_User", username);
client.DefaultRequestHeaders.Add("X-Auth-Key", api);
client.GetAsync("identity.api.rackspacecloud.com".ToAbsoluteUrl()).ContinueWith(
(requestTask) =>
{
HttpResponseMessage response = requestTask.Result;
response.EnsureSuccessStatusCode();
response.Content.ReadAsAsync<string>().ContinueWith(
(readTask) =>
{
var result = readTask.Result;
});
});
This gives me "No 'MediaTypeFormatter' is available to read an object of type 'String' with the media type 'text/html'." error.
I need to retrieve the response details as noted in the Rackspace docs (example):
HTTP/1.1 204 No Content
Date: Mon, 12 Nov 2007 15:32:21 GMT
X-Storage-Url: https://storage.clouddrive.com/v1/CF_xer7_34
X-CDN-Management-Url: https://cdn.clouddrive.com/v1/CF_xer7_34
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
How do I get the response?
When I use ReadAsStringAsync, it gives my the HTML source of my page.
Thank you.

Related

Read images from Thumbor

I am using Thumbor as Docker image on my PC. I am able to save the image to Thumbor but I am not able to read the image from URL
This is the method I am using to save the file
var httpClient = new HttpClient();
var httpContent = new ByteArrayContent(FileToByteArray(filename));
HttpResponseMessage response = null;
try
{
httpContent.Headers.Add("Content-Type", "image/jpg");
response = httpClient.PostAsync("http://localhost:32773/image", httpContent).Result;
}
catch (HttpRequestException ex)
{
}
And I am using this URL from the postman and it throws an error 400Bad Request
http://localhost:32773/1.jpg
Am I missing something in the URL? Can anyone help me with a sample C# code? appreciate your help!
The correct request URL is:
http://localhost:32773/image/<the original location response>
Here is an example of storing an image
POST http://192.168.2.48:8082/image
HTTP/1.1 201 Created
Date: Thu, 05 Mar 2020 11:56:12 GMT
Content-Length: 0
Content-Type: text/html; charset=UTF-8
Location: /image/8ad1c65a3e6341cfb231b1faf438fc0e/image.jpg
Server: TornadoServer/4.5.3
Fetching the same image:
GET http://192.168.2.48:8082/image/8ad1c65a3e6341cfb231b1faf438fc0e/image.jpg
In short: make sure you store the Location information from the response header when storing an image

Read POST Request body in Web API 2

Just for learning purpose, I am logging all http requests to my Web API 2 application using a handler.
enum LogType {Information = 1, Warning = 2, Error = 3 }
public class LogHandler: DelegatingHandler
{
async protected override Task SendAsync(HttpRequestMessage httpRequest, CancellationToken cancellationToken)
{
Trace.WriteLine(httpRequest.ToString(), LogType.Information.ToString());
var response = await base.SendAsync(httpRequest, cancellationToken);
return response;
}
}
This just prints the Request Headers as follows:
Information: Method: POST, RequestUri: 'http://localhost:49964/school/title?number=1&name=swanand pangam', Version: 1.1, Content: System.Web.Http.WebHost.HttpControllerHandler+LazyStreamContent, Headers:
{
Cache-Control: no-cache
Connection: keep-alive
Accept: text/csv
Accept-Encoding: gzip
Accept-Encoding: deflate
Host: localhost:49964
User-Agent: PostmanRuntime/7.1.1
Postman-Token: 074c3aab-3427-4368-be25-439cbabe0654
Content-Length: 31
Content-Type: text/plain
}
But I am also sending a json object in POST body which is not printed. I want to print both the Headers as well as body. Also I can't find anything in the 'HttpRequestMessage' object while debugging.
You should read the content as below
// log request body
string requestBody = await httpRequest.Content.ReadAsStringAsync();
Trace.WriteLine(requestBody);
This will log the request body.
You can read the post request like following.
string requestBody = await request.Content.ReadAsStringAsync();
var response = await base.SendAsync(httpRequest, cancellationToken);
In case you wan't to log the response also which has been generated, you can try like following.
var responseBody = await response.Content.ReadAsStringAsync();
Above code will have performance implication in you application as it will hit for each and every operation call, you need to be cautious about this. You may consider a flag to enable and disable this.
var body = new StreamReader(Request.Body);
//The modelbinder has already read the stream and need to reset the stream index
body.BaseStream.Seek(0, SeekOrigin.Begin);
var requestBody = body.ReadToEnd();

Using RestSharp to get header value from HttpResponseMessage in web API?

I'm having some trouble getting a token from a HttpResponseMessage using RestSharp. Here is my API controller code:
public HttpResponseMessage Create(long id)
{
var token = _tokenCreator.CreateToken(id);
var response = new HttpResponseMessage();
response.Headers.Add("Token", token);
response.StatusCode = HttpStatusCode.OK;
return response;
}
This is generating the token like I want, and creating the response pictured below. When I call the method with Postman, this is the body of the response that I receive. This is the same result I get if I look at the Content property of the response in my code that sends the request.
Picture of response body.
There is clearly a header section there, but it's not being recognized by RestSharp in my calling code.
public string CreateToken(long id)
{
var client = new RestClient(apiUrl);
var request = new RestRequest(Method.GET)
{
Resource = "tokencreator/create"
}
request.AddQueryParameter("id", id.ToString());
var response = client.Execute(request);
var headers = response.Headers.ToList();
// Here is what I want to do, but does not return a result
var tokenHeader = headers.Find(x => x.Name == "Token");
if(tokenHeader != null)
{
return tokenHeader.Value.ToString();
}
return "no token";
}
If I loop through and print the response's headers, these are the results:
Transfer-Encoding chunked
X-SourceFiles =?UTF-8?B?QzpccHJvamVjdHNcYXBpXEVudGl0bGVtZW50QWNjZXNzXHRva2VuY3JlYXRvclxjcmVhdGU=?=
Content-Type application/json; charset=utf-8
Date Mon, 03 Apr 2017 16:00:18 GMT
Server Kestrel
X-Powered-By ASP.NET
The "Token" header I added in the controller to the response is not there. Is there a simple way to access the "header" section that is appearing in the body of the response?
Edit: Attaching a picture of the "Headers" section of the response from Postman. There is no "Token" header. Any idea why the response.Headers.Add("Token", token) method does not add the header, or am I misunderstanding headers completely?
Picture of headers in Postman response.
So I should have specified that this was a .NET Core application. To fix the problem, I had to go to the Startup.cs file and add the following to the ConfigureServices method:
Change services.AddMvc(); to services.AddMvc().AddWebApiConventions();
You will need the NuGet package Microsoft.AspNetCore.Mvc.WebApiCompatShim, which allows compatibility with the old Web Api 2 way.

Using C# to update a Confluence page I keep getting 405 ERROR

I am trying to update a Confluence page.
I have been able to use this on Confluence localhost, but when I tried it on the production server I got this error:
StatusCode: 405, ReasonPhrase: 'Method Not Allowed', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Vary: Accept-Encoding
Date: Tue, 31 Jan 2017 21:29:44 GMT
Server: Apache/2.2.15
Server: (CentOS)
Content-Length: 342
Allow: GET
Allow: HEAD
Allow: POST
Allow: OPTIONS
Allow: TRACE
Content-Type: text/html; charset=iso-8859-1
}
This is my code. Any idea what would be causing this issue?
string json = "{\"version\":{\"number\":4},\"title\":\"Bloomberg Test\",\"type\":\"page\",\"body\":{\"storage\":{\"value\":\"Hello World\",\"representation\": \"storage\"}}}";
string userpass = username+":"+password;
string encoded = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(userpass));
string encval = "Basic " + encoded;
var content = new StringContent(json, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Atlassian-Token", "nocheck");
client.DefaultRequestHeaders.Add("Authorization", encval);
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.BaseAddress = new Uri(baseurl);
var resp = client.PutAsync(#"/rest/api/content/"+pageid, content);
405 means that the HTTP method (GET, POST, PUT ...) is not allowed.
I don't know the details of Confluence, but try using a POST request
var resp = client.PostAsync(#"/rest/api/content/"+pageid, content);
You're performing an HTTP Put via client.PutAsync(). This is probably allowed locally, but on the server it's not. The response even includes the allowed http methods:
Allow: GET
Allow: HEAD
Allow: POST
Allow: OPTIONS
Allow: TRACE
So if the suggested PostAsync() is not supported by Confluence, adjust the server and allow the PUT method as well.
Replaced:
client.BaseAddress = new Uri(baseurl);
var resp = client.PutAsync(#"/rest/api/content/"+pageid, content);
With:
var resp = client.PutAsync(baseurl+"/rest/api/content/"+pageid, content);
My guess, the BaseAddress is doing something odd like adding a slash at the end or something.
It works now!

Call WebAPI method from MVC4

I have an MVC4 WebAPI project and have a controller FileController that has this Get method in it:
public HttpResponseMessage Get(string id)
{
if (String.IsNullOrEmpty(id))
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "File Name Not Specified");
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
var stream = fileService.GetFileStream(id);
if (stream == null)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "File Not Found");
}
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = id;
return response;
}
In the browser going to localhost:9586/File/myfile.mp3it dispatches the file correctly as an attachment and you can save it. If it is an audio file, you can stream it from the HTML5 audio tag.
Now, I need to call this WebAPI method from an MVC4 web app, basically wrapping it. Here it comes:
public HttpResponseMessage DispatchFile(string id)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:8493/");
HttpResponseMessage response = client.GetAsync("api/File/"+id).Result;
return response;
}
Going to localhost:8493/File/DispatchFile/my.mp3 returns:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: { Pragma: no-cache Connection: Close Cache-Control: no-cache Date: Thu, 05 Sep 2013 15:33:23 GMT Server: ASP.NET Server: Development Server: Server/10.0.0.0 X-AspNet-Version: 4.0.30319 Content-Length: 13889 Content-Disposition: attachment; filename=horse.ogg Content-Type: application/octet-stream Expires: -1 }
So it looks like the Content is indeed StreamContent, but it doesn't return it as a saveable file. Now the question is, how to mirror the behavior when calling the API directly? Any suggestions much appreciated.
I believe the use of HttpClient.Result is not the correct approach here. I think you may need to use the 'Content' property and then call ReadAsStreamAsync to get a handle on the file stream that is returned by your WebAPI method. At that point, you should be able to just write this stream to the response stream, allowing the file to be downloaded / audio to be streamed via HTML5.
See here for an example of using HttpClient to get a file (the link shows how to handle large files, but I believe the approach used there is what you will need to do):
http://developer.greenbutton.com/downloading-large-files-with-the-net-httpclient/

Categories