最近一直在做.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

.net 动态代理的泛型方法支持问题的更多相关文章

  1. Hibernate学习--hibernate延迟加载原理(动态代理)

    在正式说hibernate延迟加载时,先说说一个比较奇怪的现象吧:hibernate中,在many-to-one时,如果我们设置了延迟加载,会发现我们在eclipse的调试框中查看one对应对象时,它 ...

  2. (转)细说JDK动态代理的实现原理

    原文:http://blog.csdn.net/mhmyqn/article/details/48474815 关于JDK的动态代理,最为人熟知的可能要数Spring AOP的实现,默认情况下,Spr ...

  3. Hibernate学习--hibernate延迟加载原理-动态代理(阿里电面)

    在正式说hibernate延迟加载时,先说说一个比较奇怪的现象吧:hibernate中,在many-to-one时,如果我们设置了延迟加载,会发现我们在eclipse的调试框中查看one对应对象时,它 ...

  4. AndroidInject项目使用动态代理增加对网络请求的支持

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3540427.html AndroidInject项目是我写的一 ...

  5. 十八、泛型 l 注解 l Servlet3.0 l 动态代理 l 类加载器基础加强

    l 泛型 l 注解 l Servlet3.0 l 动态代理 l 类加载器 泛型 1 回顾泛型类 泛型类:具有一个或多个泛型变量的类被称之为泛型类. public class A<T> { ...

  6. 从静态代理,jdk动态代理到cglib动态代理-一文搞懂代理模式

    从代理模式到动态代理 代理模式是一种理论上非常简单,但是各种地方的实现往往却非常复杂.本文将从代理模式的基本概念出发,探讨代理模式在java领域的应用与实现.读完本文你将get到以下几点: 为什么需要 ...

  7. Java动态代理全面分析

    代理模式 解说:给某一个对象提供一个代理,并由代理对象控制对原对象的引用: 代理模式需要以下几个角色: 1  主题:规定代理类和真实对象共同对外暴露的接口: 2  代理类:专门代理真实对象的类: 3 ...

  8. [原创]java WEB学习笔记104:Spring学习---AOP 前奏,通过一个问题引入动态代理

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  9. Java动态代理与Cglib库

    JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...

随机推荐

  1. 分享2个网址二维码API接口

    分享2个网址二维码生成API接口,用它们只需要填写好网址就能自动生成二维码,分别来自与bshare和jiathis分享工具中,如您需要就把下面的二维码生成API接口复制到你需要地方. 说明:把url= ...

  2. 坑!坑!坑!防不胜防的unsigned int的运算

    我很早之前就知道,unsigned int与int运算的时候,int会被转化为unsigned int来进行运算.一直觉得定这条规则的人是极度反人类的,虽说unsigned int可以表示更大的正值, ...

  3. VBS进行http请求及JSON数据的读取和生成

    背景: 近期帮一个公司做第三方API的二次封装,需要部署到该公司网站.所获取的是Json数据格式.由于该公司原系统采用的ASP+VBS技术方案,因此采用VBS对API进行请求.封装. 实现: 废话不多 ...

  4. ORA-01501: CREATE DATABASE failed

    使用dbca建库时遇到ORA-01501: CREATE DATABASE failed这个错误,检查告警日志,发现有下面错误信息: SMON: enabling tx recovery Fri Ap ...

  5. 4、解决native库不兼容

    解决native库不兼容 现象: 报警告 [root@hadoop1 hadoop-]# bin/hdfs dfs -ls /input // :: WARN util.NativeCodeLoade ...

  6. Spring MVC - 配置Spring MVC

    写在前面的话: 现在开始一段新的学习历程:Spring MVC.还是按照原来的三步走学习模式(what.why.how)进行讲解. 1.Spring MVC是什么(what) Spring MVC属于 ...

  7. gdb 定位 oops call trace

    [    1.454380] BUG: unable to handle kernel NULL pointer dereference at 00000000000005d0[    1.47402 ...

  8. 必须知道的八大种排序算法【java实现】(一) 冒泡排序、快速排序

    冒泡排序 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个 ...

  9. STM32时钟理解

    转载自 http://blog.sina.com.cn/s/blog_6ebd49350100q6xw.html STM32时钟理解 一.硬件上的连接问题 如果使用内部RC振荡器而不使用外部晶振,请按 ...

  10. 给ros安装arbotix simulator仿真环境

    首先下载程序包.编译.安装. cd ~/catkin_ws/src git clone https://github.com/pirobot/rbx1.git cd rbx1 git checkout ...