一个分布式调用框架
场景:
一个服务端(S), n个客户端(C1,C2...Cn), Cx1 通过 S 调用 Cx2 ,x1,x2属于{1,2,3...n},上指定的方法
采用WCF,并且采用泛型 实现强类型编程
过程,C1在S上发出消息(通过消息推送服务器),C2收到消息后,执行方法并上报进度与结果
注意
IIS中AppDomain是否是一个的
C2上的消息处理不在UI线程,
步骤1:
定于输入输出类,声明接口并定于实现(调用模板方法)
输入输出结构--注意命名空间跟类名要C与S端一致
public class TestARequest { public long Id { get; set; } public String Name { get; set; } public List<String> Items { get; set; } } public class TestAResponse { public long Id { get; set; } public String Name { get; set; } public List<String> Items { get; set; } }
接口与实现
public LongInvokeBucketInfo TestAStartInvoke(string position, string methodName, TestARequest request) { Action<LongInvokeBucket> nofityAct = (bucket) => { NotifyUtil.PostCSCNotify(bucket.Guid, position, methodName,null); }; return LongInvokeBucketMgr.StartInvoke4CSC<TestARequest, TestAResponse>(nofityAct,request); } public LongInvokeResponse<TestAResponse> TestALoopInvoke(LongInvokeBucketInfo request) { return LongInvokeBucketMgr.LoopInvoke<TestAResponse>(request); } public String TestARefreshInvoke(LongInvokeResponse<TestAResponse> request) { return LongInvokeBucketMgr.RefreshInvoke(request); } public LongInvokeResponse<TestARequest> TestALoadInvokeParam(String guid) { return LongInvokeBucketMgr.LoadInvokeParam<TestARequest>(guid); }
客端户执行方法格式
public void TestA(String guid) { var link = new LongInvokeLink<TestARequest, TestAResponse, IKX_InvokeService>(); try { var callParam= link.Begin(guid); link.P(string.Format("收到Name:{0},Items.Count:{1}", callParam.Name, callParam.Items.Count),10); Thread.Sleep(1000 * 2); link.P("执行一些费劲的操作..."); Thread.Sleep(1000 * 3); link.P(80); link.P("要返回了..."); Thread.Sleep(1000 * 2); #region 构建方法返回 var rModle = new TestAResponse() { Id = 2, Name = "张士大夫" };//执行结果 rModle.Items = new List<string>(); for (int i = 0; i < 100; i++) { rModle.Items.Add("第Item" + i); } #endregion link.Complete4Success(rModle); } catch (Exception ex) { link.Complete4Fail(ex.Message); } }
执行方法需要定义在反射能获取到的类型里
const String C_KXKey = "-KXInvoke:"; const String C_KXKey2 = "-KXInvoke2:"; /// <summary> /// 对应SimpleMsgClientHandle /// 如果开头是$KXInvoke: /// 那么使用本扩展 /// 格式 $KXInvoke:方法名,参数1,参数2... /// </summary> /// <param name="msg"></param> private bool MsgHandleExtension(string msg) { try { var argTypes = new List<Type>(); var methodName = ""; var args = new List<Object>(); if (msg.StartsWith(C_KXKey)) { #region 模式A var arr = msg.Substring(C_KXKey.Length).Split("$".ToCharArray()); var invokeId = 0L; if (arr.Length >= 2) { invokeId = long.Parse(arr[0]); methodName = arr[1]; args.Add(invokeId); } argTypes.Add(typeof(long)); for (int i = 2; i < arr.Length; i++) { args.Add(arr[i]); argTypes.Add(typeof(String)); } #endregion } else if (msg.StartsWith(C_KXKey2)) { #region 模式A var arr = msg.Substring(C_KXKey2.Length).Split("$".ToCharArray()); var guid = ""; if (arr.Length >= 2) { guid = arr[0].Trim(); methodName = arr[1]; args.Add(guid); } argTypes.Add(typeof(String)); for (int i = 2; i < arr.Length; i++) { args.Add(arr[i]); argTypes.Add(typeof(String)); } #endregion } #region 执行反射调用 var method = this.GetType().GetMethod(methodName, argTypes.ToArray()); if (method != null) { if (args.Count <= 0) { method.Invoke(this, null); //单线程同步处理 } else { method.Invoke(this, args.ToArray()); } } else { Console.WriteLine("没有Public签名的方法:" + methodName); } #endregion } catch (Exception ex) { Console.WriteLine(ex.Message); } return true; }
调用端:
try { var method = "TestA";// txtMethod.Text.Trim(); var argsStr = txtArgs.Text.Trim(); var position = cbxPosition.Text.Trim(); if (string.IsNullOrWhiteSpace(method) || string.IsNullOrWhiteSpace(position)) { throw new Exception("必需提供方法名称与工位!"); } var service =ServiceRTLocator.New<IKX_InvokeService>(); var request = new TestARequest() { Id = 999, Name = "9999",Items=new List<string>() }; request.Items.AddRange(new String[] {"A","B","C" }); var v = LongInvoke<TestARequest, TestAResponse>(request,position,method, new LongInvokeControl(service, "TestAStartInvoke", "TestALoopInvoke")); this.kXInvokeBindingSource.DataSource = v.Items; } catch (Exception ex) { ErrMsg(ex.Message); }
//===注意 2个反射代码-------其他的不再使用了,留备用
else if (msg.StartsWith(C_KXKey2)) { #region 模式B var arr = msg.Substring(C_KXKey2.Length).Split("$".ToCharArray()); var guid = ""; if (arr.Length >= 2) { guid = arr[0].Trim(); methodName = arr[1]; args.Add(guid); } argTypes.Add(typeof(String)); for (int i = 2; i < arr.Length; i++) { args.Add(arr[i]); argTypes.Add(typeof(String)); } #endregion var invokeInfo = FetchInfo(methodName); //针对方法路由 var methodInfo = invokeInfo.Impl.GetType().GetMethod(methodName); var ps = methodInfo.GetParameters(); var attrs = methodInfo.GetCustomAttributes(typeof(KXInvokeAttribute), false); if (attrs.Length > 0) { CallContext.SetData(C_KXMethodName, methodName); Object linkSvc = null; MethodInfo loadParamMInfo = null; MethodInfo failMInfo = null; MethodInfo completedMInfo = null; try { #region 采用无感模式 var attr = attrs[0] as KXInvokeAttribute; //var serviceTypeName = attr.Action; //var serviceType= FetchInfo(serviceTypeName).InterfaceType; #region Action 中设置com.geelyhdIServer.IKX_InvokeSerive //var segmentList = serviceTypeName.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); ////类型不在同个程序集合 //var interfaceName= segmentList.LastOrDefault(); //var assembleName= serviceTypeName.Replace("." + interfaceName,""); //var serviceType = Assembly.Load(assembleName).GetType(serviceTypeName); #endregion var inType = ps[0].ParameterType; var outType = methodInfo.ReturnType; var linkGenericType =typeof(LongInvokeLink<,,>); //var linkGenericType = Type.GetType("XXXX....LongInvokeLink`3"); var linkType = linkGenericType.MakeGenericType(inType, outType, serviceType); completedMInfo = linkType.GetMethod("Complete4Success"); failMInfo = linkType.GetMethod("Complete4Fail"); loadParamMInfo = linkType.GetMethod("Begin"); linkSvc = Activator.CreateInstance(linkType, guid); //获取输入参数 var inModel = loadParamMInfo.Invoke(linkSvc, null); CallContext.SetData(C_KXLink, linkSvc); //执行调用 var outModel = methodInfo.Invoke(_MethodHost, new object[] { inModel }); //上传返回值 completedMInfo.Invoke(linkSvc, new object[] { outModel }); #endregion } catch (Exception ex) { if (linkSvc != null && failMInfo!=null) { failMInfo.Invoke(linkSvc, new Object[] { ex.Message }); } } finally { CallContext.SetData(C_KXMethodName, null); CallContext.FreeNamedDataSlot(C_KXMethodName); CallContext.SetData(C_KXLink, null); CallContext.FreeNamedDataSlot(C_KXLink); } return true; }
透明代理
namespace F.Studio.KXInvoke { public class KXInvokeLocalHandle : MarshalByRefObject { /// <summary> /// 变成http方式传输 /// Post方式 /// </summary> /// <param name="obj"></param> /// <returns></returns> public KXInvokeEntity Do(KXInvokeEntity callEnt) { Console.WriteLine("方法执行了!"); return callEnt; } } public class KXInvokeEntity { public String MethodName { get; set; } public String InterfaceName { get; set; } public Object InModel { get; set; } public Object OutModel { get; set; } public static KXInvokeEntity Parse(IMethodCallMessage msg) { var ent = new KXInvokeEntity(); ent.MethodName = msg.MethodName; ent.InterfaceName = Type.GetType(msg.TypeName,true,true).FullName; ent.InModel = msg.InArgs[0]; return ent; } } public class KXInvokeProxy : RealProxy { private KXInvokeLocalHandle _Handler; public KXInvokeProxy(Type type) : base(type) { _Handler = new KXInvokeLocalHandle(); } public override IMessage Invoke(IMessage msg) { PreProceede(msg); IMethodCallMessage callMessage = (IMethodCallMessage)msg; var callEnt = _Handler.Do(KXInvokeEntity.Parse( callMessage)); PostProceede(msg); return new ReturnMessage(callEnt.OutModel, new object[0], 0, null, callMessage); } public void PreProceede(IMessage msg) { Console.WriteLine("方法执行前"); } public void PostProceede(IMessage msg) { Console.WriteLine("方法执行后"); } } public class KXInvokeFactory { public static T Fetch<T>() where T : class { var realProxy = new KXInvokeProxy(typeof(T)); var transparentProxy = realProxy.GetTransparentProxy(); return realProxy.GetTransparentProxy() as T; } } }