using CloudBuilder.Core.DependencyInjection.Request; using CloudBuilder.Core.Policy; using CloudBuilder.Core.Service; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; /* 注意是否是全局作用域(winform如果没有加入局部作用域,则都是全局作用域) 全局作用域: using (var scope1 = ServiceProvider.CreateScope()) { YesNoPolicyRequest yesNoPolicyRequest = ServiceProvider.GetRequiredKeyedService(typeof(YesNoPolicyRequest).Name); SelectOption[] selectOptions = yesNoPolicyRequest.FindSelectOption(true); } */ namespace CloudBuilder.Core.Request { public class ServiceRequest : IServiceRequest { private readonly HttpClient request; private readonly IConfiguration configuration; private readonly IServiceProvider provider; private readonly IContext loginContext; private JsonSerializerSettings _jsonSettings; public ServiceRequest(HttpClient request, IConfiguration configuration, IServiceProvider provider) { this.request = request; this.configuration = configuration; this.provider = provider; this.loginContext = provider.GetService()!; this.request.BaseAddress = new Uri(this.configuration.GetValue("CloudBuilder:ServiceRequest:BaseAddress")!); this.request.DefaultRequestHeaders.Add("Accept", this.configuration.GetValue("CloudBuilder:ServiceRequest:DefaultRequestHeaders:Accept")); this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); if (this.request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) this.request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); this.request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); _jsonSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, ContractResolver = new DefaultContractResolver(), ReferenceLoopHandling = ReferenceLoopHandling.Ignore, DateFormatString = "yyyy-MM-dd HH:mm:ss" }; } public void SetToken(string token) { loginContext.SetToken(token); this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); } public void SetCulture(string culture) { loginContext.SetCulture(culture); if (this.request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) this.request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); this.request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, culture); } public void SetToken() { //如果后面工程注入IContext服務对象,那么就会取出GetToken(),如果为空,防止后面工程沒有注入會出錯。 IContext loginContext = provider.GetService()!; if (loginContext != null) { this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); } } public async Task GetAsync(string api) { return await GetWithHeadersAndQueryAsync(api, null!, null!); } public async Task GetWithQueryAsync(string api, Dictionary queryParams) { return await GetWithHeadersAndQueryAsync(api, null!, queryParams); } public async Task GetWithHeadersAsync(string api, Dictionary headers) { return await GetWithHeadersAndQueryAsync(api, headers, null!); } public async Task GetWithHeadersAndQueryAsync(string api, Dictionary headers, Dictionary queryParams) { string url = api; if (queryParams != null && queryParams.Count > 0) { List query = new List(); foreach (var param in queryParams) { query.Add(string.Format("{0}={1}", param.Key, param.Value)); } url = api + "?" + QuotedString.ToDelimiteredList(query.ToArray(), '&'); } if (headers != null && headers.Count > 0) { foreach (var header in headers) { if (request.DefaultRequestHeaders.Contains(header.Key)) request.DefaultRequestHeaders.Remove(header.Key); request.DefaultRequestHeaders.Add(header.Key, header.Value); } } this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); var response = await request.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); /* await request.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false) 如果在此处加入ConfigureAwait(false),返回是数组就会出错。 要将ConfigureAwait(false)这个方法放入到下面语句 var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); */ if (!response.IsSuccessStatusCode) { var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); string errors = string.Empty; if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); throw new Exception(string.Format("{0}\r\n{1}", response.ReasonPhrase, errors)); } response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); CheckException(responseJson); return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; } public async Task PostAsJsonAsync(string api, T data) { return await PostAsJsonAsync(api, null!, data); } public async Task PostAsJsonAsync(string api, Dictionary headers, T data) { if (headers != null && headers.Count > 0) { foreach (var header in headers) { if (request.DefaultRequestHeaders.Contains(header.Key)) request.DefaultRequestHeaders.Remove(header.Key); request.DefaultRequestHeaders.Add(header.Key, header.Value); } } this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; var response = await this.request.PostAsJsonAsync(api, data, options); if (!response.IsSuccessStatusCode) { //{"errors":{},"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-64ad066978f4471cb3c9ce219c213da9-bccca8afd14676b3-00"} var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); string errors = string.Empty; if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); throw new Exception(string.Format("{0}\r\n{1}", response.ReasonPhrase, errors)); } response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); CheckException(responseJson); return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; } private void CheckException(string responseJson) { if (string.IsNullOrEmpty(responseJson) || !responseJson.StartsWith("{\"SourceCode\":\"CloudBuilder.Core.")) return; if (responseJson.StartsWith("{\"SourceCode\":\"CloudBuilder.Core.ValidatedException")) { ValidatedException vex = JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; throw vex; } else if (responseJson.StartsWith("{\"SourceCode\":\"CloudBuilder.Core.ServiceErrorException")) { ServiceErrorException sex = JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; throw sex; } } public async Task PostAsJsonAsync(string api, Dictionary headers) { if (headers != null && headers.Count > 0) { foreach (var header in headers) { if (request.DefaultRequestHeaders.Contains(header.Key)) request.DefaultRequestHeaders.Remove(header.Key); request.DefaultRequestHeaders.Add(header.Key, header.Value); } } this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); var response = await this.request.PostAsync(api, null!); if (!response.IsSuccessStatusCode) { var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); string errors = string.Empty; if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); throw new Exception(string.Format("{0}\r\n{1}", response.ReasonPhrase, errors)); } response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); CheckException(responseJson); return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; } public async Task PostAsJsonAsync(string api) { this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); var response = await this.request.PostAsync(api, new StringContent(string.Empty)); if (!response.IsSuccessStatusCode) { var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); string errors = string.Empty; if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); throw new Exception(string.Format("{0}\r\n{1}", response.ReasonPhrase, errors)); } response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); CheckException(responseJson); return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; } public async Task PostAsync(string api) { this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); var response = await this.request.PostAsync(api, new StringContent(string.Empty)); if (!response.IsSuccessStatusCode) { var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); string errors = string.Empty; if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); throw new Exception(string.Format("{0}\r\n{1}", response.ReasonPhrase, errors)); } response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); CheckException(responseJson); } public async void DownloadFile(string api, string filePath, Action progressCallback = null!, Action completedCallback = null!) { this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); var response = await this.request.PostAsync(api, new StringContent(string.Empty)); if (!response.IsSuccessStatusCode) { var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); string errors = string.Empty; if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); throw new Exception(string.Format("{0}\r\n{1}", response.ReasonPhrase, errors)); } response.EnsureSuccessStatusCode(); long? totalBytes = response.Content.Headers.ContentLength; using (Stream contentStream = await response.Content.ReadAsStreamAsync(), fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)) { byte[] buffer = new byte[8192];// 8KB緩衝區 long totalRead = 0; int read; while ((read = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await fileStream.WriteAsync(buffer, 0, read); totalRead += read; if (progressCallback != null) progressCallback(totalRead); } } if (completedCallback != null) completedCallback(filePath); } public async Task PostAsync(string api, MultipartFormDataContent data) { this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken()); if (request.DefaultRequestHeaders.Contains(ClaimPolicy.HEADER_LOCALE)) request.DefaultRequestHeaders.Remove(ClaimPolicy.HEADER_LOCALE); request.DefaultRequestHeaders.Add(ClaimPolicy.HEADER_LOCALE, loginContext.GetCulture()); var response = await this.request.PostAsync(api, data); if (!response.IsSuccessStatusCode) { var responseContext = await response.Content.ReadAsStringAsync().ConfigureAwait(false); string errors = string.Empty; if (responseContext != null && responseContext.StartsWith("{\"errors\"")) errors = responseContext.Substring(11, responseContext.IndexOf("}") - 11); throw new Exception(string.Format("{0}\r\n{1}", response.ReasonPhrase, errors)); } response.EnsureSuccessStatusCode(); var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); CheckException(responseJson); return JsonConvert.DeserializeObject(responseJson, _jsonSettings)!; } public void AddHeaders(string name, string? value) { request.DefaultRequestHeaders.Add(name, value); } public void SetContext(IContext loginContext) { this.loginContext.SetCulture(loginContext.GetCulture()); this.loginContext.SetToken(loginContext.GetToken()); } public HttpClient GetHttpClient() { return request; } } }