本篇同步發文在個人Blog: 一袋.NET要扛幾樓?打造容器化的ASP.NET Core網站!系列文章 - (8) 建立商品列表的頁面 - 1
前幾篇文章已完成商品列表的Web Api,這篇開始建立網頁介面,串接商品的Web Api並呈現商品列表。
開啟VS,在RPGShop方案的src新增Presentation的方案資料夾,並在Presentation資料夾加入新的ASP.NET Core專案,專案名稱為WebMvc,選擇專案類型Web應用程式(模型-檢視-控制器),先不要用任何HTTPS、Docker與驗證,如圖1。
圖1
按下建立,會產生預設的HomeController和Model、View,如圖2。
圖2
在WebMvc專案新增資料夾Infrastructure,會將一些HttpClient的抽象與實作,以及定義與商品服務Api的Url Pattern,建立在這個資料夾內。
定義常用的Http Get/Post/Put/Delete的非同步函式:
using System.Net.Http;
using System.Threading.Tasks;
namespace WebMvc.Infrastructure
{
public interface IHttpClient
{
Task<string> GetStringAsync(string uri);
Task<HttpResponseMessage> PostAsync<T>(string uri, T item);
Task<HttpResponseMessage> DeleteAsync(string uri);
Task<HttpResponseMessage> PutAsync<T>(string uri, T item);
}
}
建立一個CustomHttpClient類別並實作IHttpClient,會從Constructor注入System.Net.Http的HttpClient和logger。
其中Post和Put的方法有大部分共通的寫法,於是可以寫成共同的函式DoPostPutAsync,而要放在Body的資料,使用Newtonsoft.Json序列化成Json。
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace WebMvc.Infrastructure
{
public class CustomHttpClient : IHttpClient
{
private HttpClient _client;
private ILogger<CustomHttpClient> _logger;
public CustomHttpClient(HttpClient client, ILogger<CustomHttpClient> logger)
{
_client = client;
_logger = logger;
}
public async Task<HttpResponseMessage> DeleteAsync(string uri)
{
var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri);
return await _client.SendAsync(requestMessage);
}
public async Task<string> GetStringAsync(string uri)
{
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
var response = await _client.SendAsync(requestMessage);
return await response.Content.ReadAsStringAsync();
}
public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item)
{
return await DoPostPutAsync(HttpMethod.Post, uri, item);
}
public async Task<HttpResponseMessage> PutAsync<T>(string uri, T item)
{
return await DoPostPutAsync(HttpMethod.Put, uri, item);
}
private async Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string uri, T item)
{
if (method != HttpMethod.Post && method != HttpMethod.Put)
{
throw new ArgumentException("Value must be either post or put.", nameof(method));
}
var requestMessage = new HttpRequestMessage(method, uri)
{
Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json")
};
var response = await _client.SendAsync(requestMessage);
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
throw new HttpRequestException();
}
return response;
}
}
}
所有跟Api互動的Url Pattern,都在此類別規範,而我們這商品列表的頁面需要
namespace WebMvc.Infrastructure
{
public static class ApiPaths
{
public static class Catalog
{
public static string GetAllCatalogItems(string baseUri, int pageIndex, int pageSize, int? type)
{
string typeQueryString = "";
if (type.HasValue)
{
typeQueryString = type.Value.ToString();
}
return $"{baseUri}items?catalogTypeId={typeQueryString}&pageIndex={pageIndex}&pageSize={pageSize}";
}
public static string GetAllTypes(string baseUri)
{
return $"{baseUri}catalogTypes";
}
}
}
}
下一篇將寫從Api互動的Service與網頁呈現的內容