Soap Extension 来记录日志
SoapExtension is not logginghttp://forums.asp.net/t/1165658.aspx/1====================================? Soap扩展调用顺序原理分析 最近学习了一下WebService的Soap扩展开发,在学习时我发现最大的问题是不同优先级的SoapExtension的调用顺序以及chainStream方法的用途,我们知道SoapMessage具有一个Stream属性,那么为什么我们不能在SoapExtension的ProcessMessage中直接操作这个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就无法通过,因为其为空。看了下面我的解释可能您能找到答案。 继续之前请首先记住如下几个结论: 1、SOAP扩展是在SoapMessage (SoapClientMessage和SoapServerMessage类型)传输过程中对其SOAP消息处理过程的拦截器,其可以在SoapMessage的四个阶段进行拦截并且插入代码,这四个阶段分别是BeforeSerialize"AfterSerialize"BeforeDeserialize和AfterDeserialize。 2、?在整个WebService访问过程中,ChainStream一共执行四次,在客户端执行两次,在服务器端执行两次。ChainStream的调用是按照Soap扩展的高优先级到低优先级的调用顺序依次调用的。 3、?每次SoapMessage的Stage状态发生改变时都会调用SoapExtension的ProcessMessage。所以这个函数一共执行8次。其中需要特别注意的是,不同优先级的Soap扩展在Soap消息传输的不同阶段其调用顺序是不一样的,具体可以分为两个阶段:即Serialize阶段,其调用是按照Soap扩展的优先级从低到高执行的,在Deserialize阶段,其调用是按照Soap扩展优先级从高到低执行的。 从下面这段代码我们就可以看出ProcessMessage调用顺序: internalvoidRunExtensions(SoapExtension[] extensions,bool throwOnException) {?? // extensions已经按照优先级由高到底排好序 ??? if (extensions != null) ??? {??? ??????? 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的四个阶段状态,其执行chainStream和SoapExtension执行顺序和1完全一样,只不过在第一步中传输的是SoapClientMessage,而第二步中传输的是SoapServerMessage。 6、我们知道SoapExtension的Priority属性为0,其优先级越高,如果我们现在有两个SoapExtension,分别是CompressExtension(用于压缩和解压缩)和CryptoExtension(用于加密和解密),我们现在希望其执行顺序是这样的,在客户端发出请求时,首先压缩然后加密(这样可能获得较高性能)。我们知道在客户端发出请求时ProcessMessage的执行是先从低优先级执行的,所以我们将CryptoExtension的优先级设置为高于CompressExtension的优先级即可。 我们来看一下客户端通过WebService代理发出请求的具体执行流程。 1.?????客户端创建代理实例,进行必要初始化,如设置SoapHeader; 2.?????客户端通过代理实例调用Web方法; 3.?????代理实例调用基类SoapHttpClientProtocol的Invoke方法,将Web方法作为字符串传递进去; 4.?????SoapHttpClientProtocol 根据Url获取WebRequest; 5.?????SoapHttpClientProtocol 根据本地代理配置文件或者特性利用反射生成本地?SoapReflectedExtension对象,并且对其进行排序,该对象即SoapExtension的反射形式类,其主要作用是动态生成SoapExtension对象,并且调用其GetInitializer(第一次调用)和Initialize方法,主要是为了满足性能需求; 6.?????创建SoapClientMessage实例,并且设置其Stream和SoapExtensionStream为一个空的SoapExtensionStream的实例; 7.?????按照优先级顺序调用SoapExtension的ChainStream方法;并且将第六步的SoapExtensionStream传递进去;并将ChainStream的返回值设置为SoapMessage的Stream属性。这样最低优先级的SoapExtension的ChainStream返回值和SoapMessage的Message属性为同一个对象; 8.?????设置SoapMessage的Stage为BeforeSerialize,按照由低到高的优先级顺序调用SoapExtension的ProcessMessage方法; 9.?????设置Soap标头信息; 10.?获取WebRequest的RequestStream对象,如果当前SoapExtensionStream不为空则将该Stream绑定给SoapExtensionStream的InnerStream对象,这样就使得最高优先级的SoapExtension可以引用该Stream.否则直接将SoapMessage的Stream设置为RequestStream。 11.?序列化Soap调用的参数,并且将其写入SoapMessage的Stream属性中。 12.?设置SoapMessage的Stage为AfterSerialize,按照由低到高的优先级顺序调用SoapExtension的ProcessMessage方法;这里需要特别留意:由于在第7步中的最低优先级SoapExtension的Stream已经被第11步写入数据,所以在该步中第一个调用的SoapExtension的_newStream(_workStream)就具有了原始SOAP的消息流。 这就是我们在扩展SoapExtension时为啥在调用AfterSerialize之后_newStream中具有数据的原因。 13.?在SoapExtension扩展时的BeforeDeserialize阶段,由于ChainStream和ProcessMessage都是按照由高到低的顺序执行的,所以我们可以知道最接近网络的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 类(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |