遗忘海岸

江湖程序员 -Feiph(LM战士)

导航

一个分布式调用框架

场景:

一个服务端(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; }
    }
View Code

 

接口与实现

        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);
 
        }
View Code

 

客端户执行方法格式

        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);
            }
        }
View Code

 

执行方法需要定义在反射能获取到的类型里

        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;
        }
View Code

 

调用端:

            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);
            }
View Code

 

 

//===注意 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;
                    }
View Code

 

透明代理

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;
        }

    }
}
View Code

 

posted on 2021-04-12 10:34  遗忘海岸  阅读(89)  评论(0编辑  收藏  举报