From 5e3f453975e6a2517dc0c1c18392558bb0f023ed Mon Sep 17 00:00:00 2001 From: yao Date: Sun, 30 Oct 2022 18:14:28 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=A5=97=E7=94=A8SocketsHttpHandler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HackMD.API/HackMDClinet.cs | 54 +++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/HackMD.API/HackMDClinet.cs b/HackMD.API/HackMDClinet.cs index c97f8a1..ee74e8d 100644 --- a/HackMD.API/HackMDClinet.cs +++ b/HackMD.API/HackMDClinet.cs @@ -8,6 +8,17 @@ public class HackMDClient { private string token; + private readonly Lazy s_socketLazy = new Lazy(() => + { + var socketsHandler = new SocketsHttpHandler + { + PooledConnectionLifetime = TimeSpan.FromMinutes(10), + PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5), + MaxConnectionsPerServer = 10 + }; + return socketsHandler; + }); + public string Token { get { return token; } @@ -19,12 +30,20 @@ public HackMDClient(string token) this.Token = token; } - private string endpoint = "https://api.hackmd.io/v1/"; + HttpClient CreateHttpClient() + { + return new HttpClient(this.s_socketLazy.Value) + { + BaseAddress = new Uri("https://api.hackmd.io/v1/") + }; + } + #region "User API" + public User GetUserInformation() { - HttpClient client = new HttpClient(); - string uri = endpoint + $"/me"; + using HttpClient client = this.CreateHttpClient(); + string uri = "me"; // Request headers. client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); @@ -33,9 +52,11 @@ public User GetUserInformation() var UserObj = System.Text.Json.JsonSerializer.Deserialize(ResponseBody); return UserObj; } + #endregion #region "User Notes API" + /// /// Create a note /// @@ -43,23 +64,25 @@ public User GetUserInformation() /// public NoteResponse CreateNote(Note newHackMDNote) { - HttpClient client = new HttpClient(); - string uri = endpoint + "/notes"; + using HttpClient client = this.CreateHttpClient(); + string uri = "notes"; // Request headers. client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); var JSON = System.Text.Json.JsonSerializer.Serialize(newHackMDNote); var content = new StringContent(JSON, Encoding.UTF8, "application/json"); + // Asynchronously call the REST API method. var response = client.PostAsync(uri, content).Result; var ResponseBody = response.Content.ReadAsStringAsync().Result; var CreateNoteResponseObj = System.Text.Json.JsonSerializer.Deserialize(ResponseBody); return CreateNoteResponseObj; } + public NoteResponse GetNote(string noteId) { - HttpClient client = new HttpClient(); - string uri = endpoint + $"/notes/{noteId}"; + using HttpClient client = this.CreateHttpClient(); + string uri = $"notes/{noteId}"; // Request headers. client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); @@ -68,10 +91,13 @@ public NoteResponse GetNote(string noteId) var CreateNoteResponseObj = System.Text.Json.JsonSerializer.Deserialize(ResponseBody); return CreateNoteResponseObj; } - public bool UpdateNote(string noteId, string content, ReadWritePermission readPermission, ReadWritePermission writePermission, string permalink) + + public bool UpdateNote(string noteId, string content, ReadWritePermission readPermission, + ReadWritePermission writePermission, string permalink) { - HttpClient client = new HttpClient(); - string uri = endpoint + $"/notes/{noteId}"; + using HttpClient client = this.CreateHttpClient(); + + string uri = $"notes/{noteId}"; var obj = new { @@ -97,8 +123,9 @@ public bool UpdateNote(string noteId, string content, ReadWritePermission readPe /// public bool DeleteNote(string noteId) { - HttpClient client = new HttpClient(); - string uri = endpoint + $"/notes/{noteId}"; + using HttpClient client = this.CreateHttpClient(); + + string uri = $"notes/{noteId}"; // Request headers. client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); @@ -106,6 +133,7 @@ public bool DeleteNote(string noteId) var response = client.DeleteAsync(uri).Result; return response.StatusCode == System.Net.HttpStatusCode.NoContent; } + #endregion } -} +} \ No newline at end of file From c2662c39fd28f27cf21ff1988f9494b0b41cdc44 Mon Sep 17 00:00:00 2001 From: yao Date: Sun, 30 Oct 2022 21:02:27 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=94=B9=E7=94=A8=20static=20HttpClient?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HackMD.API/HackMDClinet.cs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/HackMD.API/HackMDClinet.cs b/HackMD.API/HackMDClinet.cs index ee74e8d..39d5a9d 100644 --- a/HackMD.API/HackMDClinet.cs +++ b/HackMD.API/HackMDClinet.cs @@ -8,7 +8,7 @@ public class HackMDClient { private string token; - private readonly Lazy s_socketLazy = new Lazy(() => + private static readonly Lazy s_socketLazy = new Lazy(() => { var socketsHandler = new SocketsHttpHandler { @@ -19,6 +19,14 @@ public class HackMDClient return socketsHandler; }); + private static readonly Lazy s_clientLazy = new Lazy(() => + new HttpClient(s_socketLazy.Value) + { + BaseAddress = new Uri("https://api.hackmd.io/v1/") + }); + + private static HttpClient s_client => s_clientLazy.Value; + public string Token { get { return token; } @@ -30,19 +38,11 @@ public HackMDClient(string token) this.Token = token; } - HttpClient CreateHttpClient() - { - return new HttpClient(this.s_socketLazy.Value) - { - BaseAddress = new Uri("https://api.hackmd.io/v1/") - }; - } - #region "User API" public User GetUserInformation() { - using HttpClient client = this.CreateHttpClient(); + var client = s_client; string uri = "me"; // Request headers. @@ -64,7 +64,7 @@ public User GetUserInformation() /// public NoteResponse CreateNote(Note newHackMDNote) { - using HttpClient client = this.CreateHttpClient(); + var client = s_client; string uri = "notes"; // Request headers. @@ -81,8 +81,8 @@ public NoteResponse CreateNote(Note newHackMDNote) public NoteResponse GetNote(string noteId) { - using HttpClient client = this.CreateHttpClient(); - string uri = $"notes/{noteId}"; + var client = s_client; + string uri = $"notes/{noteId}"; // Request headers. client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); @@ -95,9 +95,9 @@ public NoteResponse GetNote(string noteId) public bool UpdateNote(string noteId, string content, ReadWritePermission readPermission, ReadWritePermission writePermission, string permalink) { - using HttpClient client = this.CreateHttpClient(); + var client = s_client; - string uri = $"notes/{noteId}"; + string uri = $"notes/{noteId}"; var obj = new { @@ -123,9 +123,9 @@ public bool UpdateNote(string noteId, string content, ReadWritePermission readPe /// public bool DeleteNote(string noteId) { - using HttpClient client = this.CreateHttpClient(); + var client = s_client; - string uri = $"notes/{noteId}"; + string uri = $"notes/{noteId}"; // Request headers. client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); From faa200ef540ff1f8ce6dc158fe83eb63f3c5ad11 Mon Sep 17 00:00:00 2001 From: yao Date: Sun, 30 Oct 2022 23:49:09 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Async=20method?= =?UTF-8?q?=E3=80=81=E7=A7=BB=E9=99=A4=20static=20HttpClient?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HackMD.API/HackMD.API.csproj | 4 + HackMD.API/HackMDClinet.cs | 124 +++++++++++++++------------ HackMD.APITests/HackMDClinetTests.cs | 13 ++- 3 files changed, 77 insertions(+), 64 deletions(-) diff --git a/HackMD.API/HackMD.API.csproj b/HackMD.API/HackMD.API.csproj index 9a41e29..c3092cd 100644 --- a/HackMD.API/HackMD.API.csproj +++ b/HackMD.API/HackMD.API.csproj @@ -17,4 +17,8 @@ https://github.com/isdaviddong/HackMD.API https://github.com/isdaviddong/HackMD.API + + + + diff --git a/HackMD.API/HackMDClinet.cs b/HackMD.API/HackMDClinet.cs index 39d5a9d..dbb4a0b 100644 --- a/HackMD.API/HackMDClinet.cs +++ b/HackMD.API/HackMDClinet.cs @@ -1,6 +1,10 @@ using System; using System.Net.Http; +using System.Net.Http.Headers; using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication.JwtBearer; namespace HackMD.API { @@ -19,38 +23,40 @@ public class HackMDClient return socketsHandler; }); - private static readonly Lazy s_clientLazy = new Lazy(() => - new HttpClient(s_socketLazy.Value) - { - BaseAddress = new Uri("https://api.hackmd.io/v1/") - }); + private readonly string _token; - private static HttpClient s_client => s_clientLazy.Value; - - public string Token + public HackMDClient(string token) { - get { return token; } - set { token = value; } + this._token = token; } - public HackMDClient(string token) + static HttpClient CreateHttpClient(string token) { - this.Token = token; + return new HttpClient(s_socketLazy.Value) + { + DefaultRequestHeaders = + { + Authorization = new AuthenticationHeaderValue(JwtBearerDefaults.AuthenticationScheme, + token) + }, + BaseAddress = new Uri("https://api.hackmd.io/v1/") + }; } #region "User API" - public User GetUserInformation() + public User GetUserInformation() => this.GetUserInformationAsync().Result; + + public async Task GetUserInformationAsync(CancellationToken cancel = default) { - var client = s_client; + var client = CreateHttpClient(this._token); string uri = "me"; - // Request headers. - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); - var response = client.GetAsync(uri).Result; - var ResponseBody = response.Content.ReadAsStringAsync().Result; - var UserObj = System.Text.Json.JsonSerializer.Deserialize(ResponseBody); - return UserObj; + var request = CreateDefaultHttpRequest(token, uri); + var response = await client.SendAsync(request, cancel); + var responseBody = await response.Content.ReadAsStringAsync(); + var result = System.Text.Json.JsonSerializer.Deserialize(responseBody); + return result; } #endregion @@ -62,57 +68,57 @@ public User GetUserInformation() /// /// /// - public NoteResponse CreateNote(Note newHackMDNote) + public NoteResponse CreateNote(Note newHackMDNote) => this.CreateNoteAsync(newHackMDNote).Result; + + public async Task CreateNoteAsync(Note newHackMDNote, CancellationToken cancel = default) { - var client = s_client; + var client = CreateHttpClient(this._token); string uri = "notes"; - // Request headers. - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); - var JSON = System.Text.Json.JsonSerializer.Serialize(newHackMDNote); - var content = new StringContent(JSON, Encoding.UTF8, "application/json"); + var requestBody = System.Text.Json.JsonSerializer.Serialize(newHackMDNote); + var requestContent = new StringContent(requestBody, Encoding.UTF8, "application/json"); // Asynchronously call the REST API method. - var response = client.PostAsync(uri, content).Result; - var ResponseBody = response.Content.ReadAsStringAsync().Result; - var CreateNoteResponseObj = System.Text.Json.JsonSerializer.Deserialize(ResponseBody); - return CreateNoteResponseObj; + var response = await client.PostAsync(uri, requestContent, cancel); + var responseBody = await response.Content.ReadAsStringAsync(); + var result = System.Text.Json.JsonSerializer.Deserialize(responseBody); + return result; } - public NoteResponse GetNote(string noteId) + public NoteResponse GetNote(string noteId) => this.GetNoteAsync(noteId).Result; + + public async Task GetNoteAsync(string noteId) { - var client = s_client; + var client = CreateHttpClient(this._token); string uri = $"notes/{noteId}"; - // Request headers. - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); - var response = client.GetAsync(uri).Result; - var ResponseBody = response.Content.ReadAsStringAsync().Result; - var CreateNoteResponseObj = System.Text.Json.JsonSerializer.Deserialize(ResponseBody); - return CreateNoteResponseObj; + var response = await client.GetAsync(uri); + var responseBody = await response.Content.ReadAsStringAsync(); + var result = System.Text.Json.JsonSerializer.Deserialize(responseBody); + return result; } public bool UpdateNote(string noteId, string content, ReadWritePermission readPermission, + ReadWritePermission writePermission, string permalink) => + this.UpdateNoteAsync(noteId, content, readPermission, writePermission, permalink).Result; + + public async Task UpdateNoteAsync(string noteId, string content, ReadWritePermission readPermission, ReadWritePermission writePermission, string permalink) { - var client = s_client; + var client = CreateHttpClient(this._token); string uri = $"notes/{noteId}"; - var obj = new + var requestBody = System.Text.Json.JsonSerializer.Serialize(new { - content = content, + content, readPermission = readPermission.ToString(), writePermission = writePermission.ToString(), - permalink = permalink - }; - - // Request headers. - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); - var JSON = System.Text.Json.JsonSerializer.Serialize(obj); - var body = new StringContent(JSON, Encoding.UTF8, "application/json"); - var response = client.PatchAsync(uri, body).Result; - var ResponseBody = response.Content.ReadAsStringAsync().Result; + permalink + }); + var requestContent = new StringContent(requestBody, Encoding.UTF8, "application/json"); + var response = await client.PatchAsync(uri, requestContent); + var responseBody = await response.Content.ReadAsStringAsync(); return response.StatusCode == System.Net.HttpStatusCode.Accepted; } @@ -121,19 +127,25 @@ public bool UpdateNote(string noteId, string content, ReadWritePermission readPe /// /// /// - public bool DeleteNote(string noteId) + public bool DeleteNote(string noteId) => this.DeleteNoteAsync(noteId).Result; + + public async Task DeleteNoteAsync(string noteId) { - var client = s_client; + var client = CreateHttpClient(this._token); string uri = $"notes/{noteId}"; - // Request headers. - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.Token}"); - - var response = client.DeleteAsync(uri).Result; + var response = await client.DeleteAsync(uri); return response.StatusCode == System.Net.HttpStatusCode.NoContent; } #endregion + + private static HttpRequestMessage CreateDefaultHttpRequest(string token, string uri) + { + var request = new HttpRequestMessage(HttpMethod.Get, uri); + request.Headers.Add("Authorization", $"Bearer {token}"); + return request; + } } } \ No newline at end of file diff --git a/HackMD.APITests/HackMDClinetTests.cs b/HackMD.APITests/HackMDClinetTests.cs index 266bf52..df38f2c 100644 --- a/HackMD.APITests/HackMDClinetTests.cs +++ b/HackMD.APITests/HackMDClinetTests.cs @@ -1,8 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using HackMD.API; using System; -using System.Collections.Generic; -using System.Text; namespace HackMD.API.Tests { @@ -25,7 +22,7 @@ public HackMDClientTests() public void CreateNoteTest() { // 建立HackMDClient 物件 - HackMDClient c = new HackMDClient(token); //須提供token + HackMDClient c = new HackMDClient(this.token); //須提供token //建立新 Note var ret = c.CreateNote( new Note() @@ -39,14 +36,14 @@ public void CreateNoteTest() //取得 NoteId TempNoteId = ret.id; Assert.IsTrue(!string.IsNullOrEmpty(ret.id)); - //c.DeleteNote(ret.id); + // c.DeleteNote(ret.id); } [TestMethod()] public void DeleteNoteTest() { // 建立HackMDClient 物件 - HackMDClient c = new HackMDClient(token); //須提供token + HackMDClient c = new HackMDClient(this.token); //須提供token var ret = c.CreateNote( new Note() { @@ -67,7 +64,7 @@ public void DeleteNoteTest() public void UpdateNoteTest() { // 建立HackMDClient 物件 - HackMDClient c = new HackMDClient(token); //須提供token + HackMDClient c = new HackMDClient(this.token); //須提供token var ret = c.CreateNote( new Note() { @@ -94,7 +91,7 @@ public void UpdateNoteTest() public void GetNoteTest() { // 建立HackMDClient 物件 - HackMDClient c = new HackMDClient(token); //須提供token + HackMDClient c = new HackMDClient(this.token); //須提供token //建立文件 var ret = c.CreateNote( new Note()