2017年10月26日 星期四

C# HttpClient WebAPI : 12. 下載圖片檔案到本機儲存空間內

我們已經談完了,如何使用 HttpClient 進行 Web API 的 CRUD 操作,以及不同的資料編碼方式,讓我們可以順利的把不同格式資料,傳遞到遠端 Web API 控制器的動作方法內。
現在,我們需要進行二進位檔案型態的操作,在這兩篇文章中,我們會使用圖片檔案作為練習範例,我們需要從網站上下載圖片檔案、另外需要從用戶端把圖片檔案上傳到後端伺服器中;首先,我們來看看如何從網站下載圖片檔案(同樣的作法,你可以下載聲音、影片、PDF、Word等不同類型檔案)。

了解更多關於 [HttpClient Class] 的使用方式
了解更多關於 [使用 async 和 await 進行非同步程式設計] 的使用方式


下載圖片檔案到本機儲存空間內

我們在這裡撰寫一個方法 DownloadImageAsync,並且接收一個參數,指出要下載的圖片檔案名稱,接者,會與字串 http://vulcanwebapi.azurewebsites.net/Datas/ 組合成為一個新的 URL,這個 URL 將會指向網站伺服器上的一個圖片;最後,我們只需要對這個 URL 發出 GetAsync 方法的引數,這樣, HttpClient 類別物件就會取得這個遠端伺服器上的圖片檔案。
當取得了 HttpResponseMessage 類別物件之後,先檢查此次的 Http 呼叫是否為成功狀態,接者,使用 File.Open 建立一個檔案並且取得該檔案的 FileStream 物件,我們需要透過此物件,來將資料寫入到本機檔案中。
想要取得遠端伺服器上 HttpResponseMessage 類別物件的 Stream,可以使用這個 await response.Content.ReadAsStreamAsync() 表示式,最後,使用 stream.CopyTo(filestream); 敘述,把遠端伺服器上的內容,透過 Stream 寫入到本機檔案 Stream,完成產生本機的檔案。
private static async Task<APIResult> DownloadImageAsync(string filename)
{
    string ImgFilePath = $"My_{filename}";
    ImgFilePath = Path.Combine(Environment.CurrentDirectory, ImgFilePath);
    APIResult fooAPIResult;
    using (HttpClientHandler handler = new HttpClientHandler())
    {
        using (HttpClient client = new HttpClient(handler))
        {
            try
            {
                #region 呼叫遠端 Web API
                //string FooUrl = $"http://localhost:53494/api/Upload";
                string FooUrl = $"http://vulcanwebapi.azurewebsites.net/Datas/";
                HttpResponseMessage response = null;

                #region  設定相關網址內容
                var fooFullUrl = $"{FooUrl}{filename}";

                response = await client.GetAsync(fooFullUrl);
                #endregion
                #endregion

                #region 處理呼叫完成 Web API 之後的回報結果
                if (response != null)
                {
                    if (response.IsSuccessStatusCode == true)
                    {
                        using (var filestream = File.Open(ImgFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                        {
                            using (var stream = await response.Content.ReadAsStreamAsync())
                            {
                                stream.CopyTo(filestream);
                            }
                        }
                        fooAPIResult = new APIResult
                        {
                            Success = true,
                            Message = string.Format("Error Code:{0}, Error Message:{1}", response.StatusCode, response.Content),
                            Payload = ImgFilePath,
                        };
                    }
                    else
                    {
                        fooAPIResult = new APIResult
                        {
                            Success = false,
                            Message = string.Format("Error Code:{0}, Error Message:{1}", response.StatusCode, response.RequestMessage),
                            Payload = null,
                        };
                    }
                }
                else
                {
                    fooAPIResult = new APIResult
                    {
                        Success = false,
                        Message = "應用程式呼叫 API 發生異常",
                        Payload = null,
                    };
                }
                #endregion
            }
            catch (Exception ex)
            {
                fooAPIResult = new APIResult
                {
                    Success = false,
                    Message = ex.Message,
                    Payload = ex,
                };
            }
        }
    }

    return fooAPIResult;
}

觸發的 Web API 動作

這個範例中,將會指向 URL http://vulcanwebapi.azurewebsites.net/Datas/vulcan.png ,此時,將會要求網站伺服器回傳該檔案內容到用戶端(當然,您在後端 Web API 主機,也可以設計出各種 GET / POST / PUT 動作方法,回傳這個圖片內容到用戶端),其該動作的原始碼如下所示。

進行測試

在程式進入點函式,我們直接呼叫 DownloadImageAsync 方法,並且在應用程式可執行組件所在目錄,開啟這個圖片檔案。
static async Task Main(string[] args)
{
    var fooResult = await DownloadImageAsync("vulcan.png");
    Process myProcess = new Process();
    try
    {
        // true is the default, but it is important not to set it to false
        myProcess.StartInfo.UseShellExecute = true;
        myProcess.StartInfo.FileName = fooResult.Payload.ToString();
        myProcess.Start();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
    Console.WriteLine($"Press any key to Exist...{Environment.NewLine}");
    Console.ReadKey();
}

執行結果

這個測試將會輸出底下內容
Press any key to Exist...

HTTP 傳送與接收原始封包

讓我們來看看,這個 Web API 的呼叫動作中,在請求 (Request) 與 反應 (Response) 這兩個階段,會在網路上傳送了那些 HTTP 資料
  • 請求 (Request)
    在這裡是提供一個簡單的 GET 要求呼叫。
GET http://vulcanwebapi.azurewebsites.net/Datas/vulcan.png HTTP/1.1
Host: vulcanwebapi.azurewebsites.net
Connection: Keep-Alive
  • 反應 (Response)
    在 Http 回應封包中,我們看到了總共圖片檔案的長度為 160387,這部分可以從 Http Header 的 Content-Length 看到,另外,從 Http Header Content-Type: image/png 可以看得出來,伺服器回報這個回應內容是個 .png 圖片檔案。
    在最後面是這個圖片檔案的內容,由於這些都是經過編碼後的內容,我們僅僅顯示一小部分作為示意之用。
HTTP/1.1 200 OK
Content-Length: 160387
Content-Type: image/png
Last-Modified: Sun, 08 Oct 2017 16:09:22 GMT
Accept-Ranges: bytes
ETag: "1d3404fcd99d783"
Server: Kestrel
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=9d3635139ab6649f453417d1e9047b7ed7a79b7bef031b04afeb6a2c58b33d4e;Path=/;HttpOnly;Domain=vulcanwebapi.azurewebsites.net
Date: Mon, 23 Oct 2017 02:10:58 GMT

 PNG
 

IHDR              u         pHYs          +      tIME         8ǫe     tEXtAuthor    H    tEXtDescription      !#   
tEXtCopyr

*** FIDDLER: RawDisplay truncated at 128 characters. Right-click to disable truncation. ***

相關文章索引

C# HttpClient WebAPI 系列文章索引


了解更多關於 [HttpClient Class] 的使用方式
了解更多關於 [使用 async 和 await 進行非同步程式設計] 的使用方式



關於 Xamarin 在台灣的學習技術資源

Xamarin 實驗室 粉絲團
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
Xamarin.Forms @ Taiwan
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程


沒有留言:

張貼留言