Files
Docker/CloudBuilder/CloudBuilder.Core/Request/ServiceRequest.cs
T
2026-09-06 16:07:04 +08:00

461 lines
22 KiB
C#

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;
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<YesNoPolicyRequest>(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<IContext>()!;
this.request.BaseAddress = new Uri(this.configuration.GetValue<string>("CloudBuilder:ServiceRequest:BaseAddress")!);
this.request.DefaultRequestHeaders.Add("Accept", this.configuration.GetValue<string>("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<IContext>()!;
if (loginContext != null)
{
this.request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loginContext.GetToken());
}
}
public async Task<R> GetAsync<R>(string api)
{
return await GetWithHeadersAndQueryAsync<R>(api, null!, null!);
}
public async Task<R> GetWithQueryAsync<R>(string api, Dictionary<string, string> queryParams)
{
return await GetWithHeadersAndQueryAsync<R>(api, null!, queryParams);
}
public async Task<R> GetWithHeadersAsync<R>(string api, Dictionary<string, string> headers)
{
return await GetWithHeadersAndQueryAsync<R>(api, headers, null!);
}
public async Task<R> GetWithHeadersAndQueryAsync<R>(string api, Dictionary<string, string> headers, Dictionary<string, string> queryParams)
{
string url = api;
if (queryParams != null && queryParams.Count > 0)
{
List<string> query = new List<string>();
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);
if (response.ReasonPhrase == "Forbidden")
throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance(provider).ComposeMessage(CoreMessagePolicy.NO_PERMISSION)));
throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors));
}
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
CheckException(responseJson);
return JsonConvert.DeserializeObject<R>(responseJson, _jsonSettings)!;
}
public async Task<R> PostAsJsonAsync<T, R>(string api, T data)
{
return await PostAsJsonAsync<T, R>(api, null!, data);
}
public async Task<R> PostAsJsonAsync<T, R>(string api, Dictionary<string, string> 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);
if (response.ReasonPhrase == "Forbidden")
throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance(provider).ComposeMessage(CoreMessagePolicy.NO_PERMISSION)));
throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors));
}
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
CheckException(responseJson);
return JsonConvert.DeserializeObject<R>(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<ValidatedException>(responseJson, _jsonSettings)!;
throw vex;
}
else if (responseJson.StartsWith("{\"SourceCode\":\"CloudBuilder.Core.ServiceErrorException"))
{
ServiceErrorException sex = JsonConvert.DeserializeObject<ServiceErrorException>(responseJson, _jsonSettings)!;
throw sex;
}
}
public async Task<R> PostAsJsonAsync<R>(string api, Dictionary<string, string> 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);
if (response.ReasonPhrase == "Forbidden")
throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance(provider).ComposeMessage(CoreMessagePolicy.NO_PERMISSION)));
throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors));
}
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
CheckException(responseJson);
return JsonConvert.DeserializeObject<R>(responseJson, _jsonSettings)!;
}
public async Task<R> PostAsJsonAsync<R>(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);
if (response.ReasonPhrase == "Forbidden")
throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance(provider).ComposeMessage(CoreMessagePolicy.NO_PERMISSION)));
throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors));
}
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
CheckException(responseJson);
return JsonConvert.DeserializeObject<R>(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);
if (response.ReasonPhrase == "Forbidden")
throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance(provider).ComposeMessage(CoreMessagePolicy.NO_PERMISSION)));
throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors));
}
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
CheckException(responseJson);
}
public async void DownloadFile(string api, string filePath, Action<long> progressCallback = null!, Action<string> 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);
if (response.ReasonPhrase == "Forbidden")
throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance(provider).ComposeMessage(CoreMessagePolicy.NO_PERMISSION)));
throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + 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<Stream> PostStreamAsync<T>(string api, Dictionary<string, string> 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
};
try
{
var response = await this.request.PostAsJsonAsync(api, data, options).ConfigureAwait(false);
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);
if (response.ReasonPhrase == "Forbidden")
throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance(provider).ComposeMessage(CoreMessagePolicy.NO_PERMISSION)));
throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors));
}
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStreamAsync();
}
catch (Exception ex )
{
throw ex;
}
}
public async Task<R> PostAsync<R>(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);
if (response.ReasonPhrase == "Forbidden")
throw new Exception(string.Format("{0}", CoreMessagePolicy.GetInstance(provider).ComposeMessage(CoreMessagePolicy.NO_PERMISSION)));
throw new Exception(string.Format("{0}{1}", response.ReasonPhrase, string.IsNullOrEmpty(errors) ? "" : "\r\n" + errors));
}
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
CheckException(responseJson);
return JsonConvert.DeserializeObject<R>(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; }
}
}