.net 动态代理的泛型方法支持问题
最近一直在做.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 动态代理的泛型方法支持问题的更多相关文章
- Hibernate学习--hibernate延迟加载原理(动态代理)
在正式说hibernate延迟加载时,先说说一个比较奇怪的现象吧:hibernate中,在many-to-one时,如果我们设置了延迟加载,会发现我们在eclipse的调试框中查看one对应对象时,它 ...
- (转)细说JDK动态代理的实现原理
原文:http://blog.csdn.net/mhmyqn/article/details/48474815 关于JDK的动态代理,最为人熟知的可能要数Spring AOP的实现,默认情况下,Spr ...
- Hibernate学习--hibernate延迟加载原理-动态代理(阿里电面)
在正式说hibernate延迟加载时,先说说一个比较奇怪的现象吧:hibernate中,在many-to-one时,如果我们设置了延迟加载,会发现我们在eclipse的调试框中查看one对应对象时,它 ...
- AndroidInject项目使用动态代理增加对网络请求的支持
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3540427.html AndroidInject项目是我写的一 ...
- 十八、泛型 l 注解 l Servlet3.0 l 动态代理 l 类加载器基础加强
l 泛型 l 注解 l Servlet3.0 l 动态代理 l 类加载器 泛型 1 回顾泛型类 泛型类:具有一个或多个泛型变量的类被称之为泛型类. public class A<T> { ...
- 从静态代理,jdk动态代理到cglib动态代理-一文搞懂代理模式
从代理模式到动态代理 代理模式是一种理论上非常简单,但是各种地方的实现往往却非常复杂.本文将从代理模式的基本概念出发,探讨代理模式在java领域的应用与实现.读完本文你将get到以下几点: 为什么需要 ...
- Java动态代理全面分析
代理模式 解说:给某一个对象提供一个代理,并由代理对象控制对原对象的引用: 代理模式需要以下几个角色: 1 主题:规定代理类和真实对象共同对外暴露的接口: 2 代理类:专门代理真实对象的类: 3 ...
- [原创]java WEB学习笔记104:Spring学习---AOP 前奏,通过一个问题引入动态代理
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Java动态代理与Cglib库
JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...
随机推荐
- Linux下python安装升级详细步骤 | Python2 升级 Python3
Linux下python升级步骤 Python2 ->Python3 多数情况下,系统自动的Python版本是2.x 或者yum直接安装的也是2.x 但是,现在多数情况下建议使用3.x 那么如 ...
- SVN安装使用小结
SVN在实际的项目开发中有很广泛的用途.一开始接触SVN(Subversion),思路并不清楚,现在总算理清了. 声明:本文并不是系统地对SVN做介绍,而是笔者的使用总结,个人认为的一些要点,可能对初 ...
- Zookeeper 服务注册和发现
Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置项的管理 ...
- java编写冒泡排序
int[] arry={7,1,6,5,3,4,9,8,2}; for(int a=0;a<arry.length;a++) { for(int b=a+1;b<arry.length;b ...
- 海量IT资料 + 各种平台下的Oracle安装文件 + 公开课录像 + 各种视频教程资料
觉得老师的公开课讲的都挺好的,这里把我录的一些公开课视频分享给大家,都用的是<屏幕录像专家>来录制的,是lxe格式的,大家用这个软件来播放就可以了,后边的公开课录像文件也会慢慢添加进去的, ...
- MySQL入门(四)
我好久没有写这个系列了,也确实不知道写什么.回首我学习数据库的路,最开始搞Oracle的时候其实没有搞懂Oracle,也不知道学了什么,后来学习MySQL尤其是InnoDB才大概入了门了.我最开始学习 ...
- sql server 2005导出数据到oracle
一. 在sql server下处理需要导出的数据库 1. 执行以下sql,查出所有'float'类型的字段名,手动将float类型改为decimal(18,4). select 表名=d.name,字 ...
- 二:shell之bash变量
1.变量的分类: 用户自定义变量: 变量自定义 默认存储是字符串环境变量: 这种变量中主要保存的是和系统操作环境相关的数据.变量可以自定义,但是对系统生效的环境变量名和变 ...
- 关于mapreduce.map.java.opts
a) Update the property in relevant mapred-site.xml(from where client load the config). b) Import t ...
- 开发Eclipse自定义控件
摘自:http://www.ibm.com/developerworks/cn/opensource/os-eclipcntl/ 我们在开发自定义控件时主要考虑以下问题: 1. 自定义控件的绘制:通常 ...