最近一直在做.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. ThreadLocal源码分析

    1.概述 ThreadLocal,可以理解为线程的局部变量,作用就是为每一个使用该变量的线程都提供一个变量值的副本,每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突. ThreadLo ...

  2. .htaccess绑定网站主目录的方法

    用过cpanel的基本都会知道要把自己的服务器脚本传到public_htmk这个文件夹下,这个就是整个网站的主目录,普通的Apache服务器可以用下面的代码来实现这种效果 RewriteEngine ...

  3. Oracle行内链接不会引起USER_TABLES中CHAIN_CNT值变化

    前几天和群里网友讨论一个关于行内链接(intra-block chaining)的问题,问题非常有意思,恰好今天有空,顺便整理了一下这些知识点. 问题描述:下面SQL,创建一个超过255列的表(实际为 ...

  4. Linux下GitLab的快速安装以及备份

    源码安装 GitLab 步骤繁琐:需要安装依赖包,Mysql,Redis,Postfix,Ruby,Nginx……安装完毕还得一个个手动配置这些软件,容易出错 一.安装 在Ubuntu 14上 修改/ ...

  5. English -有感过四六级后的托福单词表-附下载

    好像自从上学期不高不低过了六级之后就没怎么持续接触英语的东西了,欧,除了要debug的时候遇到问题了,去Google到了再用那些仅有的英语知识去看别人的文章.可能是因为看到的都是自己平时接触过的方面的 ...

  6. 2. Docker - 安装

    一.Docker介绍 1. Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上, 也可以实现虚拟化. 容器时完全使用沙 ...

  7. 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式

    注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...

  8. python 的异常及其处理

    Python 异常处理 python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误.你可以使用该功能来调试python程序. 异常处理: 本站Python教程会具体介绍. 断言 ...

  9. TCP聊天工具

    //前台书写 import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java ...

  10. 云计算之路-阿里云上:RDS用户的烦恼

    http://www.cnblogs.com/cmt/p/3586029.html *博主注:阿里云数据库真的这么可笑?