无侵入方面编程-用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 ...
随机推荐
- 【转】Python numpy库的nonzero函数用法
当使用布尔数组直接作为下标对象或者元组下标对象中有布尔数组时,都相当于用nonzero()将布尔数组转换成一组整数数组,然后使用整数数组进行下标运算. nonzeros(a) 返回数组a中值不为零的元 ...
- ABBYY FineReader 12扫描界面介绍
ABBYY FineReader 12OCR图文识别软件自身拥有着自己的扫描界面,一般在默认情况下,ABBYY FineReader 使用其自身的扫描界面.本文就解析了ABBYY FineReader ...
- OpenJudge计算概论-配对碱基链
/*===================================== 配对碱基链 总时间限制: 1000ms 内存限制: 65536kB 描述 脱氧核糖核酸(DNA)由两条互补的碱基链以双螺 ...
- Android App监听软键盘按键的三种方式
前言: 我们在android手机上面有时候会遇到监听手机软键盘按键的时候,例如:我们在浏览器输入url完毕后可以点击软键盘右下角的“GO”按键加载url页面:在点击搜索框的时候,点击右下角的sea ...
- MySQLAdmin用法
MySQLAdmin用法用于执行管理性操作.语法是:shell> mysqladmin [OPTIONS] command [command-option] command ...通过执行mys ...
- PHP 动态执行
PHP 动态执行 在页面上直接输入代码,点击执行,返回执行结果 方法很简单,主要使用了 $newfunc = create_function('', $code); 函数来实现. 代码如下: < ...
- VS2013 启动时遇到空白窗口
安装了VS2013 ,然后打开,遇到空白窗口,等了10几秒无果. 我先是修复了VS2013,然后再打开VS2013,则显示登录微软账号的窗口.修复完2013时正好18:08,可能是下班了可以上网,才正 ...
- LintCode "Partition Array by Odd and Even"
One pass in-place solution: all swaps. class Solution { public: /** * @param nums: a vector of integ ...
- Python控制流语句(if,while,for)
if.py number=23 guess=int(input("enter an int:")) if guess==number: print ("congratul ...
- IIS SMTP Queue stuck
1. review smtp logs in C:\Windows\System32\LogFiles\SMTPSVC1, 2. find 421 error 2014-12-08 02:02:40 ...