Generic POST request using Microsoft.HttpClient and HttpContentExtensions
I answered my own question on this. The code can be seen in my .NET wrapper for the HelloTxt API - HelloTxt.NET, and as per my comment above, uses reflection to work out the request object properties, and populates a HttpMultipartMimeForm()
with the values, whilst checking the Required
data annotions on the class properties.
The code in question is:
/// <summary>
/// Generic post request.
/// </summary>
/// <typeparam name="K">Request Type</typeparam>
/// <typeparam name="T">Response Type</typeparam>
/// <param name="query">e.g. user.validate</param>
/// <param name="request">The Request</param>
/// <returns></returns>
public T PostRequest<K, T>(string query, K request)
{
using (var client = GetDefaultClient())
{
// build form data post
HttpMultipartMimeForm form = CreateMimeForm<K>(request);
// call method
using (HttpResponseMessage response = client.Post(query, form.CreateHttpContent()))
{
response.EnsureStatusIsSuccessful();
return response.Content.ReadAsXmlSerializable<T>();
}
}
}
/// <summary>
/// Builds a HttpMultipartMimeForm from a request object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <returns></returns>
public HttpMultipartMimeForm CreateMimeForm<T>(T request)
{
HttpMultipartMimeForm form = new HttpMultipartMimeForm();
Type type = request.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
foreach (Attribute attribute in property.GetCustomAttributes(true))
{
RequiredAttribute requiredAttribute = attribute as RequiredAttribute;
if (requiredAttribute != null)
{
if (!requiredAttribute.IsValid(property.GetValue(request, null)))
{
//Console.WriteLine("{0} [type = {1}] [value = {2}]", property.Name, property.PropertyType, property.GetValue(property, null));
throw new ValidationException(String.Format("{0} [type = {1}] requires a valid value", property.Name, property.PropertyType));
}
}
}
if (property.PropertyType == typeof(FileInfo))
{
FileInfo fi = (FileInfo)property.GetValue(request, null);
HttpFormFile file = new HttpFormFile();
file.Content = HttpContent.Create(fi, "application/octet-stream");
file.FileName = fi.Name;
file.Name = "image";
form.Files.Add(file);
}
else
{
form.Add(property.Name, String.Format("{0}", property.GetValue(request, null)));
}
}
return form;
}
Related videos on Youtube
Rebecca
Freelance .NET developer. I love well designed and elegant solutions. I'm also a code neat freak. I'm an opinionated REST evangelist.
Updated on June 04, 2022Comments
-
Rebecca almost 2 years
I am using the extremely awesome HttpClient provided in the WCF REST Starter Kit. I have the following method that is working against the HelloTxt API:
public UserValidateResponse Validate() { HttpClient client = new HttpClient(baseUrl); HttpMultipartMimeForm form = new HttpMultipartMimeForm(); form.Add("app_key", this.AppKey); form.Add("user_key", this.UserKey); HttpResponseMessage response = client.Post("user.validate", form.CreateHttpContent()); return response.Content.ReadAsXmlSerializable<UserValidateResponse>(); }
I have a nice generic GetRequest method that looks like this:
public T GetRequest<T>(string query) { HttpClient client = new HttpClient(baseUrl); client.DefaultHeaders.UserAgent.AddString(@"http://www.simply-watches.co.uk/"); HttpResponseMessage response = client.Get(query); response.EnsureStatusIsSuccessful(); T data = default(T); try { data = response.Content.ReadAsXmlSerializable<T>(); return data; } catch (Exception ex) { Console.Write(String.Format("{0}: {1}", ex.Message, ex.InnerException.Message)); } return data; }
The benefit of which is that you can pass it T as the response type as per this random example:
public List<User> GetUsers(int deptid) { string query = String.Format("department.getUsers?api_key={0}&dept_id={1}", this.APIKey, deptId); return GetRequest<List<User>>(query); }
I now want to the same generic style POST method, rather than GET and I'm sure I can use the HttpContentExtensions, but I can't figure out how to transform the request into a HttpMultipartMimeForm. this is what I have so far:
public T PostRequest<K, T>(string query, K request) { HttpClient client = new HttpClient(baseUrl); // the following line doesn't work! Any suggestions? HttpContent content = HttpContentExtensions.CreateDataContract<K>(request, Encoding.UTF8, "application/x-www-form-urlencoded", typeof(HttpMultipartMimeForm)); HttpResponseMessage response = client.Post(query, content); response.EnsureStatusIsSuccessful(); T data = default(T); try { data = response.Content.ReadAsXmlSerializable<T>(); return data; } catch (Exception ex) { Console.Write(String.Format("{0}: {1}", ex.Message, ex.InnerException.Message)); } return data; }
It would be called like this:
UserValidateResponse response = PostRequest<UserValidateRequest, UserValidateResponse>("user.validate", new UserValidateRequest(this.AppKey, this.UserKey));
It is to work against this API: http://hellotxt.com/developers/documentation. Any suggestions are extremely welcome! I could define a different form for each POST, but it would be nice to do this generically.
-
Sнаđошƒаӽ about 5 yearsThe github link you provided is broken.