.NET HttpClient 二次封装

2 篇文章 0 订阅
2 篇文章 0 订阅

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.代码可能有问题请谨慎使用

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值