2015-11-08 54 views
0

我來自iOS(Swift)背景。在我的一個Swift應用程序中,我有這個調用API的類。我試圖將它移植到C#(Windows Form應用程序),但我遇到了一些障礙。首先是Swift代碼。沒有什麼花哨。一種方法是POST請求登錄到API,另一個函數執行GET方法來檢索用戶配置文件的JSON響應。這兩種方法都是異步的。異步調用API並解析JSON

import Foundation 

class API { 

    private let session = NSURLSession.sharedSession() 
    private let baseURL = "https://www.example.com/api/" 

    func login(userID userID: String, password: String, completion: (error: NSError?) ->()) { 
     let url = NSURL(string: baseURL + "login")! 
     let params = ["username": userID, "password": password] 
     let request = NSMutableURLRequest(URL: url) 
     request.HTTPMethod = "POST" 
     request.encodeParameters(params) // encodeParameters is an extension method 
     session.dataTaskWithRequest(request, completionHandler: { data, response, error in 
      if let httpResponse = response as? NSHTTPURLResponse { 
       if httpResponse.statusCode != 200 { 
        completion(error: error) 
       } else { 
        completion(error: nil) 
       } 
      } 
     }).resume() 
    } 

    func fetchUser(completion: (user: User?, error: NSError?) ->()) { 
     let url = NSURL(string: baseURL + "profile")! 
     let request = NSURLRequest(URL: url) 
     session.dataTaskWithRequest(request, completionHandler: { data, response, error in 
      if let error = error { 
       completion(user: nil, error: error) 
      } else { 
       // Parsing JSON 
       var jsonDict = [String: AnyObject]() 
       do { 
        jsonDict = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: AnyObject] 
       } catch { 
        print("Error occurred parsing data: \(error)") 
        completion(user: nil, error: error) 
       } 

       let user = User() 
       user.name = jsonDict["name"] as! String 
       user.age = jsonDict["age"] as! Int 

       completion(user: user, error: nil) 
      } 
     }).resume() 
    } 
} 

這是我的嘗試將其轉換爲C#。

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Drawing; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Net.Http; 
using System.Runtime.Serialization.Json; 
using System.Text; 
using System.Xml.Linq; 
using System.Xml.XPath; 

namespace MyTrayApp 
{ 
    public partial class Form1 : Form 
    { 
     private string baseURL = "https://www.example.com/api/"; 


     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private async void Form1_Load(object sender, EventArgs e) 
     { 
      await login("myusername", "mypassword"); 
      await fetchUser(); 
     } 

     async Task login(string userID, string password) 
     { 
      using (var client = new HttpClient()) 
      { 
       client.BaseAddress = new Uri(baseURL); 
       var parameters = new Dictionary<string, string> 
       { 
        { "username", userID }, 
        { "password", password } 
       }; 

       var encodedParameters = new FormUrlEncodedContent(parameters); 
       var response = await client.PostAsync("login", encodedParameters); 
       string responseString = await response.Content.ReadAsStringAsync(); 
       //Console.WriteLine(responseString); 
      } 
     } 

     async Task fetchUser() 
     { 
      using (var client = new HttpClient()) 
      { 
       client.BaseAddress = new Uri(baseURL); 
       var response = await client.GetAsync("profile"); 
       response.EnsureSuccessStatusCode(); 

       var responseString = await response.Content.ReadAsStringAsync(); 

       var jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(responseString.ToCharArray()), new System.Xml.XmlDictionaryReaderQuotas()); 
       var root = XElement.Load(jsonReader); 
       Console.WriteLine(root.XPathSelectElement("//name").Value); 

       //Console.WriteLine(responseString); 
      } 
     } 
    } 
} 

這些都是我遇到的問題。

  1. 在我的Swift方法中,它們有完成處理程序。我怎樣才能在C#中做同樣的事情?
  2. 在Swift中,您會得到一個NSData對象,您可以將它傳遞給NSJSONSerialization以創建JSON對象。在我目前的實現中,我在XElement.Load(jsonReader);處得到一個XML異常。我不確定這是否是正確的做法。我在這裏發現了大量不同的解決方案。但有些是針對Metro應用程序的,有些針對網絡,這一切都非常令人難以置信。此外,大多數解決方案都使用第三方庫,如JSON.NET。我試圖在沒有第三方庫的情況下實現這一點。
+0

爲了說明Todd說的話,大多數人只是使用JSON.NET作爲事實上的.net解析器。但是,如果第三方依賴關係實際上是阻止者,那麼有些人只是從SimpleJSON內聯源代碼http://simplejson.codeplex.com/SourceControl/latest –

+0

另外,建議重用HttpClient的實例,所以只需聲明它作爲一個領域,並在你完成之後進行處理。這將提供更好的性能,因爲它可以讓您重用HTTP連接。 –

回答

1

在我的Swift方法中,它們有完成處理程序。我如何在C#中執行相同的 ?

接線完成處理程序的目的是讓您在等待HTTP呼叫完成時不佔用線程。 async/await的美妙之處在於,您不必在C#中執行此操作。 await關鍵字指示編譯器將字面上的方法的其餘部分重寫爲回調。遇到await會立即釋放當前線程,從而防止UI凍結。您已經正確編寫了異步代碼;即使看起來同步,它也會異步行爲。

你的第二個問題是有些寬泛,但我會做2點建議:

  1. 與JSON數據處理時,不要使用XElement。微軟的XML parsing library(其中之一)的一部分,與JSON無關。

  2. 我不知道爲什麼沒有第三方庫實現這一點很重要。我知道人們有他們的理由,但特別是Json.NET已經變得非常流行和無處不在,以至於微軟自己已經將它融入他們的ASP.NET MVC和Web API框架中。也就是說,如果你必須避免它,here是你如何使用微軟庫來反序列化JSON。