加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Soap Extension 来记录日志

发布时间:2020-12-17 00:34:36 所属栏目:安全 来源:网络整理
导读:SoapExtension is not logging http://forums.asp.net/t/1165658.aspx/1 ==================================== ? Soap 扩展调用顺序原理分析 最近学习了一下 WebService 的 Soap 扩展开发,在学习时我发现最大的问题是不同优先级的 SoapExtension 的调用顺

SoapExtension is not logging

http://forums.asp.net/t/1165658.aspx/1

====================================

?

Soap扩展调用顺序原理分析

最近学习了一下WebServiceSoap扩展开发,在学习时我发现最大的问题是不同优先级的SoapExtension的调用顺序以及chainStream方法的用途,我们知道SoapMessage具有一个Stream属性,那么为什么我们不能在SoapExtensionProcessMessage中直接操作这个Stream呢,例如你的代码可能会是这个样子:

publicoverridevoidProcessMessage(SoapMessagemessage)

??????? {

???????????switch (message.Stage)

??????????? {

???????????????//序列化之后压缩这个流

???????????????caseSoapMessageStage.AfterSerialize:

???????????????????message.Stream =CompressStream(message.Stream);

???????????????????break;

?

???????????????//反序列化之前解压缩这个流

???????????????caseSoapMessageStage.BeforeDeserialize:

???????????????????message.Stream =DeCompressStream(message.Stream);

???????????????????break;

???????????????default:

???????????????????break;

??????????? }

??????? }

???????///<summary>

???????///压缩输入流,返回压缩后的新流。

???????///</summary>

???????///<param name="inputStream">输入流,该流将被压缩</param>

???????///<returns>返回压缩后的新流。</returns>

???????privateStreamCompressStream(StreaminputStream)

??????? {

???????????//simulate code here

???????????returnnewMemoryStream();

??????? }

???????///<summary>

???????///解压缩输入流,返回解压后的新流。

???????///</summary>

???????///<param name="compressedStream">被压缩的输入流</param>

???????///<returns>返回解压后的新流。</returns>

???????privateStreamDeCompressStream(StreamcompressedStream)

??????? {

???????????//simulate code here

???????????returnnewMemoryStream();

??????? }

我非常希望这段代码能够正确执行,但是在WebService调用时,在第一个CompressStream就无法通过,因为其为空。看了下面我的解释可能您能找到答案。

继续之前请首先记住如下几个结论:

1SOAP扩展是在SoapMessage (SoapClientMessageSoapServerMessage类型)传输过程中对其SOAP消息处理过程的拦截器,其可以在SoapMessage的四个阶段进行拦截并且插入代码,这四个阶段分别是BeforeSerialize"AfterSerialize"BeforeDeserializeAfterDeserialize

2、?在整个WebService访问过程中,ChainStream一共执行四次,在客户端执行两次,在服务器端执行两次。ChainStream的调用是按照Soap扩展的高优先级到低优先级的调用顺序依次调用的。

3、?每次SoapMessageStage状态发生改变时都会调用SoapExtensionProcessMessage。所以这个函数一共执行8次。其中需要特别注意的是,不同优先级的Soap扩展在Soap消息传输的不同阶段其调用顺序是不一样的,具体可以分为两个阶段:即Serialize阶段,其调用是按照Soap扩展的优先级从低到高执行的,在Deserialize阶段,其调用是按照Soap扩展优先级从高到低执行的。

从下面这段代码我们就可以看出ProcessMessage调用顺序:

internalvoidRunExtensions(SoapExtension[] extensions,bool throwOnException)

{??

// extensions已经按照优先级由高到底排好序

??? if (extensions != null)

??? {???
//BeforeDeSerialize或者AfterDeSerialize阶段按照由高到低的优先级顺序执行

??????? if ((this.stage & (SoapMessageStage.AfterDeserialize | SoapMessageStage.BeforeDeserialize)) != ((SoapMessageStage)0))

??????? {

??????????? for (inti = 0; i < extensions.Length; i++)

??????????? {

??????????????? extensions[i].ProcessMessage(this);

???????????????if ((this.Exception != null) && throwOnException)

??????????????? {

???????????????????throw this.Exception;

??????????????? }

??????????? }

??????? }

??????? else

??????? {???

???????????????????????????????? ?//BeforeSerialize或者AfterSerialize阶段按照由低到高的优先级顺序执行

??????????? for (intj = extensions.Length - 1; j >= 0; j--)

??????????? {

??????????????? extensions[j].ProcessMessage(this);

???????????????if ((this.Exception != null) && throwOnException)

??????????????? {

???????????????????throw this.Exception;

??????????????? }

??????????? }

??????? }

??? }

}

4、SoapExtension的优先级越高,其越接近网络,即其越接近网络传输层数据。

5、WebService调用过程基本可以分为两个阶段:1、从客户端发出请求到服务器端接受请求的过程刚好就是ProcessMessage执行的四个阶段,2、从服务器端发出响应到客户端接受响应其也是执行ProcessMessage的四个阶段状态,其执行chainStreamSoapExtension执行顺序和1完全一样,只不过在第一步中传输的是SoapClientMessage,而第二步中传输的是SoapServerMessage

6、我们知道SoapExtensionPriority属性为0,其优先级越高,如果我们现在有两个SoapExtension,分别是CompressExtension(用于压缩和解压缩)CryptoExtension(用于加密和解密),我们现在希望其执行顺序是这样的,在客户端发出请求时,首先压缩然后加密(这样可能获得较高性能)。我们知道在客户端发出请求时ProcessMessage的执行是先从低优先级执行的,所以我们将CryptoExtension的优先级设置为高于CompressExtension的优先级即可。

我们来看一下客户端通过WebService代理发出请求的具体执行流程。

1.?????客户端创建代理实例,进行必要初始化,如设置SoapHeader;

2.?????客户端通过代理实例调用Web方法;

3.?????代理实例调用基类SoapHttpClientProtocolInvoke方法,将Web方法作为字符串传递进去;

4.?????SoapHttpClientProtocol 根据Url获取WebRequest

5.?????SoapHttpClientProtocol 根据本地代理配置文件或者特性利用反射生成本地?SoapReflectedExtension对象,并且对其进行排序,该对象即SoapExtension的反射形式类,其主要作用是动态生成SoapExtension对象,并且调用其GetInitializer(第一次调用)和Initialize方法,主要是为了满足性能需求;

6.?????创建SoapClientMessage实例,并且设置其StreamSoapExtensionStream为一个空的SoapExtensionStream的实例;

7.?????按照优先级顺序调用SoapExtensionChainStream方法;并且将第六步的SoapExtensionStream传递进去;并将ChainStream的返回值设置为SoapMessageStream属性。这样最低优先级的SoapExtensionChainStream返回值和SoapMessageMessage属性为同一个对象;

8.?????设置SoapMessageStageBeforeSerialize,按照由低到高的优先级顺序调用SoapExtensionProcessMessage方法;

9.?????设置Soap标头信息;

10.?获取WebRequestRequestStream对象,如果当前SoapExtensionStream不为空则将该Stream绑定给SoapExtensionStreamInnerStream对象,这样就使得最高优先级的SoapExtension可以引用该Stream.否则直接将SoapMessageStream设置为RequestStream

11.?序列化Soap调用的参数,并且将其写入SoapMessageStream属性中。

12.?设置SoapMessageStageAfterSerialize,按照由低到高的优先级顺序调用SoapExtensionProcessMessage方法;这里需要特别留意:由于在第7步中的最低优先级SoapExtensionStream已经被第11步写入数据,所以在该步中第一个调用的SoapExtension_newStream(_workStream)就具有了原始SOAP的消息流。

这就是我们在扩展SoapExtension时为啥在调用AfterSerialize之后_newStream中具有数据的原因。

13.?SoapExtension扩展时的BeforeDeserialize阶段,由于ChainStreamProcessMessage都是按照由高到低的顺序执行的,所以我们可以知道最接近网络的SoapExtension首先传入的是一个网络流(NetworkStream),所以我们在ChainStream中保存的_oldStream就是该网络流。

14.?在服务器端其执行步骤和客户端执行步骤基本完全一样,只不过在传输过程中是SoapServerMessage

这是一个MSDN的实例,请注意其中的注释语句。

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

usingSystem.IO;

usingSystem.Web;

usingSystem.Web.Services;

usingSystem.Web.Services.Protocols;

namespaceSoapExtensionLib

{

???///<summary>

???///跟踪soap请求和响应。

///</summary>

publicclassTraceExtension:SoapExtension

??? {

???????privateStream_newStream;//可以传给低扩展的流

???????privateStream_oldStream;//优先级高的扩展传递进来的流

???????privatestring_fileName;//日志文件路径

???????publicoverrideStreamChainStream(Streamstream)

??????? {

???????????_oldStream =stream;

???????????_newStream =newMemoryStream();

???????????return_newStream;

??????? }

???????publicoverridevoidProcessMessage(SoapMessagemessage)

??????? {

???????????switch (message.Stage)

??????????? {

???????????????caseSoapMessageStage.BeforeSerialize:

???????????????????break;

???????????????caseSoapMessageStage.AfterSerialize:

???????????????????WriteOutput(message);

???????????????????break;

???????????????caseSoapMessageStage.BeforeDeserialize:

???????????????????WriteInput(message);

???????????????????break;

???????????????caseSoapMessageStage.AfterDeserialize:

???????????????????break;

??????????? }

??????? }

???????privatevoidWriteOutput(SoapMessagemessage)

??????? {

???????????//这里是准备向网络传输的,即客户端发出请求和服务器端发出响应时发生的。

???????????//在这两个阶段ChainStream调用顺序和ProcessMessage相反,所以可以肯定_newStream

???????????//一定不为空,而_oldStream为空。

???????????_newStream.Position = 0;

???????????FileStreamfs =newFileStream(_fileName,FileMode.Append,FileAccess.Write);

???????????StreamWriterwriter =newStreamWriter(fs);

???????????writer.WriteLine("date time:" + DateTime.Now.ToString());

???????????writer.Flush();

???????????CopyStream(_newStream,fs);

???????????writer.Close();

???????????//这里非常重要,因为需要将低优先级低的扩展逐级向上复制给高优先级的扩展

???????????_newStream.Position = 0;

???????????CopyStream(_newStream,_oldStream);

??????? }

???????privatevoidWriteInput(SoapMessagemessage)

??????? {

???????????//这里是从网络传输进来的,即服务器端接受请求和客户端接受响应时发生的。

???????????//在这两个阶段ChainStream调用顺序和ProcessMessage相同,所以可以肯定_oldStream

???????????//一定不为空,而_newStream为空。

???????????CopyStream(_oldStream,_newStream);

???????????FileStreamfs =newFileStream(_fileName,FileAccess.Write);

???????????StreamWriterwriter =newStreamWriter(fs);

???????????writer.WriteLine("date time:" + DateTime.Now.ToString());

???????????writer.Flush();

???????????_newStream.Position = 0;

???????????CopyStream(_newStream,fs);

???????????writer.Close();

???????????_newStream.Position = 0;

??????? }

???????privatevoidCopyStream(Streamfrom,Streamto)

??????? {

???????????TextReaderreader =newStreamReader(from);

???????????TextWriterwriter =newStreamWriter(to);

???????????writer.WriteLine(reader.ReadToEnd());

???????????writer.Flush();

??????? }

???????publicoverrideobjectGetInitializer(TypeserviceType)

??????? {

???????????return"c:""" +serviceType.FullName +".log";

??????? }

???????publicoverrideobjectGetInitializer(LogicalMethodInfomethodInfo,SoapExtensionAttributeattribute)

??????? {

???????????return ((TraceExtensionAttribute)attribute).FileName;

??????? }

???????publicoverridevoidInitialize(objectinitializer)

??????? {

???????????_fileName = (string)initializer;

??????? }

??? }

}

我们以一个压缩SOAP消息的扩展为例结束本专题。

首先定义一个SoapExtension的扩展类CompressExtension

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

usingSystem.IO;

usingSystem.Web;

usingSystem.Web.Services;

usingSystem.Web.Services.Protocols;

usingICSharpCode.SharpZipLib.Core;

usingICSharpCode.SharpZipLib.Zip;

namespaceSoapExtensionLib

{

???///<summary>

???///提供压缩和解压缩的Soap扩展。

???///</summary>

???publicclassCompressExtension:SoapExtension

??? {

???????privateStream_workStream;

???????privateStream_oldStream;

???????privateint_compressLevel;

???????privatestaticreadonlyint_DEFAULTLEVEL=9;

???????publicoverrideStreamChainStream(Streamstream)

??????? {

???????????_oldStream =stream;

???????????_workStream =newMemoryStream();

???????????return_workStream;

??????? }

???????publicoverrideobjectGetInitializer(TypeserviceType)

??????? {

???????????return_DEFAULTLEVEL;

??????? }

???????publicoverrideobjectGetInitializer(LogicalMethodInfomethodInfo,SoapExtensionAttributeattribute)

??????? {

???????????return ((CompressExtensionAttribute)attribute).CompressLevel;

??????? }

???????publicoverridevoidInitialize(objectinitializer)

??????? {

???????????_compressLevel = (int)initializer;

??????? }

???????publicoverridevoidProcessMessage(SoapMessagemessage)

??????? {

???????????switch (message.Stage)

??????????? {

???????????????caseSoapMessageStage.AfterSerialize:

???????????????????CompressStream();

???????????????????break;

???????????????caseSoapMessageStage.BeforeDeserialize:

???????????????????DeCompressStream();

???????????????????break;

???????????????default:

???????????????????break;

??????????? }

??????? }

???????privatevoidCompressStream()

??????? {

???????????//利用zip算法将_workStream压缩到_oldStream中,

???????????//_oldStream将传递给高优先级的SoapExtension进行处理。

???????????_workStream.Position = 0;

???????????ZipOutputStreamzipStream =newZipOutputStream(_oldStream);

???????????zipStream.SetLevel(_compressLevel);

???????????byte[]buffer =newbyte[4096];

???????????ZipEntryentry =newZipEntry("compress");

???????????zipStream.PutNextEntry(entry);

???????????StreamUtils.Copy(_workStream,zipStream,buffer);

???????????zipStream.Finish();

??????? }

???????privatevoidDeCompressStream()

??????? {

???????????//利用zip算法将_oldStream解压缩到_workStream中。

???????????//_workStream将传输给低优先级的SoapExtension进行处理。

???????????ZipInputStreamzipStream =newZipInputStream(_oldStream);

???????????ZipEntrytheEntry =null;

???????????byte[]buffer =newbyte[4096];

???????????while ((theEntry = zipStream.GetNextEntry()) !=null)

??????????? {

???????????????intreadByt = 0;

???????????????do{

???????????????????readByt =zipStream.Read(buffer,buffer.Length);

???????????????????_workStream.Write(buffer,readByt);

??????????????? }

???????????????while (readByt > 0);

??????????? }

???????????_workStream.Position = 0;

??????? }

??? }

}

再定义一个特性:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

usingSystem.IO;

usingSystem.Web;

usingSystem.Web.Services;

usingSystem.Web.Services.Protocols;

namespaceSoapExtensionLib

{

??? [AttributeUsage(AttributeTargets.Method)]

???publicclassCompressExtensionAttribute:SoapExtensionAttribute

??? {

???????privateint_priority;

???????privateint_level;

???????publicCompressExtensionAttribute()

??????? {

???????????_level = 9;

???????????_priority = 0;

??????? }

???????publicoverrideTypeExtensionType

??????? {

???????????get {returntypeof(CompressExtension); }

??????? }

???????publicintCompressLevel

??????? {

???????????get {return_level; }

???????????set {_level =value; }

??????? }

???????publicoverrideintPriority

??????? {

???????????get

??????????? {

???????????????return_priority;

??????????? }

???????????set

??????????? {

???????????????_priority =value;

??????????? }

??????? }

??? }

}

下面是这个测试的WebService

usingSystem;

usingSystem.Web;

usingSystem.Web.Services;

usingSystem.Web.Services.Protocols;

usingSoapExtensionLib;

[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

publicclassService : System.Web.Services.WebService

{

???publicService () {

???????//如果使用设计的组件,请取消注释以下行

???????//InitializeComponent();

??? }

??? [WebMethod]

??? [SoapExtensionLib.CompressExtension(CompressLevel = 9)]

???publicstringHelloWorld() {

???????return"Hello World";

??? }

??? [WebMethod]

??? [SoapExtensionLib.CompressExtension(CompressLevel=9)]

???publicstringCaculateString()

??? {

???????return"Zhang xuebao";

??? }

}

?

=========================================

http://msdn.microsoft.com/zh-cn/library/system.web.services.protocols.soapextension(v=vs.80).aspx

SoapExtension 类

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读