2011-01-20 8 views
6

Tôi đang sử dụng HttpClient cực kỳ tuyệt vời được cung cấp trong Bộ khởi động REST WCF. Tôi có phương pháp sau đó là làm việc với các API hellotxt:Yêu cầu POST chung sử dụng Microsoft.HttpClient và 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>(); 
} 

Tôi có một phương pháp getRequest generic đẹp trông như thế này:

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

Lợi ích của việc đó là bạn có thể vượt qua nó T như các loại phản ứng theo ví dụ ngẫu nhiên này:

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

bây giờ tôi muốn cùng một phương pháp kiểu POST chung chung, chứ không phải là GET và tôi chắc chắn rằng tôi có thể sử dụng HttpContentExtensions, nhưng tôi không thể f igure ra làm thế nào để chuyển đổi các yêu cầu vào một HttpMultipartMimeForm. đây là những gì tôi có cho đến nay:

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

Nó sẽ được gọi là như thế này:

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

Đó là làm việc với API này: http://hellotxt.com/developers/documentation. Mọi đề xuất đều cực kỳ được hoan nghênh! Tôi có thể xác định một hình thức khác nhau cho mỗi POST, nhưng nó sẽ là tốt đẹp để làm điều này một cách tổng quát.

+0

Tôi có một cảm giác là cách duy nhất để làm điều này là sử dụng phản xạ và xây dựng một HttpMultipartMimeForm dựa trên các tính chất đơn giản của một lớp, hoặc sắp đặt từng đối tượng và sau đó nhận được những đứa trẻ đầu tiên dưới nút XML gốc. – Junto

Trả lời

2

Tôi đã trả lời câu hỏi của riêng mình về vấn đề này. Các mã có thể được nhìn thấy trong .NET wrapper for the HelloTxt API - HelloTxt.NET của tôi, và theo bình luận của tôi ở trên, sử dụng phản ánh để làm việc ra các thuộc tính yêu cầu đối tượng, và điền một HttpMultipartMimeForm() với các giá trị, trong khi kiểm tra các chú thích dữ liệu Required trên các thuộc tính lớp.

Các mã trong câu hỏi là:

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