.NET BCL Series (TCP Client / HTTP Client) | Network

2022-07-01

筆記 .NET Base Class Library 各式基礎函式庫的使用原理與技巧,讓開發 .NET 程式自然且流暢 🙂

logo

說明

TCPClient

測試伺服器與特定 Port 否啟用,並且以 1 秒鐘立刻逾時 (timeout)。

var client = new System.Net.Sockets.TcpClient();
var success = false;
try
{
    var task = client.BeginConnect("web1", 80, null, null);
    success = task.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
}
catch (Exception)
{

}

HttpClient

.NET 推薦在 HTTP 互動的類別上優先使用 HttpClient,早期的 WebClient 以及 WebRequest 已經被警示為 Deprecated。但 HttpClient 無法與 FTP 互動以及顯示傳送進度,仍不可完全取代 WebClient。

.NET Framework 當中, HttpClient 的底層仍是 HttpWebRequest 到了 .NET 才有獨立的 HttpClient 以 SocketsHttpHandler 實作

using System.Net.Http;
using System.Net;

static readonly HttpClient client = new HttpClient();
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

HttpResponseMessage response = await client.GetAsync("https://httpstat.us/404");
Console.WriteLine((int)response.StatusCode);

string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);

預設 HttpClient 可以回應各種 StatusCode,如果要限制成功 (Success 200) 的情況,可以使用 response.EnsureSuccessStatusCode 讓不是 200 的 StatusCode Raise Exception。

response.EnsureSuccessStatusCode();

預設上 .NET 會自動選擇適合的 TLS Portocol,但可能碰到回應 Server 只支援 TLS 1.2 以上而無法成功建立連線的問題,這個時候可以透過 ServicePointManager.SecurityProtocol 來指定 Client 端要使用的 TLS 版本。

System.Net.SecurityProtocolType.Ssl3
System.Net.SecurityProtocolType.Tls
System.Net.SecurityProtocolType.Tls11
System.Net.SecurityProtocolType.Tls12
System.Net.SecurityProtocolType.Tls13

NTLM

在 HttpClientHandler 設定 UseDefaultCredentials 為 true,HttpClient 物件在發送 HTTP 請求時,就會使用目前執行緒的 Windows 身分來進行驗證 (NTLM)。

using (var client = 
    new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }))
{
    using (var response = await client.GetAsync(url))
    {
        if (response.IsSuccessStatusCode)
        {
            result = await response.Content.ReadAsStringAsync();
        }
    }
}

HTTP Upload File

HttpClient

下列是伺服器端負責接收檔案上傳的 Code,可以接收多個檔案。

Controller.cs

public ActionResult Upload(HttpPostedFileBase[] files)
{
    var fileUploads = new List<FiledUploaded> {  };

    foreach (var file in files)
    {
        var fileUpload = new FiledUploaded(file, Server.MapPath("~/Uploads/"));

        file.SaveAs(Path.Combine(fileUpload.ServerPath, fileUpload.GuidName));

        fileUploads.Add(fileUpload);
    }

    return View(fileUploads);
}

下列是 Client 端負責將檔案進行上傳的 Code,示範多檔上傳的方式。

UploadProgram.cs

using System.Net;
using System.Net.Http;

string url = "https://localhost:12345/Home/Upload";

var formData = new MultipartFormDataContent();

formData.Add(
    new StreamContent(new FileStream(@"C:\temp\sun.png", FileMode.Open))
    ,"files" // name Mapping Controler's HttpPostedFileBase[] Parameters
    ,"moon.png" // fileName
);

formData.Add(
    new StreamContent(new FileStream(@"C:\temp\moon.png", FileMode.Open))
    ,"files"
    ,"sun.png"
);

using (var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true })){

    var httpResponseMessage = await client.SendAsync(
        new HttpRequestMessage(HttpMethod.Post, url)
        {
            Content = formData
        });
    Console.WriteLine(httpResponseMessage.StatusCode);
}

需要注意的是 MultipartFormDataContent 所加入的 HttpContent 所指定的 name 必須要與接收伺服器端的 Controller 的參數一致,本例都是 files

如果接收端需要 Windows 驗證,可以在 HttpClient 使用 HttpClientHandler 並且使用 UseDefaultCredentials 會使用目前 Client 端登入的 Windows 驗證進行傳送。