Skip to content

Commit 4435954

Browse files
author
liguoliang
committed
优化客户端调用逻辑
1 parent 74613cc commit 4435954

4 files changed

Lines changed: 160 additions & 56 deletions

File tree

src/DotNetCoreRpc.Client/HttpRequestInterceptor.cs

Lines changed: 27 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,72 +12,46 @@ namespace DotNetCoreRpc.Client
1212
{
1313
public class HttpRequestInterceptor : IInterceptor
1414
{
15-
private readonly HttpClient _httpClient;
15+
private readonly RequestHandler _requestHandler;
1616
public HttpRequestInterceptor(HttpClient httpClient)
1717
{
18-
_httpClient = httpClient;
18+
_requestHandler = new RequestHandler(httpClient);
1919
}
2020

2121
public void Intercept(IInvocation invocation)
2222
{
23-
HandleRequest(invocation).GetAwaiter().GetResult();
24-
}
23+
var methodReturnType = invocation.Method.ReturnType.GetTypeInfo();
2524

26-
private async Task HandleRequest(IInvocation invocation)
27-
{
28-
var methodInfo = invocation.Method;
29-
var requestModel = new RequestModel
30-
{
31-
TypeFullName = methodInfo.DeclaringType.FullName,
32-
MethodName = methodInfo.Name,
33-
Paramters = invocation.Arguments
34-
};
35-
HttpContent httpContent = new StringContent(requestModel.ToJson());
36-
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
37-
var responseMessage = await _httpClient.PostAsync("/DotNetCoreRpc/ServerRequest", httpContent);
38-
if (responseMessage.StatusCode == HttpStatusCode.OK)
25+
if (!methodReturnType.IsAsync())
3926
{
40-
var methodReturnType = methodInfo.ReturnType.GetTypeInfo();
41-
byte[] result = await responseMessage.Content.ReadAsByteArrayAsync();
42-
if (result != null && result.Length != 0)
27+
var result = _requestHandler.SyncResultHandle(invocation.Method, invocation.Arguments);
28+
if (result == null)
4329
{
44-
ResponseModel responseModel = result.FromJson<ResponseModel>();
45-
if (responseModel.Code != (int)HttpStatusCode.OK)
46-
{
47-
throw new Exception($"请求出错,返回内容:{Encoding.UTF8.GetString(result)}");
48-
}
49-
if (responseModel.Data != null)
50-
{
51-
if (!methodReturnType.IsAsync())
52-
{
53-
invocation.ReturnValue = responseModel.Data.ToJson().FromJson(methodInfo.ReturnType);
54-
return;
55-
}
30+
return;
31+
}
5632

57-
var returnValue = responseModel.Data.ToJson().FromJson(methodReturnType.GetGenericArguments()[0]);
58-
var resultType = invocation.Method.ReturnType.GetGenericArguments()[0];
59-
if (methodReturnType.IsTaskWithResult())
60-
{
61-
invocation.ReturnValue = TaskUtils.TaskResultFunc(resultType).Invoke(returnValue);
62-
return;
63-
}
33+
invocation.ReturnValue = result;
34+
return;
35+
}
6436

65-
if (methodReturnType.IsValueTaskWithResult())
66-
{
67-
invocation.ReturnValue = TaskUtils.ValueTaskResultFunc(resultType).Invoke(returnValue);
68-
return;
69-
}
70-
}
37+
if (methodReturnType.IsTask() || methodReturnType.IsValueTask())
38+
{
39+
invocation.ReturnValue = Task.CompletedTask;
40+
return;
41+
}
7142

72-
if (methodReturnType.IsTask() || methodReturnType.IsValueTask())
73-
{
74-
invocation.ReturnValue = Task.CompletedTask;
75-
return;
76-
}
77-
}
43+
if (methodReturnType.IsTaskWithResult())
44+
{
45+
invocation.ReturnValue = _requestHandler.GetTaskResultHandleFunc(methodReturnType).Invoke(invocation.Method, invocation.Arguments);
7846
return;
7947
}
80-
throw new Exception($"请求异常,StatusCode:{responseMessage.StatusCode}");
81-
}
48+
49+
if (methodReturnType.IsValueTaskWithResult())
50+
{
51+
invocation.ReturnValue = _requestHandler.GetValueResultHandleFunc(methodReturnType).Invoke(invocation.Method, invocation.Arguments);
52+
return;
53+
}
54+
}
55+
8256
}
8357
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using Castle.DynamicProxy;
2+
using DotNetCoreRpc.Core;
3+
using System;
4+
using System.Collections.Concurrent;
5+
using System.Collections.Generic;
6+
using System.Linq.Expressions;
7+
using System.Net;
8+
using System.Net.Http;
9+
using System.Net.Http.Headers;
10+
using System.Reflection;
11+
using System.Text;
12+
using System.Text.Json;
13+
using System.Threading;
14+
using System.Threading.Tasks;
15+
16+
namespace DotNetCoreRpc.Client
17+
{
18+
public class RequestHandler
19+
{
20+
private static readonly ConcurrentDictionary<TypeInfo, Func<MethodInfo, object[], object>> _taskFuncCache = new ConcurrentDictionary<TypeInfo, Func<MethodInfo, object[], object>>();
21+
private static readonly ConcurrentDictionary<TypeInfo, Func<MethodInfo, object[], object>> _valueTaskFuncCache = new ConcurrentDictionary<TypeInfo, Func<MethodInfo, object[], object>>();
22+
23+
private readonly HttpClient _httpClient;
24+
public RequestHandler(HttpClient httpClient)
25+
{
26+
_httpClient = httpClient;
27+
}
28+
29+
public object SyncResultHandle(MethodInfo methodInfo, params object[] arguments)
30+
{
31+
return TaskResultHandle<object>(methodInfo, arguments).GetAwaiter().GetResult();
32+
}
33+
34+
public Func<MethodInfo, object[], object> GetTaskResultHandleFunc(TypeInfo methodReturnType)
35+
{
36+
return _taskFuncCache.GetOrAdd(methodReturnType, type => {
37+
return GetHandleFunc(nameof(TaskResultHandle), type);
38+
});
39+
}
40+
41+
public Func<MethodInfo, object[], object> GetValueResultHandleFunc(TypeInfo methodReturnType)
42+
{
43+
return _valueTaskFuncCache.GetOrAdd(methodReturnType, type => {
44+
return GetHandleFunc(nameof(ValueResultHandle), type);
45+
});
46+
}
47+
48+
private Func<MethodInfo, object[], object> GetHandleFunc(string handleMethodName, TypeInfo methodReturnType)
49+
{
50+
var returnType = methodReturnType.GetGenericArguments()[0];
51+
var resultMethod = GetType().GetMethod(handleMethodName, BindingFlags.NonPublic | BindingFlags.Instance)!.MakeGenericMethod(returnType);
52+
ParameterExpression methodInfoSource = Expression.Parameter(typeof(MethodInfo), "methodInfo");
53+
ParameterExpression argumentsSource = Expression.Parameter(typeof(object[]), "arguments");
54+
var instance = Expression.Constant(this);
55+
var callExpr = Expression.Call(instance, resultMethod, methodInfoSource, argumentsSource);
56+
var convertBody = Expression.Convert(callExpr, typeof(object));
57+
var expr = Expression.Lambda<Func<MethodInfo, object[], object>>(convertBody, methodInfoSource, argumentsSource).Compile();
58+
return expr;
59+
}
60+
61+
private async Task<T> TaskResultHandle<T>(MethodInfo methodInfo, params object[] arguments)
62+
{
63+
var result = await SendRequest(methodInfo, arguments);
64+
if (result != null && result.Length != 0)
65+
{
66+
ResponseModel responseModel = result.FromJson<ResponseModel>();
67+
if (responseModel.Code != (int)HttpStatusCode.OK)
68+
{
69+
throw new Exception($"请求出错,返回内容:{Encoding.UTF8.GetString(result)}");
70+
}
71+
72+
TypeInfo methodReturnType = methodInfo.ReturnType.GetTypeInfo();
73+
if (methodReturnType.IsAsync())
74+
{
75+
methodReturnType = methodReturnType.GetGenericArguments()[0].GetTypeInfo();
76+
}
77+
78+
if (responseModel.Data is JsonElement jsonElement)
79+
{
80+
var returnValue = jsonElement.FromJson(methodReturnType);
81+
return (T)returnValue;
82+
}
83+
}
84+
85+
return default;
86+
}
87+
88+
private ValueTask<T> ValueResultHandle<T>(MethodInfo methodInfo, params object[] arguments)
89+
{
90+
var taskResult = TaskResultHandle<T>(methodInfo, arguments);
91+
return new ValueTask<T>(taskResult);
92+
}
93+
94+
private async Task<byte[]> SendRequest(MethodInfo methodInfo, params object[] arguments)
95+
{
96+
var requestModel = new RequestModel
97+
{
98+
TypeFullName = methodInfo.DeclaringType.FullName,
99+
MethodName = methodInfo.Name,
100+
Paramters = arguments
101+
};
102+
103+
HttpContent httpContent = new StringContent(requestModel.ToJson());
104+
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
105+
var responseMessage = await _httpClient.PostAsync("/DotNetCoreRpc/ServerRequest", httpContent);
106+
byte[] result = await responseMessage.Content.ReadAsByteArrayAsync();
107+
if (responseMessage.StatusCode == HttpStatusCode.OK)
108+
{
109+
return result;
110+
}
111+
112+
throw new Exception($"请求异常,StatusCode:{responseMessage.StatusCode}");
113+
}
114+
}
115+
}

src/DotNetCoreRpc.Core/JsonExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,15 @@ public static object FromJson(this byte[] utf8Json, Type type)
3737
{
3838
return JsonSerializer.Deserialize(utf8Json, type, serializerOptions);
3939
}
40+
41+
public static T FromJson<T>(this JsonElement jsonElement) where T : class, new()
42+
{
43+
return jsonElement.Deserialize<T>(serializerOptions);
44+
}
45+
46+
public static object FromJson(this JsonElement jsonElement, Type type)
47+
{
48+
return jsonElement.Deserialize(type, serializerOptions);
49+
}
4050
}
4151
}

src/DotNetCoreRpc.Server/DotNetCoreRpcMiddleware.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
using System.IO;
55
using System.Linq;
66
using System.Linq.Expressions;
7+
using System.Net;
78
using System.Reflection;
9+
using System.Text.Json;
810
using System.Threading.Tasks;
911
using DotNetCoreRpc.Core;
1012
using DotNetCoreRpc.Core.RpcBuilder;
@@ -27,7 +29,7 @@ public DotNetCoreRpcMiddleware(RequestDelegate next, RpcServerOptions rpcServerO
2729
public async Task InvokeAsync(HttpContext context)
2830
{
2931
var requestContent = await context.Request.ReadStringAsync();
30-
ResponseModel responseModel = new ResponseModel{ Code = 500 };
32+
ResponseModel responseModel = new ResponseModel{ Code = (int)HttpStatusCode.InternalServerError };
3133
if (string.IsNullOrEmpty(requestContent))
3234
{
3335
responseModel.Message = "未读取到请求信息";
@@ -70,7 +72,10 @@ private async Task HandleRequest(HttpContext context, RequestModel requestModel)
7072
{
7173
if (paramters[i].GetType() != methodParamters[i].ParameterType)
7274
{
73-
paramters[i] = paramters[i].ToJson().FromJson(methodParamters[i].ParameterType);
75+
if (paramters[i] is JsonElement jsonElement)
76+
{
77+
paramters[i] = jsonElement.FromJson(methodParamters[i].ParameterType);
78+
}
7479
}
7580
}
7681

@@ -101,7 +106,7 @@ private AspectPiplineBuilder CreatPipleline(RpcContext aspectContext)
101106
ResponseModel responseModel = new ResponseModel
102107
{
103108
Data = rpcContext.ReturnValue,
104-
Code = 200
109+
Code = (int)HttpStatusCode.OK
105110
};
106111
await aspectContext.HttpContext.Response.WriteAsync(responseModel.ToJson());
107112
});

0 commit comments

Comments
 (0)