最近一直在做.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. linux下svn命令使用大全(share)

     转自:http://blog.chinaunix.net/uid-22566367-id-1965771.html 1.将文件checkout到本地目录 svn checkout path(path ...

  2. 优化SqlServer--数据压缩

    数据压缩是对存储和性能优势的加强.减少数据库占用的磁盘空间量将减少整体数据文件存储空间,在一下几个方面增加吞吐量: 1.更好的I/O利用率,每个页面可以读写更多的数据. 2.更好的内存利用率,缓冲区可 ...

  3. js 获取json串中的值

    用js中著名的eval函数var strJSON = "{name:'json name'}";//得到的JSONvar obj = eval( "(" + s ...

  4. pt-diskstats 报错 Can't locate Time/HiRes.pm in @INC

    调用 pt-diskstats 时报错如下Can't locate Time/HiRes.pm in @INC [root@localhost ~]# pt-diskstats Can't locat ...

  5. js相对路径相关(比如:js中的路径依赖导入该js文件的路径)

    问题描述: 前几天调用同事的js接口文件,在他自己的html测试页面ok,在我这边调用时出现问题. debug过程中,将该测试html移到其他位置都不行,放到原html测试页面同层次路径下是OK的. ...

  6. MongoDB学习——基础入门

    MongoDB--基础入门 MongoDB是目前比较流行的一种非关系型数据库(NoSql),他的优势这里不废话,我们关注怎么使用它. 安装 下载,首先肯定要去下载,我们去官网下载,在国内,可能没FQ可 ...

  7. andriod fragment调用Activity函数方法

    (1)新增一个activity public MainActivity getMainActivity(); } (2)在MainActivity 的Java文件中增加 getMainActivit公 ...

  8. Tomcat免安装配置2

    Tomcat 是一款优秀的JSP/Servlet容器,最初由SUN开发,后来被贡献给了Apache社区.Tomcat现在的版本已到6.Tomcat6实现了Servlet2.5和JSP2.1规范.针对w ...

  9. cloudera cdh native lib

    如果通过命令行的方式安装cloudera 版本的hadoop,下载它的cdh版本. 解压后执行,你会发现报warning,没有native的库,lib/native是空的. 如何获取native的文件 ...

  10. git 添加远程仓库遇到的问题

    上午在学习廖雪峰老师的 git 教程(http://www.liaoxuefeng.com/),在添加远程仓库这一节中遇到了两个问题: 问题描述: 一.关联自己的远程仓库. fatal: Not a ...