FormUrlEncodedContent works but StringContent does not - c#

I have a question about those 2 httpcontents.
I've made an webapi (php), copy from this: http://www.9lessons.info/2012/05/create-restful-services-api-in-php.html
I re-used the Rest.inc.php, and implement my own api file.
I try to call this api from .Net (I'm a .Net developer) - a simple WinForm Application - the FormUrlEncodedContent works but the StringContent does not.
This my code:
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("username", username);
parameters.Add("title", title);
parameters.Add("text", text);
var jsonString = JsonConvert.SerializeObject(parameters);
var content = new StringContent(jsonString, Encoding.UTF8, "text/json");
//var content = new FormUrlEncodedContent(parameters);
PostData(url, content);
And the reason why I want to use StringContent: in the real data, sometime the parameters will contain a byte[] (photo), and the FormUrlEncodedContent can't handle it
Please help me
Thanks alot!

They are very different formats. If the api does not have a smart model binder like Asp.Net Web API then it will not work. You can always base64 encode your byte array which is the typical way to transmit bytes via HTTP.

Related

How to make HttpClient.PostAsync work the same way as post from Postman?

When I post to my API (written in .NET core and hosted on Linux) from Postman, everything works as expected. When I do the same from code (using HttpClient), the parameters do not get sent. Below my code:
var content = new FormUrlEncodedContent(new []
{
new KeyValuePair<string, string>(nameof(userName), userName),
new KeyValuePair<string, string>(nameof(serialNumber), serialNumber)
});
var result = await _httpClient.PostAsync(_uri, content).ConfigureAwait(false);
var json = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<Response>(json);
In my opinion content should get sent and everything should be alright. I see significant differences between the calls in Wireshark.
Working POST from Postman:
POST from HttpClient that does not work:
.
What can I do to make sure that my HttpClient.PostAsync sends the data correctly?
The Postman version doesn't have a body, but it has userName and serialNumber encoded into the url as query parameters.
In order to achieve the same using HttpClient, you need to add those parameters to the url.
var uriBuilder = new UriBuilder(_uri);
// If you already have query parameters, this code will preserve them.
// Otherwise you can just create a new NameValueCollection instance.
var parameters = HttpUtility.ParseQueryString(uriBuilder.Query);
parameters[nameof(userName)] = userName;
parameters[nameof(serialNumber)] = serialNumber;
uriBuilder.Query = parameters.ToString();
// Pass null as HttpContent to make HttpClient send an empty body
var result = await _httpClient.PostAsync(uriBuilder.ToString(), null).ConfigureAwait(false);

WebClient - UploadValues : Get Status Response

I'am trying to pass values from a controller to another controller in another domain. I'am adding data to a NameValueCollection and pass it to another controller [httppost] method and receiving data there mapped to a Model same as i passed from.
Currently i'am running it locally by opening two instance of VS simultaneously. When the both VS is opened the values are passed correctly and the information is written to db correctly and i receive a response like "{byte[0]}". Now when i try stopping the destination controller Project and try to submit data then it wont work but still i get the same response as "{byte[0]}". Can somebody please help me how to return the response command in this scenario. Is there a way a understand the UploadValues are completed or not completed.
.........
.........
NameValueCollection resumeDetails = new NameValueCollection();
resumeDetails.Add("FirstName", "KRIZTE");
byte[] res = this.Post(ConfigurationManager.AppSettings["RedirectionUrl"].ToString(), resumeDetails);
return View("Index");
}
public byte[] Post(string uri, NameValueCollection resumeDetails)
{
byte[] response = null;
WebClient client = new WebClient();
response = client.UploadValues(uri, resumeDetails);
return response;
}
You should not use the WebClient because of problems like this.
Microsoft implemented HttpClient class as a newer API and it has these benefits:
HttpClient is the newer of the APIs and it has the benefits of
has a good async programming model
1- being worked on by Henrik F Nielson who is basically one of the inventors of HTTP, and he designed the API so it is easy for you to follow the HTTP standard, e.g. generating standards-compliant headers
2- is in the .Net framework 4.5, so it has some guaranteed level of support for the forseeable future
3- also has the xcopyable/portable-framework version of the library if you want to use it on other platforms - .Net 4.0, Windows Phone etc.
so I'm gonna show you an example of using HttpClient:
var uri = "http://google.com";
var client = new HttpClient();
try
{
var values = new List<KeyValuePair<string, string>>();
// add values to data for post
values.Add(new KeyValuePair<string, string>("FirstName", "KRITZTE"));
FormUrlEncodedContent content = new FormUrlEncodedContent(values);
// Post data
var result = await client.PostAsync(uri, content);
// Access content as stream which you can read into some string
Console.WriteLine(result.Content);
// Access the result status code
Console.WriteLine(result.StatusCode);
}
catch(AggregateException ex)
{
// get all possible exceptions which are thrown
foreach (var item in ex.Flatten().InnerExceptions)
{
Console.WriteLine(item.Message);
}
}

JSON return type from API call

I am making a c# asp.net website which uses memes. I am making an API call to imgflip.com using HttpClient.PostAsync(url, FormUrlEncodedContent) - this returns a JSON object which includes a link to the generated meme on their server. In the API documentation the successful result looks like this:
{
"success": true,
"data": {
"url": "http://i.imgflip.com/123abc.jpg",
"page_url": "https://imgflip.com/i/123abc"
}
}
I am getting a result which looks like this (note the forward and back slashes in the url):
{"success":true,"data":{"url":"http:\/\/i.imgflip.com\/ho1uk.jpg","page_url":"https:\/\/imgflip.com\/i\/ho1uk"}}
I need to parse out the backslashes and the url works fine - why am I getting them in the first place? Parsing them out is straightforward but the the fact they are there makes me think something must be wrong with my request. Here is the method I am using to get the response:
public async Task<string> GetReponseAsString(string templateID, string userName, string password, string topText, string bottomText) //non-optional parameters
{
string postURL = "https://api.imgflip.com/caption_image";
var formContent = new FormUrlEncodedContent(new[]{
new KeyValuePair<string, string>("template_id", templateID),
new KeyValuePair<string, string>("username", userName),
new KeyValuePair<string, string>("password", password),
new KeyValuePair<string, string>("text0", topText),
new KeyValuePair<string, string>("text1", bottomText)
});
HttpClient client = new HttpClient();
var response = await client.PostAsync(postURL, formContent);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return response.Content.ReadAsStringAsync().Result;
}
I am getting the right response (almost) and specifying the proper content type in the content header type - any ideas why my returned object has the backslashes?
The JSON specification defines the forward slash as a character that can optionally be escaped.
What you receive is a valid JSON document. The solution is simple. Use a JSON parser (see https://stackoverflow.com/a/9573161).
You should not care about the serialized representation of structured data (that's what JSON is - a serialization format for structured data). You could receive this:
{
"\u0073\u0075\u0063\u0063\u0065\u0073\u0073":true,
"\u0064\u0061\u0074\u0061": {
"\u0075\u0072\u006c":"\u0068\u0074\u0074\u0070:\/\/\u0069\u002e\u0069\u006d\u0067\u0066\u006c\u0069\u0070\u002e\u0063\u006f\u006d\/\u0068\u006f1\u0075\u006b\u002e\u006a\u0070\u0067",
"\u0070\u0061\u0067\u0065_\u0075\u0072\u006c":"\u0068\u0074\u0074\u0070\u0073:\/\/\u0069\u006d\u0067\u0066\u006c\u0069\u0070\u002e\u0063\u006f\u006d\/\u0069\/\u0068\u006f1\u0075\u006b"
}
}
from the server and it would still be the same thing as stated in the imgflip API documentation.
Just use a parser, it will do the right thing. Don't attempt to work with String.IndexOf() or regular expressions on JSON.

Post complex type formatted as form-url-encoded using ASP.Net HttpClient

I need to HTTP POST a complex type to a web service (which I don't controll). I believe the web service was built using an older version of ASP.NET MVC. It model binds payloads formatted as form-url-encoded.
If I fire the following at it, it works perfectly. As you can see, I've manually created a collection of key/value pairs.
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("Username", "some-username"),
new KeyValuePair<string, string>("Password", "some-password"),
new KeyValuePair<string, string>("Product", "some-product")
};
var content = new FormUrlEncodedContent(values);
var response = new HttpClient().PostAsync(url, content).Result;
But I don't want to have to do this, I just want to send complex types if I can.
var content = new ComplexType("some-username", "some-password", "some-product");
var response = new HttpClient().PostAsync(url, content).Result;
I believe there used to be a HttpRequestMessage<T> but that's been dropped in favour of
HttpClient.PostAsJsonAsync<T>(T value) sends “application/json”
HttpClient.PostAsXmlAsync<T>(T value) sends “application/xml”
But I don't want to send Json or XML I want to send form-url-ecncoded without the hassle of converting complex types to collections of key/value pairs.
Essentially I'd also like to know the answer to this question that Jaans poses (His is the second comment to the second answer).
Can anyone advise please.
Flurl [disclosure: I'm the author] provides a method that seems to be exactly what you're looking for:
using Flurl.Http;
var resp = await url.PostUrlEncodedAsync(new {
Username = "some-username",
Password = "some-password",
Product = "some-product",
});
Flurl is small and portable, and uses HttpClient under the hood. It is available via NuGet:
PM> Install-Package Flurl.Http
Since you've almost got a solution that does work, I'd say just go with it. Organize your code inside an extension method so that you can post using that, something like:
public static async Task<HttpResponseMessage> PostAsFormUrlEncodedAsync<T>(
this HttpClient httpClient, T value)
{
// Implementation
}
Your implementation just needs to serialize your object into form-encoded values, which you should be able to do easily with reflection.
Then you can call the code exactly as you would for JSON or XML.
You can do this:
var content = new ComplexType("some-username", "some-password", "some-product");
var response = new HttpClient().PostAsync<ComplexType>(url, content, new FormUrlEncodedMediaTypeFormatter()).Result;

Simple HTTP POST in Windows Phone 8

I have a string that I need to POST in Windows Phone 8. It looks like this:
https://www.scoreoid.com/api/getPlayers?api_key=[apiKey]&game_id=[gameID]&response=xml&username=[username]&password=[password]
This string simply returns another string (that is formatted as XML that I parse later in my code).
I have yet to find a simple solution to this like in Windows 8.
Edit: Found the solution to my problem with an assist from rciovati and the HttpClient library.
Here's my simple code:
var httpClient = new HttpClient();
return await httpClient.GetStringAsync(uri + "?" + post_data);
Using the new Http Client Library is quite easy:
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("api_key", "12345"),
new KeyValuePair<string, string>("game_id", "123456")
};
var httpClient = new HttpClient(new HttpClientHandler());
HttpResponseMessage response = await httpClient.PostAsync(url, new FormUrlEncodedContent(values));
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
You can find other informations about this library here.
Here's a pretty useful blog post from Andy Wigley about how to do Http networking on Windows Phone 8. The WinPhoneExtensions wrapper library he speaks of basically simulates the async/await model of network programming you can do in Win8.
http://blogs.msdn.com/b/andy_wigley/archive/2013/02/07/async-and-await-for-http-networking-on-windows-phone.aspx

Categories

Resources