由於辭職的原因,最近正在忙於找工作。在這段期間收到了一家公司的上機測試題,一共兩道題,其中一道題是關於REST API的應用。雖然在面試時,我已經說過,不懂REST,但那面試PM還是給了一道這題讓我做。面試的PM還是比較友好,沒有限定時間,結果自己不爭氣,一邊查資料一邊做,一個多小時過了還是沒做出來,所以最后我放棄了,當然面試也就失敗了。於是歸納了一下失敗的原因,主要還是對REST不了解,把REST當做Web Service的另一種形式,先入為主的理解錯誤,必然會導致了失敗。
回歸正傳,什么是REST? 在此不詳說。我說一下自己的理解吧。簡單地說,REST就是一種基本HTTP請求服務從而達到操作資源的技術,其支持多種數據格式,比如xml、Json、Csv等等。Web Service是基本XML並利用SOAP協議實現遠程資源訪問操作的技術。因此,兩者本質是是不同的。也許我的理解不完全正確,歡迎指出錯誤。
下面來看看這道題,如下:
Userstory:
As a user I want to be able to see maximum, minimum and average predicted temperature for the following 3 days,
based on the city that needs to be entered.
Acceptance criteria:
Windows form application written in C#
One input field to define the city
A combobox to select Fahrenheit or Celcius degrees
Use free web service provided by http://www.worldweatheronline.com
The following key can be used to retrieve data : c6bbde7c9c021451123107
Show 'Retrieving weather data...' in status bar when request of data is submitted. Once data is retrieved
update status accordingly.
Use of linq statements to calculate the minimum, maximum and average temperature.
Main form needs to be responsive at all times
Use of delegates
Retrieval of data and UI logic needs to be seperated in code
Error handling when connection
以下是我寫的代碼:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net; using System.IO; using System.Xml; using System.Xml.Linq; using System.Threading; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); Init(); } private void Init() { //初始化單位數據 List<object> list = new List<object>(); list.Add(new{key="Celsius", value="C"}); list.Add(new { key = "Fahrenheit", value = "F" }); cbUnit.DataSource = list; cbUnit.DisplayMember = "key"; cbUnit.ValueMember = "value"; cbUnit.SelectedIndex = 0; } private void btCalculate_Click(object sender, EventArgs e) { try { slStatus.Text = "Retrieving weather data....."; string city = tbCity.Text; string unit = cbUnit.SelectedValue.ToString(); Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("city", city); dic.Add("unit", unit); Thread thread = new Thread(new ParameterizedThreadStart(ThreadProcess)); thread.IsBackground = true; thread.Start(dic); } catch (Exception ex) { slStatus.Text = "獲取數據失敗...."; } } /// <summary> /// 后台處理線程 /// </summary> /// <param name="obj"></param> private void ThreadProcess(object obj) { Dictionary<string, string> dic = obj as Dictionary<string, string>; XDocument xmlDoc = GetData(dic["city"]); SetData(xmlDoc, dic["unit"]); slStatus.Text = ""; } /// <summary> /// 獲取數據 /// </summary> /// <param name="city"></param> /// <returns></returns> private XDocument GetData(string city) { XDocument doc; Uri uri = new Uri(string.Format(@"http://free.worldweatheronline.com/feed/weather.ashx?q={0},china&format=xml&num_of_days=3&key=c6bbde7c9c021451123107",city)); HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest; using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) { StreamReader reader = new StreamReader(response.GetResponseStream()); string result=reader.ReadToEnd(); StringReader str = new StringReader(result); doc=XDocument.Load(str); } return doc; } /// <summary> /// 設置數據 /// </summary> /// <param name="doc"></param> /// <param name="unit"></param> private void SetData(XDocument doc,string unit) { var query = from p in doc.Root.Elements("weather") select new { Date = p.Element("date") == null ? null : p.Element("date").Value, MaxC = p.Element("tempMaxC") == null ? null : p.Element("tempMaxC").Value, MinC = p.Element("tempMinC") == null ? null : p.Element("tempMinC").Value, MaxF = p.Element("tempMaxF") == null ? null : p.Element("tempMaxF").Value, MinF = p.Element("tempMinF") == null ? null : p.Element("tempMinF").Value }; if (unit == "C") { CrossThreadAccess(tbMaximum, query.Max(p => p.MaxC)); CrossThreadAccess(tbMinimum, query.Min(p => p.MinC)); } else { CrossThreadAccess(tbMaximum, query.Max(p => p.MaxF)); CrossThreadAccess(tbMinimum, query.Min(p => p.MinF)); } CrossThreadAccess(tbAverage, Convert.ToString((Convert.ToInt32(tbMaximum.Text) + Convert.ToInt32(tbMinimum.Text)) / 2)); } /// <summary> /// UI線程間訪問 /// </summary> /// <param name="control"></param> /// <param name="value"></param> private void CrossThreadAccess(Control control,string value) { if (control.InvokeRequired) { control.Invoke(new Action<Control, string>(CrossThreadAccess), control, value); } else { TextBox tb = control as TextBox; if (tb != null) tb.Text = value; } } } }
效果如下: