2011-01-20 18 views
6

Estoy usando el extremadamente impresionante HttpClient proporcionado en WCF REST Starter Kit. Tengo el siguiente método que está trabajando en contra de la API HelloTxt:Solicitud POST genérica utilizando Microsoft.HttpClient y HttpContentExtensions

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>(); 
} 

que tienen un buen método GetRequest genérico que se parece a esto:

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; 
} 

El beneficio de las cuales es que se puede pasar de T como el tipo de respuesta de acuerdo con este ejemplo al azar:

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); 
} 

ahora quiero el mismo método POST estilo genérico, en lugar de GET y estoy seguro de que puedo utilizar los HttpContentExtensions, pero no puedo f igure cómo transformar la solicitud en HttpMultipartMimeForm. esto es lo que tengo hasta ahora:

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; 
} 

sería llamado como esto:

UserValidateResponse response = PostRequest<UserValidateRequest, UserValidateResponse>("user.validate", new UserValidateRequest(this.AppKey, this.UserKey)); 

Es a trabajar en contra de esta API: http://hellotxt.com/developers/documentation. ¡Cualquier sugerencia es extremadamente bienvenida! Podría definir una forma diferente para cada POST, pero sería bueno hacerlo genéricamente.

+0

tengo la sensación de la única manera de hacerlo es utilizar la reflexión y construir un HttpMultipartMimeForm basado en las propiedades simples de una clase, o serializar el objeto y luego los primeros hijos debajo del nodo raíz de XML. – Junto

Respuesta

2

Respondí mi propia pregunta sobre esto. El código se puede ver en mi .NET wrapper for the HelloTxt API - HelloTxt.NET, y según mi comentario anterior, utiliza la reflexión para calcular las propiedades del objeto de solicitud y rellena un HttpMultipartMimeForm() con los valores, mientras se verifican las anotaciones de datos Required en las propiedades de la clase.

El código en cuestión es:

/// <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; 
} 
Cuestiones relacionadas