zoukankan      html  css  js  c++  java
  • .net 动态代理的泛型方法支持问题

        最近一直在做.net平台下的高速服务框架。其中有一个问题一直困扰着我:通过动态代理RealProxy创建的服务代理,不支持泛型方法调用。比如:

    接口声明:

    public interface IMetedataService
    {
        string GetData<T>(T p);

        string GetDataWithHSF<T>(T p);
    }

    接口实现:

    public class EventMetadataService:IMetedataService
       {
           public string GetData<T>(T p)
           {
               JavaScriptSerializer ser = new JavaScriptSerializer();
               return ser.Serialize(p);
           }

           public string GetDataWithHSF<T>(T p)
           {
               JavaScriptSerializer ser = new JavaScriptSerializer();
               string data = ser.Serialize(p);

               string getdata = HSFService.Proxy<IMetedataService>().GetData<string>(DateTime.Now.ToLongTimeString());
               return getdata + " " + data;

           }
       }

        EventMetadataService被部署到HSF的Container中。在HSF的Consumer端,调用代码如下。此代码在执行时会出现异常:不能对containsgenericparameters为true的类型或方法执行后期绑定操作

    EventData dd = new EventData();
                dd.ID = Guid.NewGuid().ToString();
                dd.Code = "Good boy";
                dd.Names = data;
                List<EventData> res = new List<EventData>();
                res.Add(dd);

                var result = HSFService.Proxy<IMetedataService>().GetData<List<EventData>>(res);

        在HSFService中,通过动态代理远程调用HSF的Container服务。重载了RealProxy,其的核心代码如下:

    public override IMessage Invoke(IMessage msg)
            {
              
                DateTime start = DateTime.Now;
                RemoteInvokeMessage requestMessage = null;
                var message = msg as IMethodCallMessage;
                if (message == null)
                {
                    return null;
                }

                try
                {
                    requestMessage = new RemoteInvokeMessage
                    {
                        ServiceClassName = typeof(TProxy).FullName,
                        MethodName = message.MethodName,
                        Parameters = message.InArgs,
                        Version = this._serviceVersion,
                        Properties = new System.Collections.Generic.Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                    };

                    var responseMessage = tcpClient.SendMessageAndWaitForResponse(requestMessage) as RemoteInvokeReturnMessage;
                    if (responseMessage == null)
                    {
                        return null;
                    }

                    if (responseMessage.RemoteException != null)
                    {
                      return new ReturnMessage(responseMessage.RemoteException, message);

                    }
                    else
                    {
                        return new ReturnMessage(responseMessage.ReturnValue, null, 0, message.LogicalCallContext, message);
                    }
                }
                catch (Exception ex)
                {
                    return new ReturnMessage(ex, message);
                }
            }
        }

      为了解决上述异常,修改了RealProxy的Invoke代码,并在RemoteInvokeMessage中加入了记录泛型方法的属性:

    public string[] GenericTypes { get; set; }

     Invoke方法的代码更新如下:

    public override IMessage Invoke(IMessage msg)
            {
              
                DateTime start = DateTime.Now;
                RemoteInvokeMessage requestMessage = null;
                var message = msg as IMethodCallMessage;
                if (message == null)
                {
                    return null;
                }

                try
                {
                    requestMessage = new RemoteInvokeMessage
                    {
                        ServiceClassName = typeof(TProxy).FullName,
                        MethodName = message.MethodName,
                        Parameters = message.InArgs,
                        Version = this._serviceVersion,
                        Properties = new System.Collections.Generic.Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                    };

            if (message.MethodBase!= null && message.MethodBase.IsGenericMethod)
                    {
                        var tps= message.MethodBase.GetGenericArguments();
                        if (tps != null)
                        {
                            List<string> strTypes = new List<string>();
                           
                            foreach (var item in tps)
                            {
                                strTypes.Add(JsonConvert.SerializeObject(item));
                            }

                            requestMessage.GenericTypes = strTypes.ToArray();
                        }
                    }

                    var responseMessage = tcpClient.SendMessageAndWaitForResponse(requestMessage) as RemoteInvokeReturnMessage;
                    if (responseMessage == null)
                    {
                        return null;
                    }

                    if (responseMessage.RemoteException != null)
                    {
                      return new ReturnMessage(responseMessage.RemoteException, message);

                    }
                    else
                    {
                        return new ReturnMessage(responseMessage.ReturnValue, null, 0, message.LogicalCallContext, message);
                    }
                }
                catch (Exception ex)
                {
                    return new ReturnMessage(ex, message);
                }
            }
        }

      上面标记代码,主要是提取了泛型方法的类型。只要把类型传递到HSF Container中,就可反射加载相关类型,并在反射调用方法时,通过MakeGenericMethod方法设置泛型类型,从而解决异常“不能对containsgenericparameters为true的类型或方法执行后期绑定操作”。

    MethodInfo m = null;
               if (methodMap.ContainsKey(methodName) == true)
               {
                   if (methodMap.TryGetValue(methodName, out m) == false)
                       m = InternalGetMethod(typeName, methodName, m, arg);
               }
               else
                   m = InternalGetMethod(typeName, methodName, m, arg);

               if (m.IsGenericMethod)
               {
                   List<Type> typs = new List<Type>();
                   if (message.GenericTypes != null)
                   {
                       foreach (string item in message.GenericTypes)
                       {
                           typs.Add(GetDataType(item));
                       }
                   }
                   m = m.MakeGenericMethod(typs.ToArray());
               }

        顺便说一句,HSF Container拿到泛型方法的类型后,需要转换为Type类型对象,这里也有很多的问题和技巧,贴一下我的解决方案把。

    private Type GetDataType(string item)
            {
                string asmName = string.Empty;
                string tName = string.Empty;

                var citem = item.Replace(""", "");

                Type result = Type.GetType(citem, false, true);
                if (result != null)
                    return result;
                if (result == null)
                    result = Type.ReflectionOnlyGetType(citem, false, true);
                if (result != null)
                    return result;

                throw new HSFException(ErrorCode.InvalideParam, "无法找到类型:" + item);

            }

        一定要确保类型对应的程序集已经被加载。

    魏亮 2016-2-1

  • 相关阅读:
    数据库流行度9月排行榜:Oracle 的老骥伏枥和 MongoDB 逆风飞扬
    ssh 执行单引号和双引号问题
    【Netapp】在模拟器中使用disk removeowner报错
    ES6的let和const命令(一)
    ES6的let和const命令(一)
    ES6的let和const命令(一)
    ES6的let和const命令(一)
    Android开发之《异常处理》
    Android开发之《异常处理》
    Android开发之《异常处理》
  • 原文地址:https://www.cnblogs.com/teld/p/5174952.html
Copyright © 2011-2022 走看看