最近一直在做.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. JMS(Java消息服务)入门教程

    什么是Java消息服务 Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建.发送.读取消息等,用于支持JAVA应用程序开发.在J2EE中 ...

  2. PMBOK学习笔记一

    项目管理就是将知识.技能.工具与技术应用于项目活动,以满足项目的要求.为了实现对这些知识的应用,需要对项目管理过程进行有效管理 为了取得项目成功,项目团队应该:. 选择适用的过程来实现项目目标:. 使 ...

  3. 十五天精通WCF——第十一天 如何对wcf进行全程监控

    说点题外话,我们在玩asp.net的时候,都知道有一个叼毛玩意叫做“生命周期”,我们可以用httpmodule在先于页面的page_load中 做一些拦截,这样做的好处有很多,比如记录日志,参数过滤, ...

  4. js 判断pc端或手机端

    <script> (function () { var navUA = navigator.userAgent; var defIncludeStr = "iPhone|Andr ...

  5. json数据处理实战:Kafka+Flume+Morphline+Solr+Hue数据组合索引

    背景:Kafka消息总线的建成,使各个系统的数据得以在kafka节点中汇聚,接下来面临的任务是最大化数据的价值,让数据“慧”说话. 环境准备: Kafka服务器*3. CDH 5.8.3服务器*3,安 ...

  6. oracle常用命令集合

    一. 表空间相关命令 创建数据表空间 create SMALLFILE tablespace dataSpace datafile 'E:\oracle\product\10.2.0\oradata\ ...

  7. Jmeter之Bean shell使用(一)

    一.什么是Bean Shell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法; BeanShell是一种松散类型的脚本语言(这点和JS类似); BeanS ...

  8. mongo数据备份及恢复脚本

    #!/bin/bashtime="$(date +"%Y.%m.%d")" id=`echo "show dbs;"|/usr/local/ ...

  9. Hadoop Kernel tunning

    /etc/security/limits.conf @ochadoop soft nofile 102642 @ochadoop hard nofile 102642 @ochadoop soft n ...

  10. Neutron VxLAN + Linux Bridge 环境中的网络 MTU

    1. 基础知识 1.1 MTU   一个网络接口的 MTU 是它一次所能传输的最大数据块的大小.任何超过MTU的数据块都会在传输前分成小的传输单元.MTU 有两个测量层次:网络层和链路层.比如,网络层 ...