最近一直在做.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. 集群服务器 时间同步 - Chrony

    greenplum,openstack等云计算项目需要集群服务器部署,服务器之间的时间需要同步,但并不是所有机器可以 直接连外网,这时可以用Chrony工具解决. 解决方法是将其中一台设为时间服务器, ...

  2. Java基础知识学习(八)

    IO操作 5个重要的类分别是:InputStream.OutStream.Reader.Writer和File类 面向字符的输入输出流 输入流都是Reader的子类, CharArrayReader ...

  3. Java成员的访问权限控制

    Java中的访问权限控制包含两个部分: 类的访问权限控制 类成员的访问权限控制 对类来说,访问权限控制修饰符可以是public或者无修饰符(默认的包访问权限): 对于类成员来说,访问权限控制修饰符可以 ...

  4. 一秒钟看懂SaaS、CRM、OA、ERP、HR、进销存

    自2014年以来,SaaS.CRM.OA.ERP.HR.APM.进销存.财务系统等,这些名词大量出现在微信朋友圈.电视楼宇广告和千百万融资资讯中.它们到底是什么意思?相互之间又有什么区别?在这个飞速发 ...

  5. java web 中的servlet讲解

    首先,解释一下解释一下什么是servlet?说一说Servlet的生命周期? servlet有良好的生存期的定义,包括加载和实例化.初始化.处理请求以及服务结束.这个生存期由javax.servlet ...

  6. SQL Server 2008 R2——VC++ ADO 操作 存储过程 向datetime类型参数传入空值

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  7. cocos2d之json使用实例

    前端使用: json管理器中函数解析: 对宠物技能map的定义: 宠物技能表单--数据的基础定义:

  8. php反射机制

    PHP5添加了一项新的功能:Reflection.这个功能使得phper可以reverse-engineer class, interface,function,method and extensio ...

  9. centos之开放80端口

    #/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT  #/sbin/iptables -I INPUT -p tcp --dport 22 -j ...

  10. perl多线程理解

    Thread:在使用多线程处理比较大的数据量的扫描,遇到读写文件可能死锁的问题. Perl 线程的生命周期 1.使用 threads 包的 create() 方法: use threads; sub ...