164 lines
5.8 KiB
C#
164 lines
5.8 KiB
C#
|
//------------------------------------------------------------------------------
|
|||
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
|||
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
|||
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
|||
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
|||
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
|||
|
// Github源代码仓库:https://github.com/RRQM
|
|||
|
// API首页:https://touchsocket.net/
|
|||
|
// 交流QQ群:234762506
|
|||
|
// 感谢您的下载和使用
|
|||
|
//------------------------------------------------------------------------------
|
|||
|
|
|||
|
#if NET6_0_OR_GREATER || NET481_OR_GREATER
|
|||
|
using System;
|
|||
|
using System.Collections.Concurrent;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Reflection;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using TouchSocket.Core;
|
|||
|
|
|||
|
namespace TouchSocket.Rpc
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// RpcDispatchProxy
|
|||
|
/// </summary>
|
|||
|
public abstract class RpcDispatchProxy<TClient, TAttribute> : DispatchProxy where TClient : IRpcClient where TAttribute : RpcAttribute
|
|||
|
{
|
|||
|
private readonly ConcurrentDictionary<MethodInfo, ProxyModel> m_methods = new ConcurrentDictionary<MethodInfo, ProxyModel>();
|
|||
|
private readonly MethodInfo m_fromResultMethod;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// RpcDispatchProxy
|
|||
|
/// </summary>
|
|||
|
public RpcDispatchProxy()
|
|||
|
{
|
|||
|
this.m_fromResultMethod = typeof(Task).GetMethod("FromResult");
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取调用Rpc的客户端。
|
|||
|
/// </summary>
|
|||
|
public abstract TClient GetClient();
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
protected sealed override object Invoke(MethodInfo targetMethod, object[] args)
|
|||
|
{
|
|||
|
var value = this.m_methods.GetOrAdd(targetMethod, this.AddMethod);
|
|||
|
var rpcMethod = value.RpcMethod;
|
|||
|
var invokeKey = value.InvokeKey;
|
|||
|
|
|||
|
var invokeOption = value.InvokeOption ? (IInvokeOption)args.Last() : InvokeOption.WaitInvoke;
|
|||
|
|
|||
|
object[] ps;
|
|||
|
if (value.InvokeOption)
|
|||
|
{
|
|||
|
var pslist = new List<object>();
|
|||
|
|
|||
|
for (var i = 0; i < args.Length; i++)
|
|||
|
{
|
|||
|
if (i < args.Length - 1)
|
|||
|
{
|
|||
|
pslist.Add(args[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ps = pslist.ToArray();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ps = args;
|
|||
|
}
|
|||
|
|
|||
|
this.OnBefore(targetMethod, value.InvokeKey, ref ps);
|
|||
|
|
|||
|
object result = default;
|
|||
|
|
|||
|
switch (rpcMethod.TaskType)
|
|||
|
{
|
|||
|
case TaskReturnType.Task:
|
|||
|
{
|
|||
|
this.GetClient().Invoke(invokeKey, invokeOption, ref ps, rpcMethod.ParameterTypes);
|
|||
|
result = EasyTask.CompletedTask;
|
|||
|
break;
|
|||
|
}
|
|||
|
case TaskReturnType.TaskObject:
|
|||
|
{
|
|||
|
var obj = this.GetClient().Invoke(rpcMethod.ReturnType, invokeKey, invokeOption, ref ps, rpcMethod.ParameterTypes);
|
|||
|
result = value.GenericMethod.Invoke(default, obj);
|
|||
|
break;
|
|||
|
}
|
|||
|
case TaskReturnType.None:
|
|||
|
default:
|
|||
|
{
|
|||
|
if (rpcMethod.HasReturn)
|
|||
|
{
|
|||
|
result = this.GetClient().Invoke(rpcMethod.ReturnType, invokeKey, invokeOption, ref ps, rpcMethod.ParameterTypes);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
this.GetClient().Invoke(invokeKey, invokeOption, ref ps, rpcMethod.ParameterTypes);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (rpcMethod.HasByRef)
|
|||
|
{
|
|||
|
for (var i = 0; i < ps.Length; i++)
|
|||
|
{
|
|||
|
args[i] = ps[i];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this.OnAfter(targetMethod, invokeKey, ref args, ref result);
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private ProxyModel AddMethod(MethodInfo info)
|
|||
|
{
|
|||
|
var attribute = info.GetCustomAttribute<TAttribute>(true) ?? throw new Exception($"在方法{info.Name}中没有找到{typeof(TAttribute)}的特性。");
|
|||
|
var rpcMethod = new RpcMethod(info);
|
|||
|
var invokeKey = attribute.GetInvokenKey(rpcMethod);
|
|||
|
var invokeOption = false;
|
|||
|
if (info.GetParameters().Length > 0 && typeof(IInvokeOption).IsAssignableFrom(info.GetParameters().Last().ParameterType))
|
|||
|
{
|
|||
|
invokeOption = true;
|
|||
|
}
|
|||
|
return new ProxyModel()
|
|||
|
{
|
|||
|
InvokeKey = invokeKey,
|
|||
|
RpcMethod = rpcMethod,
|
|||
|
InvokeOption = invokeOption,
|
|||
|
GenericMethod = rpcMethod.TaskType == TaskReturnType.TaskObject ? new Method(this.m_fromResultMethod.MakeGenericMethod(rpcMethod.ReturnType)) : default
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 方法调用前
|
|||
|
/// </summary>
|
|||
|
/// <param name="method"></param>
|
|||
|
/// <param name="invokeKey"></param>
|
|||
|
/// <param name="args"></param>
|
|||
|
/// <returns></returns>
|
|||
|
protected virtual void OnBefore(MethodInfo method, string invokeKey, ref object[] args)
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 方法调用后
|
|||
|
/// </summary>
|
|||
|
/// <param name="method"></param>
|
|||
|
/// <param name="invokeKey"></param>
|
|||
|
/// <param name="args"></param>
|
|||
|
/// <param name="result"></param>
|
|||
|
protected virtual void OnAfter(MethodInfo method, string invokeKey, ref object[] args, ref object result)
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|