Need to build URL encoded query from model object for HttpClient
My Model is
class SaveProfileRequest
{
public string gName { get; set; }
public string gEmail { get; set; }
public long gContact { get; set; }
public string gCompany { get; set; }
public string gDeviceID { get; set; }
public string Organization { get; set; }
public string profileImage { get; set; }
public string documentImagefront { get; set; }
public string documentImageback { get; set; }
}
SaveProfileRequest request = new SaveProfileRequest() { gName = name, gEmail = email, gContact = phonenumber, gCompany = company,
gDeviceID = deviceId, Organization = "", profileImage = "", documentImageback = "", documentImagefront = "" };
string response = await RequestProvider.PostAsync<string, SaveProfileRequest>(uri, request);
I have a working code for content type JSON
content = new StringContent(JsonConvert.SerializeObject(data));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
Where data is of type TInput
Tried
content = new StringContent(System.Net.WebUtility.UrlEncode(JsonConvert.SerializeObject(data)));
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
but didn't workout
JsonConvert
produces only json content. For urlencoded query you should construct instance of FormUrlEncodedContent
. As constructor parameter it takes collection of KeyValuePair<string, string>
. So the main trick is to build this collection for model object.
You could use reflection for this purpose. But there is a simpler solution based on Json.net. It was described here and following ToKeyValue()
extension method is a copy/paste from that blog post:
public static class ObjectExtensions
{
public static IDictionary<string, string> ToKeyValue(this object metaToken)
{
if (metaToken == null)
{
return null;
}
JToken token = metaToken as JToken;
if (token == null)
{
return ToKeyValue(JObject.FromObject(metaToken));
}
if (token.HasValues)
{
var contentData = new Dictionary<string, string>();
foreach (var child in token.Children().ToList())
{
var childContent = child.ToKeyValue();
if (childContent != null)
{
contentData = contentData.Concat(childContent)
.ToDictionary(k => k.Key, v => v.Value);
}
}
return contentData;
}
var jValue = token as JValue;
if (jValue?.Value == null)
{
return null;
}
var value = jValue?.Type == JTokenType.Date ?
jValue?.ToString("o", CultureInfo.InvariantCulture) :
jValue?.ToString(CultureInfo.InvariantCulture);
return new Dictionary<string, string> { { token.Path, value } };
}
}
Now you could build the url-encoded content as easy as:
var keyValues = data.ToKeyValue();
var content = new FormUrlEncodedContent(keyValues);
This can be done effortlessly with Flurl (disclaimer: I'm the author) as this exact scenario - parsing a .NET object's properties into URL-encoded key-value pairs - is supported right out the box:
using Flurl.Http;
var resp = await url.PostUrlEncodedAsync(data);
Flurl uses HttpClient
under the hood, so in the example above, resp
is an instance of HttpResponseMessage
, just as if the call was made using HttpClient
directly. You could also append .ReceiveString()
to the call if you just want the response body, or .ReceiveJson<T>()
if you're expecting a JSON response and want a matching .NET object of type T
.
You can use this simplified version
public static class URLExtensions
{
public static string ToKeyValueURL(this object obj)
{
var keyvalues = obj.GetType().GetProperties()
.ToList()
.Select(p => $"{p.Name} = {p.GetValue(obj)}")
.ToArray();
return string.Join('&',keyvalues);
}
}