五一假期快速上手 MVC 寫的小 Demo:呼叫淘寶開放平台 API 搜尋商品,前端價格區間篩選。展示 Model Binding、HttpClient 呼叫、JSON 反序列化、View 渲染完整流程。
@using (Html.BeginForm("Search", "Home", FormMethod.Get)) {
<fieldset>
<legend>搜尋商品</legend>
<p>關鍵字:@Html.TextBox("keyword")</p>
<p>價格上限:@Html.TextBox("max")</p>
<p>價格下限:@Html.TextBox("min")</p>
</fieldset>
<input type="submit" value="搜尋" />
}
// 產生 GET /Home/Search?keyword=手機&max=5000&min=1000

public class HomeController : Controller {
private readonly HttpClient _client = new HttpClient { BaseAddress = new Uri("https://eco.taobao.com/router/rest") };
private const string AppKey = "your_app_key";
private const string AppSecret = "your_app_secret";
public async Task<ActionResult> Search(string keyword, decimal? max, decimal? min) {
if (string.IsNullOrWhiteSpace(keyword)) return View("Index");
// 1. 構建淘寶 API 參數
var parameters = new Dictionary<string, string> {
["method"] = "taobao.items.search",
["app_key"] = AppKey,
["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
["format"] = "json",
["v"] = "2.0",
["sign_method"] = "md5",
["q"] = keyword,
["start_price"] = min?.ToString(),
["end_price"] = max?.ToString(),
["fields"] = "num_iid,title,price,pic_url,detail_url"
};
parameters["sign"] = GenerateSign(parameters, AppSecret); // 簽名算法
// 2. 發送請求
var content = new FormUrlEncodedContent(parameters);
var response = await _client.PostAsync("", content);
var json = await response.Content.ReadAsStringAsync();
// 3. 反序列化 (簡化:動態解析)
dynamic result = JsonConvert.DeserializeObject(json);
var items = new List<dynamic>();
if (result?.item_search_response?.items?.item != null) {
foreach (var item in result.item_search_response.items.item)
items.Add(item);
}
ViewBag.Keyword = keyword;
ViewBag.Max = max;
ViewBag.Min = min;
return View("Results", items);
}
private string GenerateSign(IDictionary<string, string> dict, string secret) {
var sorted = dict.OrderBy(k => k.Key).Select(k => k.Key + k.Value);
var raw = secret + string.Join("", sorted) + secret;
using (var md5 = MD5.Create())
return BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(raw))).Replace("-", "").ToLower();
}
}
@model List<dynamic>
<h2>搜尋「@ViewBag.Keyword」結果 (價格 @ViewBag.Min - @ViewBag.Max)</h2>
<div class="row">
@foreach (var item in Model) {
<div class="col-md-3">
<div class="card">
<img src="@item.pic_url" class="card-img-top" alt="@item.title" />
<div class="card-body">
<h6 class="card-title">@item.title</h6>
<p class="card-text">¥@item.price</p>
<a href="@item.detail_url" target="_blank" class="btn btn-primary">查看詳情</a>
</div>
</div>
</div>
}
</div>
| 知識點 | 本例體現 |
|---|---|
| Model Binding | Action 參數自動繫結 QueryString:keyword, max, min |
| HttpClient 非同步 | async/await 避免阻塞執行緒,單例模式複用連線 |
| 第三方 API 整合 | 參數排序、簽名、時間戳、錯誤處理 (嘗試/捕獲) |
| 動態 JSON 解析 | JsonConvert.DeserializeObject<dynamic> 快速原型,無需強型別 DTO |
| ViewModel 傳遞 | ViewBag 傳遞搜尋條件,Model 傳遞結果集 |
| 前端驗證 | 可加入 jquery.validate.unobtrusive 客戶端價格數字驗證 |
dynamic,獲得編譯期檢查與 IntelliSense。Polly 重試/熔斷/快取策略,應對 API 限流與不穩定。HttpMessageHandler 驗證請求構建與解析邏輯。