无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(二)
上一篇文章 "无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)"中,我们实现了监视每个页面的执行情况和调用WebService的简单信息。
这次我们继续深入一下SoapExtension的应用,在不改变Soap的WSDL文档的情况下,配合在Dotnet编写的WebService站点配置我们编写的SoapExtension,来穿透传输我们自定义的数据对象。由于SoapExtension是全局的,我们还要加一些标识来区分服务器是否已经配置了我们的SoapExtension,从而不影响其它的WebService调用。
在SoapExtension中,我想到有两种方案:
一种是直接在SoapMessage.Headers中插入自定义的SoapHeader对象,然后在客户端的序列化后,从SoapUnknownHeader中取出数据,然后反序列化成自定义的对象。
第二种是对SoapMessage.ContentType 添加一个额外的标识,在另一方检测这个标识,来从流中取出自己长度的数据。反序列化成自定义的对象。
我感觉第二种方案比较简单,高效,我们看一下代码:
/// <summary>
/// WSInvokeMonitorExtension 的摘要说明。
/// </summary>
public class StreamWSInvokeMonitorExtension : SoapExtension
{
private const string WSInvokeMonitorKey = "__WSInvokeMonitorKey__";
private const int MaxDataLength = 5 * 1024 * 1024; //5M
private XmlSerializer serializer = new XmlSerializer(typeof(DbConnInfo));
private Stream originStream;
private Stream usingStream = new MemoryStream();
private WSInvokeInfo invokeInfo = new WSInvokeInfo();
public override System.IO.Stream ChainStream(System.IO.Stream stream)
{
originStream = stream;
return usingStream;
} public override object GetInitializer(Type serviceType)
{
return null;
} public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return null;
} public override void Initialize(object initializer)
{ } public override void ProcessMessage(SoapMessage message)
{
if(message is SoapClientMessage)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
this.invokeInfo.BeginInvokeTime = DateTime.Now;
this.invokeInfo.MethodName = message.MethodInfo.Name;
break; case SoapMessageStage.AfterSerialize:
usingStream.Seek(0, SeekOrigin.Begin);
CopyStream(usingStream, originStream);
break; case SoapMessageStage.BeforeDeserialize:
usingStream.SetLength(0);
CopyStream(originStream, usingStream);
usingStream.Seek(0, SeekOrigin.Begin);
if(message.ContentType.IndexOf("ExtInfo=true") != -1){
//先读出自己的信息
byte[] bytesFlags = new byte[]{66,69}; // BE 标识 if(usingStream.ReadByte() == bytesFlags[0]) //检验标志位
{
byte[] bytesLength = new byte[BitConverter.GetBytes((Int32)0).Length];
usingStream.Read(bytesLength,0, bytesLength.Length); //读取长度
int length = BitConverter.ToInt32(bytesLength,0); if(length < MaxDataLength) //检验数据是否非法
{
if(usingStream.ReadByte() == bytesFlags[1]) //检验标志位
{
byte[] bytesData = new byte[length];
usingStream.Read(bytesData,0, bytesData.Length);
using(MemoryStream ms = new MemoryStream(bytesData))
{
DbConnInfo header = serializer.Deserialize(ms) as DbConnInfo;
Debug.WriteLine(header.Info);
} break;
} } } //数据不对,则重置流位置
usingStream.Position = 0;
} break; // About to call methods
case SoapMessageStage.AfterDeserialize:
//添加到Module记录
this.invokeInfo.EndInvokeTime = DateTime.Now;
PageInfo pageInfo = (PageInfo)HttpContext.Current.Items[WSInvokeMonitorKey] ;
if(pageInfo != null)
{
pageInfo.AppendInvokeInfo(this.invokeInfo);
} break; // After Method call default:
throw new Exception("No stage such as this");
} }
else if(message is SoapServerMessage)
{
switch (message.Stage)
{
// Incoming from client
case SoapMessageStage.BeforeDeserialize:
usingStream.SetLength(0);
CopyStream(originStream, usingStream);
usingStream.Seek(0, SeekOrigin.Begin); break; // About to call methods
case SoapMessageStage.AfterDeserialize:
break; // After Method call
case SoapMessageStage.BeforeSerialize:
//设置自定义Header
usingStream.SetLength(0); //清空并先写入自定义的信息
byte[] bytesData = null;
using(MemoryStream ms = new MemoryStream())
{
serializer.Serialize(ms,new DbConnInfo("3个数据库连接")); //服务端自定义的信息
bytesData = ms.ToArray();
}
message.ContentType += ";ExtInfo=true";
//写入标识
byte[] bytesFlags = new byte[]{66,69}; // BE
usingStream.WriteByte(bytesFlags[0]); //写入长度
byte[] dataLength = BitConverter.GetBytes(bytesData.Length);
usingStream.Write(dataLength, 0, dataLength.Length); //再写入标志
usingStream.WriteByte(bytesFlags[1]); //写入数据
usingStream.Write(bytesData, 0, bytesData.Length);
break; // Outgoing to other
case SoapMessageStage.AfterSerialize:
usingStream.Seek(0, SeekOrigin.Begin);
CopyStream(usingStream, originStream);
break; default:
throw new Exception("No stage such as this");
} }
} private void CopyStream(Stream src, Stream des)
{
byte[] buf = new byte[1024];
int length = 0;
do
{
length = src.Read(buf,0,buf.Length);
des.Write(buf,0,length);
} while (length == buf.Length); }
} [System.Serializable]
public class DbConnInfo
{
private string info;
public string Info
{
get { return info; }
set { info = value; }
} public DbConnInfo()
{
} public DbConnInfo(string info)
{
this.Info = info;
}
}
代码中,在服务端写入标识: message.ContentType += ";ExtInfo=true";
然后在客户端检测:if(message.ContentType.IndexOf("ExtInfo=true") != -1){...}
这样便保证了不会影响其它没有加载Soap扩展的调用。
到目前为至,我们已经成功的把服务端的信息对象,在不改变WSDL的情况下,无侵入的传递到调用端。具体收集什么信息,就要在WebService端进行收集了!我这里的要求是收集数据库连接的情况,下一次继续介绍吧。
附:方案一实现代码:
[System.Serializable]
public class DbConnInfoSoapHeader
{
private string info;
public string Info
{
get { return info; }
set { info = value; }
} public DbConnInfoSoapHeader()
{ } public DbConnInfoSoapHeader(string info)
{
this.Info = info;
}
} [System.Serializable]
public class SoapHeaderWrap : SoapHeader
{
private byte[] soapData = null;
private object data; [XmlIgnoreAttribute]
[SoapIgnoreAttribute]
public object Data
{
get { return data; }
set
{
data = value;
soapData = null;
}
}
private string key;
[XmlAttribute]
public string Key
{
get { return key; }
set { key = value; }
} [XmlAttribute]
public string TypeName
{
get{ return this.Data.GetType().AssemblyQualifiedName;
}
set{}
} public byte[] SoapData
{
get
{
if(soapData == null && this.Data != null)
{
using(MemoryStream ms = new MemoryStream())
using(StreamWriter sw = new StreamWriter(ms,new UTF8Encoding(false)))
{
XmlSerializer serializer = new XmlSerializer(this.Data.GetType());
serializer.Serialize(sw, this.Data);
ms.Position = 0;
soapData = ms.ToArray();
} } return soapData;
}
set { }
} public SoapHeaderWrap(string key, object soapData)
{
this.Key = key;
this.Data = soapData;
} public SoapHeaderWrap(string key)
:this(key,null)
{
} public SoapHeaderWrap()
:this(string.Empty)
{
} }
http://www.cnblogs.com/evlon/archive/2009/06/01/1493923.html
无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(二)的更多相关文章
- 无侵入方面编程-用HttpModule+SoapExtension监视页面执行参数(一)
先简单介绍一下项目吧,我们这个项目是用VS2003开发的,老早一个项目.WEB前端机+业务处理(WebService层)+数据库分别布置在不同的计算机上. 现在老总有一个需求,要统计出每个页面的执行时 ...
- Android平台免Root无侵入AOP框架Dexposed使用详解
Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架. Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者 ...
- Android免Root无侵入AOP框架Dexposed
Dexposed框架是阿里巴巴无线事业部近期开源的一款在Android平台下的免Root无侵入运行期AOP框架,该框架基于AOP思想,支持经典的AOP使用场景,可应用于日志记录,性能统计,安全控制,事 ...
- Dexposed:android免Root无侵入Aop框架
在网上看到了阿里推出的一个android开源项目,名为Dexposed, 是一个Android平台下的无侵入运行期AOP框架.旨在解决像性能监控.在线热补丁等移动开发常见难题,典型使用场景为: AOP ...
- 无插件Vim编程技巧
无插件Vim编程技巧 http://bbs.byr.cn/#!article/buptAUTA/59钻风 2014-03-24 09:43:46 发表于:vim 相信大家看过<简明Vim教程& ...
- 单点登录CAS使用记(八):使用maven的overlay实现无侵入的改造CAS
前期在学习CAS部署的过程中,都是网上各种教程,各种方案不停的尝试. 期间各种侵入改源码,时间久了,改了哪个文件,改了哪段配置,增加了哪段代码,都有可能混淆不清了. 而且最大的问题是,万一换个人来维护 ...
- 发布时去掉 debug 和 提醒日志,简单无侵入
在 proguard 文件中加入下面代码,让发布时去掉 debug 和 提醒日志,简单无侵入! -assumenosideeffects class android.util.Log { public ...
- 无插件VIM编程技巧(网摘)
无插件VIM编程技巧 原文出处:[陈皓 coolshell] 相信大家看过<简明Vim教程>也玩了<Vim大冒险>的游戏了,相信大家对Vim都有一个好的入门了.我在这里把我日常 ...
- Hook 无侵入式埋点(页面统计)
一.技术原理 Method-Swizzling 黑魔法 方法交换(不懂的可以查) 二.页面统计 某盟页面统计SDK需要开发者在APP基类里实现ViewDidAppear和viewDidDisappea ...
随机推荐
- unity3d中切换武器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...
- XML 命名空间(XML Namespaces)
XML 应用程序 XML CDATA XML 命名空间提供避免元素命名冲突的方法. 命名冲突 在 XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突. 这个 X ...
- HTML,XML中的转义字符
HTML中的转义字符 HTML中<, >,&等有特别含义,(前两个字符用于链接签,&用于转义),不能直接使用.使用这三个字符时,应使用他们的转义序列,如下所示: & ...
- Oracle数据库—— 事务处理与并发控制
一.涉及内容 1.理解事务的概念和几个特性. 2.熟练掌握事务管理命令的使用. 3.理解并发操作的概念和数据库锁的类型. 二.具体操作 (12.5 实验) 1. 分析以下代码,说出代码中的哪些部分体现 ...
- php 同步因子的并发处理
在php中,如果处理支付时,会涉及到并发. 具体体现在同步通知支付结果和异步通知结果. 拿支付宝来说,同步通知call_back和异步通知notify是没有固定先后顺序的. 有可能notify先通知到 ...
- nginx path_info问题解决
问题: 访问www.xxxx.com/index.php/api/xxxxxxxxx网址时,提示无法访问,找不到页面 解决: 第一次,是改了nginx.conf,不会报这个错误了,但还是没有用 loc ...
- oracle自动备份
因为一个项目上马,需要设置自动备份,网上搜索了一下,windows平台下基本上是通过系统的任务计划完成的,于是我也写了一下,无非就是exp xxxx.dmp,文件名是用的日期加时间,精确到秒,一小时备 ...
- 利用百度地图API,获取经纬度坐标
利用百度地图API,获取经纬度坐标 代码很简单,但在网上没找到现成的获取地图经纬度的页面. 就是想,给当前页面传递一个经纬度,自动定位到此经纬度.然后可以重新选择,选择完返回经纬度. 效果如下: 源代 ...
- activiti自定义流程之整合(四):整合自定义表单部署流程定义
综合前几篇博文内容,我想在整合这一部分中应该会有很多模块会跳过不讲,就如自定义表单的表单列表那一块,因为这些模块在整合的过程中都几乎没有什么改动,再多讲也是重复无用功. 正因为如此,在创建了流程模型之 ...
- 单源最短路径——Floyd算法
正如我们所知道的,Floyd算法用于求最短路径.Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3). Floyd算法的基本思想如下:从任意 ...