這是一篇關於如何在用戶端 (Client) 使用 HttpClient 類別的說明系列文章,在這裡我們將會說明如何使用 HttpClient 所建立的物件,進行遠端 Web API 的 Get / Post / Put / Delete 等動作的呼叫與接收回傳結果,當然,我們也會說明如何使用 QueryString / Form-Data / Multi-Part / JSON 等不同格式,將用戶端的資料,傳遞到遠端 Web API 的使用方式;除了一般純文字的 Web API 內容呼叫與回傳,我們在這裡也會進行如何處理 Binary 二進位的資料上傳與取得,我們將會說明如何上傳圖片檔案到遠端 Web API 伺服器上與如何使用 HttpClient 取得遠端 Web Server 上的圖片檔案,接著儲存到本機上。
當然,我們也需要了解如何從用戶端傳送 Http Header 與 Cookie 到遠端 Web API上,接著,如何在用戶端中,取得 Web API回報的 Cookie 與 Header 資料;尤其,我們也會展示如何顯示 HttpClient 下載大量資料的時候的進度回報事件設計方式與如何取消較長時間的 HttpClient 呼叫,最後,我們將會設定一個逾時時間,當執行 HttpClient 的 Web API 執行期間,花費時間超過我們所設定的時間,將會終止這樣的 Web API 呼叫之程式寫法。
HttpClient 系列文章索引
後端 Web API 的原始碼
namespace VulcanWebAPI.Controllers { [Route("api/[controller]")] public class ValuesController : Controller { // http://vulcanwebapi.azurewebsites.net/api/values [HttpGet] public APIResult Get() { APIResult foo = new APIResult() { Success = true, Message = "成功得所有資料集合", Payload = new List<APIData>() { new APIData() { Id =777, Name = "Vulcan01" }, new APIData() { Id =234, Name ="Vulcan02" } } }; return foo; } [HttpGet("QueryStringGet")] public APIResult QueryStringGet([FromQuery] APIData value) { APIResult foo; if (value.Id == 777) { foo = new APIResult() { Success = true, Message = "透過 Get 方法,接收到 Id=777", Payload = new APIData() { Id = 777, Name = "Vulcan by QueryStringGet" } }; } else { foo = new APIResult() { Success = false, Message = "無法發現到指定的 ID", Payload = null }; } return foo; } [HttpGet("GetException")] public APIResult GetException() { APIResult foo = new APIResult(); throw new Exception("喔喔,我發生錯誤了"); return foo; } [HttpGet("GetExceptionFilter")] [CustomExceptionFilter] public APIResult GetExceptionFilter() { APIResult foo = new APIResult(); throw new Exception("喔喔,我發生錯誤了"); return foo; } // http://vulcanwebapi.azurewebsites.net/api/values/777 [HttpGet("{id}")] public APIResult Get(int id) { APIResult foo; if (id == 777) { foo = new APIResult() { Success = true, Message = "透過 Get 方法,接收到 Id=777", Payload = new APIData() { Id = 777, Name = "Vulcan01" } }; } else { foo = new APIResult() { Success = false, Message = "無法發現到指定的 ID", Payload = null }; } return foo; } // http://vulcanwebapi.azurewebsites.net/api/Values // 使用 JSON 格式 [HttpPost] public APIResult Post([FromBody]APIData value) { APIResult foo; if (value.Id == 777) { foo = new APIResult() { Success = true, Message = "透過 post 方法,接收到 Id=777 資料", Payload = value }; } else { foo = new APIResult() { Success = false, Message = "無法發現到指定的 ID", Payload = null }; } return foo; } // http://vulcanwebapi.azurewebsites.net/api/Values/FormUrlencodedPost // 使用 FormUrlEncodedContent [HttpPost("FormUrlencodedPost")] public APIResult FormUrlencodedPost([FromForm]APIData value) { APIResult foo; if (value.Id == 777) { foo = new APIResult() { Success = true, Message = "透過 post 方法,接收到 Id=777 資料", Payload = value }; } else { foo = new APIResult() { Success = false, Message = "無法發現到指定的 ID", Payload = null }; } return foo; } [HttpPut] public APIResult Put(int id, [FromBody]APIData value) { APIResult foo; if (value.Id == 777) { foo = new APIResult() { Success = true, Message = "透過 Put 方法,接收到 Id=777 資料", Payload = value }; } else { foo = new APIResult() { Success = false, Message = "無法發現到指定的 ID", Payload = null }; } return foo; } [HttpDelete("{id}")] public APIResult Delete(int id) { APIResult foo; if (id == 777) { foo = new APIResult() { Success = true, Message = "Id=777 資料 已經刪除了", Payload = null }; } else { foo = new APIResult() { Success = false, Message = "無法發現到指定的 ID", Payload = null }; } return foo; } // http://vulcanwebapi.azurewebsites.net/api/values/HeaderPost [HttpPost("HeaderPost")] public APIResult HeaderGet([FromBody]LoginInformation loginInformation) { APIResult foo; StringValues VerifyCode = ""; this.HttpContext.Request.Headers.TryGetValue("VerifyCode", out VerifyCode); if (StringValues.IsNullOrEmpty(VerifyCode)) { foo = new APIResult() { Success = false, Message = "驗證碼沒有發現", Payload = null }; } else { if (VerifyCode != "123") { foo = new APIResult() { Success = false, Message = "驗證碼不正確", Payload = null }; } else { if (loginInformation.Account == "Vulcan" && loginInformation.Password == "123") { foo = new APIResult() { Success = true, Message = "這個帳號與密碼正確無誤", Payload = null }; } else { foo = new APIResult() { Success = false, Message = "這個帳號與密碼不正確", Payload = null }; } } } return foo; } [HttpPost("Login")] public async Task<APIResult> Login([FromBody]LoginInformation loginInformation) { APIResult foo; if (loginInformation.Account == "Vulcan" && loginInformation.Password == "123") { var claims = new List<Claim>() { new Claim(ClaimTypes.Name, "Herry"), new Claim(ClaimTypes.Role, "Users") }; var claimsIdentity = new ClaimsIdentity(claims, "myTest"); var principal = new ClaimsPrincipal(claimsIdentity); try { await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties { ExpiresUtc = DateTime.UtcNow.AddMinutes(20), IsPersistent = true, AllowRefresh = true }); foo = new APIResult() { Success = true, Message = "這個帳號與密碼正確無誤", Payload = null }; } catch (Exception ex) { Console.WriteLine(ex.Message); foo = new APIResult() { Success = false, Message = "這個帳號與密碼不正確", Payload = null }; } } else { foo = new APIResult() { Success = false, Message = "這個帳號與密碼不正確", Payload = null }; } return foo; } [Authorize] [HttpGet("LoginCheck")] public APIResult LoginCheck() { APIResult foo = new APIResult() { Success = true, Message = "成功得所有資料集合", Payload = new List<APIData>() { new APIData() { Id =777, Name = "Vulcan01" }, new APIData() { Id =234, Name ="Vulcan02" } } }; return foo; } [HttpGet("LongTimeGet")] public async Task<APIResult> LongTimeGet() { APIResult foo; await Task.Delay(5000); foo = new APIResult() { Success = true, Message = "透過 Get 方法", Payload = new APIData() { Id = 777, Name = "Vulcan01" } }; return foo; } } }
namespace VulcanWebAPI.Controllers { [Route("api/[controller]")] public class UploadController : Controller { APIResult fooAPIResult = new APIResult(); private IHostingEnvironment _HostingEnvironment; public UploadController(IHostingEnvironment hostingEnvironment) { _HostingEnvironment = hostingEnvironment; } [HttpPost] public async Task<APIResult> Post(List<IFormFile> files) { // https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads string webDatasRoot = Path.Combine(_HostingEnvironment.WebRootPath, "Datas"); long size = files.Sum(f => f.Length); // full path to file in temp location if (files.Count > 0) { foreach (var formFile in files) { if (formFile.Length > 0) { var filePath = Path.Combine(webDatasRoot, formFile.FileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await formFile.CopyToAsync(stream); } fooAPIResult.Success = true; fooAPIResult.Message = "檔案上傳成功"; fooAPIResult.Payload = new APIData { Id = 3000, Name = "Your Name", Filename = formFile.FileName }; } } } else { fooAPIResult.Success = false; fooAPIResult.Message = "沒有任何檔案上傳"; fooAPIResult.Payload = null; } return fooAPIResult; } [HttpPost("FileAndData")] public async Task<APIResult> FileAndData(List<IFormFile> files, LoginInformation loginInformation) { // https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads string webDatasRoot = Path.Combine(_HostingEnvironment.WebRootPath, "Datas"); long size = files.Sum(f => f.Length); // full path to file in temp location if (files.Count > 0) { foreach (var formFile in files) { if (formFile.Length > 0) { using (var memoryStream = new MemoryStream()) { await formFile.CopyToAsync(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(memoryStream); var fooContent = streamReader.ReadToEnd(); fooAPIResult.Success = true; fooAPIResult.Message = "檔案上傳成功"; fooAPIResult.Payload = new LoginInformation { Account = $">> {loginInformation.Account}", Password = $">> {loginInformation.Account}", VerifyCode = fooContent }; } } } } else { fooAPIResult.Success = false; fooAPIResult.Message = "沒有任何檔案上傳"; fooAPIResult.Payload = null; } return fooAPIResult; } } }
關於 Xamarin 在台灣的學習技術資源