取得後端 Web API 的 JWT Token ,並且呼叫相關 API 的做法
在這篇文章中,將會使用登入驗證完成之後取得的權杖,呼叫 https://lobworkshop.azurewebsites.net/api/Invoices 這個發票 API,說明如何進行發票的 CRUD ,也就是 Create 新增、Retrive 查詢、Update 更新、Delete 刪除的作業。
在這篇文章所提到的範例程式碼,可以從這裡 GitHub 取得
為了要能夠完成這樣的練習,首先需要建立發票 API 會用到的 DTO 類別,這些類別如下所示:
#region DTO 型別宣告
public class LoginRequestDTO
{
public string Account { get; set; }
public string Password { get; set; }
}
public class LoginResponseDTO
{
public int Id { get; set; }
public string Account { get; set; }
public string Name { get; set; }
public string Token { get; set; }
public int TokenExpireMinutes { get; set; }
public string RefreshToken { get; set; }
public int RefreshTokenExpireDays { get; set; }
public string Image { get; set; }
}
public class InvoiceRequestDTO
{
public int Id { get; set; }
public string InvoiceNo { get; set; }
public UserDTO user { get; set; }
public DateTime Date { get; set; }
public string Memo { get; set; }
}
public class InvoiceResponseDTO
{
public int Id { get; set; }
public string InvoiceNo { get; set; }
public UserDTO user { get; set; }
public DateTime Date { get; set; }
public string Memo { get; set; }
}
public class UserDTO
{
public int Id { get; set; }
}
/// <summary>
/// 呼叫 API 回傳的制式格式
/// </summary>
public class APIResult
{
/// <summary>
/// 此次呼叫 API 是否成功
/// </summary>
public bool Status { get; set; } = false;
/// <summary>
/// 呼叫 API 失敗的錯誤訊息
/// </summary>
public string Message { get; set; } = "";
/// <summary>
/// 呼叫此API所得到的其他內容
/// </summary>
public object Payload { get; set; }
}
#endregion
首先,來看看如何呼叫新增發票 API,在這裡要先建立要新增發票的物件 InvoiceRequestDTO invoiceRequestDTO ,接著,使用
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginResponseDTO.Token);
敘述,把登入驗證成功後取得的 JWT Token,放入此次新增發票的請求的 HTTP 標頭 Header 內,如此,對於後端 Web Server 收到這個新增發票請求的時候,將會先檢查 JWT 權杖是否存,若存在,將會檢查該權杖是否正確、還在有效期限等等狀況,若沒有問題發生,將會觸發新增發票的 程式碼。
在這裡,將會使用
await client.PostAsync(url, new StringContent(httpJsonPayload, System.Text.Encoding.UTF8, "application/json"));
表示式,呼叫遠端的新增發票 API,第二個參數將會是此次要新增發票的內容。private static async Task<InvoiceResponseDTO> CreateInvoiceAsync(LoginResponseDTO loginResponseDTO)
{
InvoiceResponseDTO invoiceResponseDTO = new InvoiceResponseDTO();
string url = "https://lobworkshop.azurewebsites.net/api/Invoices";
InvoiceRequestDTO invoiceRequestDTO = new InvoiceRequestDTO()
{
InvoiceNo = "123",
Memo = "查理王",
Date = new DateTime(2019, 05, 20),
user = new UserDTO()
{
Id = loginResponseDTO.Id
}
};
var httpJsonPayload = JsonConvert.SerializeObject(invoiceRequestDTO);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginResponseDTO.Token);
HttpResponseMessage response = await client.PostAsync(url,
new StringContent(httpJsonPayload, System.Text.Encoding.UTF8, "application/json"));
if (response.IsSuccessStatusCode)
{
String strResult = await response.Content.ReadAsStringAsync();
APIResult apiResult = JsonConvert.DeserializeObject<APIResult>(strResult, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
if (apiResult.Status == true)
{
string itemJsonContent = apiResult.Payload.ToString();
Console.WriteLine($"成功新增一筆發票 : {itemJsonContent}");
invoiceResponseDTO = JsonConvert.DeserializeObject<InvoiceResponseDTO>(itemJsonContent, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
}
}
return invoiceResponseDTO;
}
對於想要修改遠端 Web API 資料庫內的發票紀錄,當然需要先取得該發票紀錄內容,在此,將會透過剛剛呼叫玩新增發票 API 後所得到的該發票紀錄,緊接著來呼叫修改 API。
在底下的呼叫修改發票方法中,第二個參數將會這次要修改發票的物件,而根據 REST 規範,當我們要進行修改某個紀錄的時候,需要提供一個 URI,該 URI 可以指向到該筆發票紀錄,因此,當要進行修改發票的時候,所要使用的 URL ,將會設定為
string url = $"https://lobworkshop.azurewebsites.net/api/Invoices/{UpdateItem.Id}";
,也就是要把該發票紀錄的 ID 放到 URL 路徑。
接下來將會進行任意修改該發票紀錄,當然也需要將 JWT Token,使用這個敘述
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginResponseDTO.Token);
,設定到此次 HTTP REST API 呼叫過程中,如此,就可以接著使用 await client.PutAsync(url, new StringContent(httpJsonPayload, System.Text.Encoding.UTF8, "application/json"));
敘述,呼叫遠端的發票更新 API。private static async Task<InvoiceResponseDTO> UpdateInvoiceAsync(LoginResponseDTO loginResponseDTO, InvoiceResponseDTO UpdateItem)
{
InvoiceResponseDTO invoiceResponseDTO = new InvoiceResponseDTO();
string url = $"https://lobworkshop.azurewebsites.net/api/Invoices/{UpdateItem.Id}";
InvoiceRequestDTO invoiceRequestDTO = new InvoiceRequestDTO()
{
Id = UpdateItem.Id,
InvoiceNo = UpdateItem.InvoiceNo,
Memo = "修正" +UpdateItem.Memo,
Date = UpdateItem.Date.AddDays(5),
user = UpdateItem.user
};
var httpJsonPayload = JsonConvert.SerializeObject(invoiceRequestDTO);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginResponseDTO.Token);
HttpResponseMessage response = await client.PutAsync(url,
new StringContent(httpJsonPayload, System.Text.Encoding.UTF8, "application/json"));
String strResult = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
APIResult apiResult = JsonConvert.DeserializeObject<APIResult>(strResult, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
if (apiResult.Status == true)
{
string itemJsonContent = apiResult.Payload.ToString();
Console.WriteLine($"成功修改一筆發票 : {itemJsonContent}");
invoiceResponseDTO = JsonConvert.DeserializeObject<InvoiceResponseDTO>(itemJsonContent, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
}
}
return invoiceResponseDTO;
}
當想要查詢遠端 Web API 上的發票紀錄,可以使用 HTTP Get 方法,當然,也是要將 JWT Token 放到 HTTP 標頭 Header 上;在這個發票查詢的 API,將會回傳 List ,也就是 InvoiceResponseDTO 的集合物件。
private static async Task<List<InvoiceResponseDTO>> QueryInvoiceAsync(LoginResponseDTO loginResponseDTO)
{
List<InvoiceResponseDTO> invoiceResponseDTOs = new List<InvoiceResponseDTO>();
string url = "https://lobworkshop.azurewebsites.net/api/Invoices";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginResponseDTO.Token);
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
String strResult = await response.Content.ReadAsStringAsync();
APIResult apiResult = JsonConvert.DeserializeObject<APIResult>(strResult, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
String strResult = await response.Content.ReadAsStringAsync();
if (apiResult.Status == true)
{
Console.WriteLine($"成功查詢發票 : {itemJsonContent}");
invoiceResponseDTOs = JsonConvert.DeserializeObject<List<InvoiceResponseDTO>>(itemJsonContent, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
}
}
return invoiceResponseDTOs;
}
當要刪除某個發票紀錄的時候,根據 REST 規範,一樣需要使用 URI 標示出該發票紀錄所在的地方,在這裡將會使用這樣的敘述
string url = $"https://lobworkshop.azurewebsites.net/api/Invoices/{Id}";
,當然,同樣也需要把 JWT Token 放到此次的 HTTP 呼叫標頭上。
最後,使用
await client.DeleteAsync(url);
敘述,呼叫遠端刪除的 API。private static async Task<InvoiceResponseDTO> DeleteInvoiceAsync(LoginResponseDTO loginResponseDTO, int Id)
{
InvoiceResponseDTO invoiceResponseDTO = new InvoiceResponseDTO();
string url = $"https://lobworkshop.azurewebsites.net/api/Invoices/{Id}";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginResponseDTO.Token);
HttpResponseMessage response = await client.DeleteAsync(url);
String strResult = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
APIResult apiResult = JsonConvert.DeserializeObject<APIResult>(strResult, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
if (apiResult.Status == true)
{
string itemJsonContent = apiResult.Payload.ToString();
Console.WriteLine($"成功刪除一筆發票 : {itemJsonContent}");
invoiceResponseDTO = JsonConvert.DeserializeObject<InvoiceResponseDTO>(itemJsonContent, new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore });
}
}
return invoiceResponseDTO;
}
現在,可以在 Main 方法內,使用底下的方法來進行發票的 CRUD 呼叫
static async Task Main(string[] args)
{
// 登入系統,取得 JTW Token
await LoginAsync();
// 從檔案中取得 JWT 權杖 Token
string fileContent = await StorageUtility.ReadFromDataFileAsync("", "MyDataFolder", "MyFilename.txt");
LoginResponseDTO loginResponseDTO = JsonConvert.DeserializeObject<LoginResponseDTO>(fileContent);
#region CRUD => Retrive 取得該使用者的發票資料
List<InvoiceResponseDTO> invoiceResponseDTOs = await QueryInvoiceAsync(loginResponseDTO);
PrintAllInvoice(invoiceResponseDTOs);
#endregion
#region CRUD => Create 新增發票資料
InvoiceResponseDTO invoiceResponseDTO = await CreateInvoiceAsync(loginResponseDTO);
#endregion
#region CRUD => Retrive 取得該使用者的發票資料
invoiceResponseDTOs = await QueryInvoiceAsync(loginResponseDTO);
PrintAllInvoice(invoiceResponseDTOs);
#endregion
#region CRUD => Update 修改發票資料
invoiceResponseDTO = await UpdateInvoiceAsync(loginResponseDTO, invoiceResponseDTO);
#endregion
#region CRUD => Retrive 取得該使用者的發票資料
invoiceResponseDTOs = await QueryInvoiceAsync(loginResponseDTO);
PrintAllInvoice(invoiceResponseDTOs);
#endregion
#region CRUD => Delete 刪除發票資料
foreach (var item in invoiceResponseDTOs)
{
await DeleteInvoiceAsync(loginResponseDTO, item.Id);
}
#endregion
#region CRUD => Retrive 取得該使用者的發票資料
invoiceResponseDTOs = await QueryInvoiceAsync(loginResponseDTO);
PrintAllInvoice(invoiceResponseDTOs);
#endregion
Console.WriteLine("Press any key for continuing...");
Console.ReadKey();
}
由於後端 Web API 所發出的 JWT Token 僅僅會有 15 分鐘的有效期限,因此,當您成功執行過該專案後,等候 15 分鐘之後,可以把 Main 方法內的
await LoginAsync();
註解起來,再度執行看看,不過,先在 QueryInvoiceAsync 方法內的 if (apiResult.Status == true)
敘述上設定一個中斷點,當執行到這個中斷點,先查詢看看 apiResult.Status 屬性值,應該是 false,而在該敘述的上一行,那就是 String strResult = await response.Content.ReadAsStringAsync();
這個敘述,請檢查看看 strResult 變數值,將會看到底下的內容,後端 Web API 將會因為這次呼叫查詢發票 API,因為所提供的 JWT 權杖 Token 已經逾期,因此,將會得到 401 的錯誤訊息。{"Status":false,"HTTPStatus":401,"ErrorCode":1,"Message":"錯誤代碼 1, 存取權杖可用期限已經逾期超過","Payload":null}
使用 C# HttpClient 追蹤與顯示 HTTP Request / Response 封包內容 文章中,有說明如何呼叫遠端 Web API,進行使用者帳號身分驗證的工作,一旦身分驗證成功之後,將會得到遠端 API 伺服器產生的 JWT 權杖 Token,不過,該權杖有效期限僅有 15 分鐘有效時間。