1. 创建请求类型特性
/// <summary>
///
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class PostAttribute : Attribute
{
public PostAttribute(string url)
{
Url = url;
}
public string Url { get; set; }
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class GetAttribute : Attribute
{
public GetAttribute(string url)
{
Url = url;
}
public string Url { get; set; }
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class DeleteAttribute : Attribute
{
public DeleteAttribute(string url)
{
Url = url;
}
public string Url { get; set; }
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class PutAttribute : Attribute
{
public PutAttribute(string url)
{
Url = url;
}
public string Url { get; set; }
}
2. 创建参数类型特性
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class QueryAttribute : Attribute
{
public QueryAttribute(string source)
{
Source = source;
}
public string Source { get; set; }
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class BodyAttribute : Attribute
{
public BodyAttribute()
{
}
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class PathAttribute : Attribute
{
public PathAttribute(string source)
{
Source = source;
}
public string Source { get; set; }
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class FormAttribute : Attribute
{
}
3. 创建一个代理
public class ApiClientFactory
{
public static T CreateClient<T>() where T : class
{
var proxy = DispatchProxy.Create<T, ClientProxy>();
return proxy;
}
public class ClientProxy : DispatchProxy
{
private readonly HttpClient _httpClient = HttpClientSingleton.GetFactory();
protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
{
try
{
// 获取异步调用的结果
var task = InvokeAsync(targetMethod, args);
if (targetMethod?.ReturnType == typeof(Task))
{
task.Wait();
return task;
}
if (targetMethod?.ReturnType == typeof(string))
{
task.Wait();
return Convert.ToString(task.Result);
}
if (targetMethod?.ReturnType?.IsValueType == true)
{
var returnType = targetMethod?.ReturnType;
task.Wait();
return Convert.ChangeType(task.Result, returnType!);
}
var resultProperty = task.GetType().GetProperty("Result");
task.Wait(); // 确保任务完成
var result = resultProperty?.GetValue(task);
// 检查目标方法是否期望返回 Task<T>
if (targetMethod?.ReturnType.IsGenericType == true &&
targetMethod.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
{
// 获取返回类型 Task<T> 的泛型参数类型
var resultType = targetMethod.ReturnType.GetGenericArguments()[0];
if (resultType.Name == "String")
{
if (result != null)
{
return Task.FromResult(Convert.ToString(result)!);
}
else
{
return Task.FromResult<string>(null);
}
}
if (resultType.IsValueType)
{
Task.FromResult(Convert.ChangeType(result, resultType));
}
// 创建 Task<T> 的实例
var taskCompletionSource = typeof(TaskCompletionSource<>)
?.MakeGenericType(resultType)
?.GetConstructor(Type.EmptyTypes)
?.Invoke(null);
typeof(TaskCompletionSource<>)
?.MakeGenericType(resultType)
?.GetMethod("SetResult")
?.Invoke(taskCompletionSource, new[] { Convert.ChangeType(result, resultType) });
return typeof(TaskCompletionSource<>)
?.MakeGenericType(resultType)
?.GetProperty("Task")
?.GetValue(taskCompletionSource);
}
// 对于非泛型 Task,返回原始 Task
return task;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
private async Task<object?> InvokeAsync(MethodInfo? targetMethod, object[] args)
{
try
{
var get = targetMethod?.GetCustomAttribute<GetAttribute>();
var post = targetMethod?.GetCustomAttribute<PostAttribute>();
var delete = targetMethod?.GetCustomAttribute<DeleteAttribute>();
var put = targetMethod?.GetCustomAttribute<PutAttribute>();
string? url = "";
if (get != null)
{
url = get?.Url;
}
else if (post != null)
{
url = post?.Url;
}
else if (delete != null)
{
url = delete?.Url;
}
else if (put != null)
{
url = put?.Url;
}
else
{
throw new Exception("接口得请求头必须包含一个POST GET PUT DELETE 特性");
}
var parameters = targetMethod?.GetParameters().ToList();
int i = 0;
var queryBuilder = new StringBuilder();
HttpContent? payloadContent = null;
parameters?.ForEach(item =>
{
if (item.GetCustomAttribute<PathAttribute>() is PathAttribute pathAttr)
{
url = url?.Replace($"{{{pathAttr.Source}}}", args[i].ToString());
}
else if (item.GetCustomAttribute<QueryAttribute>() is QueryAttribute queryAttr)
{
queryBuilder.AppendFormat("{0}={1}", queryAttr.Source, HttpUtility.UrlEncode(args[i].ToString()));
queryBuilder.Append('&');
}
else if (parameters[i].GetCustomAttribute<BodyAttribute>() is BodyAttribute)
{
payloadContent = new StringContent(JsonConvert.SerializeObject(args[i]), Encoding.UTF8, "application/json");
}
else if (parameters[i].GetCustomAttribute<FormAttribute>() is FormAttribute)
{
Dictionary<string, string> formData = new Dictionary<string, string>();
if (args[i] != null)
{
foreach (var property in args[i].GetType().GetProperties())
{
//公共属性添加到表单数据中
var value = property.GetValue(args[i]);
if (value != null)
{
formData.Add(property.Name, value?.ToString() ?? "");
}
}
}
payloadContent = new FormUrlEncodedContent(formData);
}
i++;
});
if (queryBuilder.Length > 0)
{
// 移除最后一个 '&' 字符
queryBuilder.Length--;
url = $"{url}?{queryBuilder}";
}
// 根据请求类型发送 HTTP 请求
Task<HttpResponseMessage>? responseTask = null;
responseTask = _httpClient.GetAsync(url);
if (get != null)
{
responseTask = _httpClient.GetAsync(url);
}
else if (post != null)
{
responseTask = _httpClient.PostAsync(url, payloadContent);
}
else if (delete != null)
{
responseTask = SendDeleteRequestWithPayloadAsync(url, payloadContent);
}
else if (put != null)
{
responseTask = _httpClient.PutAsync(url, payloadContent);
}
else
{
throw new Exception("接口得请求必须包含一个POST GET PUT DELETE 特性");
}
var response = await responseTask;
if (response.IsSuccessStatusCode)
{
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var returnType = targetMethod?.ReturnType;
if (returnType == typeof(Task)) return Task.CompletedTask;
if (returnType?.Name == "String") return responseContent;
if (returnType?.IsValueType == true) return Convert.ChangeType(responseContent, returnType);
if (returnType?.GenericTypeArguments[0].Name == "String")
{
return responseContent;
}
if (returnType == null) return null;
return JsonConvert.DeserializeObject(responseContent, returnType?.GenericTypeArguments[0]!);
}
else
{
return null;
}
}
catch (Exception ex)
{
throw new Exception($"{ex.Message}");
}
}
private async Task<HttpResponseMessage> SendDeleteRequestWithPayloadAsync(string? url, HttpContent? content)
{
var request = new HttpRequestMessage(HttpMethod.Delete, url)
{
Content = content
};
return await _httpClient.SendAsync(request);
}
}
}
4. 创建接口比如
public interface IApiService
{
[Post("WeatherForecast/Post")]
Task<PostTest> GetPost([Body] PostTest test);
[Post("WeatherForecast/FromPost")]
int GetFromPost([Form] PostTest test);
[Post("WeatherForecast/Post/{id}/{name}")]
Task<PostTest> GetPostPath([Path("id")] string id, [Path("name")] string name);
[Delete("WeatherForecast/Delete")]
Task<PostTest> GetDelete([Body]PostTest test);
[Delete("WeatherForecast/Delete/{id}/{name}")]
Task<PostTest> GetDelete([Path("id")] string id, [Path("name")] string name);
[Delete("WeatherForecast/DeleteP")]
Task<PostTest> GetDeleteP([Query("id")] string id, [Query("name")] string name);
}
5. 调用接口
var apiService = ApiClientFactory.CreateClient<IApiService>();
var result = await apiService.GetDeleteP("11", "22");
var result1 = await apiService.GetDelete("11", "22");
var a = apiService.GetFromPost(new Scheduling.Test.PostTest() { id = "11", name = "2323" });
6. 补上获取单例得方法
public class HttpClientSingleton
{
private static HttpClient _httpClient;
private HttpClientSingleton()
{
}
private static object o_lock = new object();
public static HttpClient GetFactory()
{
if (_httpClient is null)
{
lock (o_lock)
{
if (_httpClient is null)
{
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => { return true; };
clientHandler.SslProtocols = SslProtocols.None;
_httpClient = new HttpClient(clientHandler);
_httpClient.BaseAddress = new Uri("http://localhost:5119/");
}
}
}
return _httpClient;
}
}
7.代码可能有问题请谨慎使用