StringContent vs ObjectContent - c#

I am using System.Net.Http's HttpClient to call a REST API with "POST"
using the following code:
using (HttpRequestMessage requestMessage = new HttpRequestMessage(
HttpMethod.Post, new Uri(request)) { })
{
response = await httpClient.PostAsync(request, objectContent);
}
The "objectContent" is currently this -
objectContent = new ObjectContent(jsonContent.GetType(),
jsonContent,
new JsonMediaTypeFormatter());
I was wondering what difference it makes if this was a StringContent rather than an ObjectContent like this?
objectContent = new StringContent(content);
objectContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
Both work fine. Because it is JSON, i tend to assume that StringContent would make sense. But when is ObjectContent to be used because pretty much all content sent is a "string".

I was wondering what difference it makes if this was a StringContent
rather than an ObjectContent like this?
In your example there won't be any difference. ObjectContent simply allows a "wider" range of types to be sent via HttpClient, while StringContent is narrower for string values only, such as JSON.
StringContent is a slim wrapper around ByteArrayContent, and actually stores the value passed as a byte[]. You simply get the benefit of not needing to transform your string back and forth.
Edit:
Given the fact that you're posting a JSON, you can even make it less verbose by using HttpClientExtensions.PostAsJsonAsync<T>:
await httpClient.PostAsJsonAsync(url, json);

If someone will search how to send request by PostAsync in .NET Core 2.1:
I did not found PostAsJsonAsync method in HttpClient, but your solution with setting:
objectContent = new StringContent(content);
objectContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
"do the job" perfectly also in .NET Core.
Edit:
Additionally If you want add your own header you can type:
objectContent.Headers.Add("Your header", "Value");

ObjectContent is used to format more complex Mime types using built-in or custom-written formatters. It is OK to use ObjectContent for a simple string as well, it doesn't make much difference except for the performance which (IMHO and not checked) may be better with StringContent, since it may have been optimized specifically for strings

Related

HttpRequestMessage won't allow Authorization header value

I'm trying to reuse my HttpClient instance, as that's best practice. Therefore, in one particular request, I want to set the Authorization header on the request, instead of setting it globally on the client. From everything I've read, this ought to work:
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await _client.SendAsync(request);
This compiles, but then throws when I attempt to call it. The exception I get is:
"Misused header name. Make sure request headers are used with
HttpRequestMessage, response headers with HttpResponseMessage, and
content headers with HttpContent objects."
I'm confused why I'm allowed to set this value on the request message if it's just going to throw, and I also haven't figured out a workaround.
I've tried directly adding the header using TryAddWithoutValidation but I still get the same exception (not even a return of false like I'd expect!)
I'm suspecting this might be a bug in the framework since multiple people have posted this exact code with no apparent problems, but would be interested in any insights/workarounds.
Turns out that due to a different bug, the value of "token" was null. I would recommend checking this first if you're having this issue: note that the error message was 100% a lie.

HttpClient.GetStreamAsync() with custom request?

My goal is to use the HttpClient class to make a web-request so that I can write the response to a file (after parsing). Therefore I need the result as a Stream.
HttpClient.GetStreamAsync() only takes the string requestUri as parameter. So there is no possibility to create a request with custom HttpRequestHeader, custom HttpMethod, custom ContentType, custom content and so on?
I saw that HttpWebRequest is sometimes used instead, but in my PCL (Profile111) there is no Add method for the Headers. So can I use HttpClient, should I use HttpWebRequest instead or should I use another class/library at all?
GetStreamAsync is just a shortcut for building and sending a content-less GET request. Doing it the "long way" is fairly straightforward:
var request = new HttpRequestMessage(HttpMethod.???, uri);
// add Content, Headers, etc to request
request.Content = new StringContent(yourJsonString, System.Text.Encoding.UTF8, "application/json");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
var stream = await response.Content.ReadAsStreamAsync();
Since you mentioned being open to using a different library, here's an alternative that uses Flurl (disclaimer: I'm the author). Say you want to POST some JSON data with a couple custom headers and receive a stream:
var stream = await "https://api.com"
.WithHeaders(new { header1 = "value1", header2 = "value2" })
.PostJsonAsync(data)
.ReceiveStream();
Here data is just a POCO. Don't worry about serializing it to a JSON string or setting Content-Type to application/json; Flurl will do both for you.
Flurl uses HttpClient under the hood and targets .NET Standard 1.1, which is fully compatible with PCL Profile111.

RestSharp PUT request parameters

I'm having issues figuring out how to create a put request using RestSharp.
I need to pass an integer followed by a JSON body in the same request.
So far I have this:
for (var i = 0; i < ReorderedTasks.Count; i++) {
var reorderedTasksJson = new JavaScriptSerializer().Serialize(ReorderedTasks[i]);
var request = new RestRequest("api/task/5/{ID}/", Method.PUT);
request.AddParameter("ID", ReorderedTasks[i].ID.ToString(), ParameterType.UrlSegment);
request.AddParameter("application/json; charset=utf-8", reorderedTasksJson, ParameterType.RequestBody);
client.Execute(request);
}
I've tested out the JSON ad requestBody on POST and it works fine. I think my issue is with the first parameter I'm trying to pass ReorderedTasks[i].ID , I'm not sure if I'm handling the passing of this correctly.
I've initialised client at the beginning of my class.
Problem is the DB isn't updating and I need to isolate the problem. Is the above the correct way in dealing with my two parameters needing passed?
I suggest to put ReorderedTasks[i].ID.ToString() directly to url path.
var request = new RestRequest($"api/task/5/{ReorderedTasks[i].ID.ToString()}/", Method.PUT);
It will help to reduce possible problems with http request format.
I'll add it here, so someone will benefit from it.
If your endpoint URL have parameters like ?param=value&param2=value that you want to pass along with request RestSharp's AddParameter(string, string) won't work with PUT method (but it works just fine with GET or if endpoint doesn't have URL parameters, so it is deceiving)
Use AddParameter(string, string, ParameterType.QueryString) in order to PUT Method work correctly.
Well it depends on what does the webApi expect..
You could use Fiddler to inspect what being sent through the wire and what response You are getting (http://www.telerik.com/fiddler)
Also - here are some sample's how other users use RestSharp
How do I use PUT in RestSharp?

previewing what a .NET HttpResponse object will post (obtaining cURL or similar serialised output)

I am not getting the response I am wanting for the following code:
var multipart = new MultipartFormDataContent();
var empty = Encoding.ASCII.GetBytes("\r\n\r\n\r\n");
HttpContent content = new ByteArrayContent(empty);
content.Headers.Add("name", "jform[ical_url]");
multipart.Add(content);
...[cut for brevity]...
using (var handler = new HttpClientHandler { UseCookies = false })
using (var client = new HttpClient(handler) { BaseAddress = new System.Uri("http://icalendar.org") })
{
var response = await client.PostAsync("/validator", multipart);
I know exactly what I would like the POST request to look like (having used Firebug's 'copy cURL' menu item).
Is there a way to see what the client.PostAsync will send, or an extension to serialise the multipart variable above so that I can compare with the cURL string from a successful post?
Thank you.
Overriding the delegating handler has provided some of the answer, as per this SO answer.
I had not clearly explained that this was a class library. I tried Crowcoders advice, but I couldn't get it to work, and as the entire solution contains no WebAPI or MVC or similar projects, and I am trying to post to a validation site to check certain unit tests meet a spec. Briefly looking through the Stackify Prefix docs, I think the ability to handle this kind of scenario is in the pipeline, but not released as yet.
As I would love to know if any defaults are being added to the header (Accept, Language etc), I might look at Fiddler.

Converting PHP array to C# when calling API

I've looked at several related examples on SO and tried a number of methods to get this to work, but I become more confused with each attempt.
I'm trying to search through the Wordpress.org plugin repository API and get a list of plugins from the search results.
The endpoint is: http://api.wordpress.org/plugins/info/1.0/
The two important bits of data to pass are "action" and "search." The action I'm interested in at the moment is "query_plugins", and passing a search string along in the request.
This is a PHP equivalent:
$payload = array(
'action' => 'query_plugins',
'request' => serialize(
(object)array(
'search ' => 'search-phrase',
)
)
);
$body = wp_remote_post( 'http://api.wordpress.org/plugins/info/1.0/', array( 'body' => $payload) );
The only real documentation I've been able to find is from this blog post (which is where I got the above sample code): https://dd32.id.au/projects/wordpressorg-plugin-information-api-docs/
I'm using RestSharp to build the request, with code along these lines:
var client = new RestClient("http://api.wordpress.org/");
var request = new RestRequest("plugins/info/1.0", Method.POST);
request.AddParameter("XXX", "XXX");
var response = client.Execute(request);
var content = response.Content;
the "request.AddParameter("XXX", "XXX"); above is where I'm stuck. I need to build the PHP array equivalent in C# (and serialize it properly?) so that the API will accept the request. I've tried several variants and combinations, from everything as primitive as:
request.AddParameter("action", "query_plugins");
request.AddParameter("search", "keyword");
// and variants such as request.AddParameter("request", "[{ search: keyword }]);
Which I knew wouldn't work (but took a stab with anyway), to using a Dictionary() with the action and search parameters, and attempting to serialize it in several ways (most recent involved JsonConvert.SerializeObject).
At this point I don't know which tree I should be barking up, I have a feeling I'm not even in the right vicinity. I'm not even sure if I should be serializing to JSON, XML, or just a byte-stream (as I understand that's what the PHP serialize() method does, if I'm not mistaken), and I'm not sure the best approach to package all of the data I need to send off in the request.
This seems to work. Instead of POST, use GET
See the working sample here..
https://dotnetfiddle.net/rvL9eC
var client = new RestClient("http://api.wordpress.org/");
var request = new RestRequest("plugins/info/1.0", Method.GET);
request.AddParameter("action", "query_plugins");
request.AddParameter("search", "oauth");
var response = client.Execute(request);
var content = response.Content;

Categories

Resources