问题描述
我有这个问题的最后一天。我创建了以下MSDN文章和博客文章的负载的SOAP扩展,但我不能得到它的工作。好了一些code:
I have had this problem for the last day. I have created a SOAP Extension following the MSDN articles and a load of blog posts but I just can't get it to work. Ok Some code:
public class EncryptionExtension : SoapExtension
{
Stream _stream;
public override object GetInitializer(Type serviceType)
{
return typeof(EncryptionExtension);
}
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return attribute;
}
public override void Initialize(object initializer)
{
}
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
break;
case SoapMessageStage.BeforeDeserialize:
break;
case SoapMessageStage.AfterDeserialize:
break;
default:
throw new Exception("invalid stage");
}
}
public override Stream ChainStream(Stream stream)
{
_stream = stream;
return stream;
}
}
还有一个属性类:
There is also an attribute class:
[AttributeUsage(AttributeTargets.Method)]
public class EncryptionExtensionAttribute : SoapExtensionAttribute
{
public override Type ExtensionType
{
get { return typeof(EncryptionExtension); }
}
public override int Priority
{
get;
set;
}
}
所以,当消息进来,我可以看到入站SOAP请求时,我在BeforeDeserialization和AfterDeserialization,这是伟大的调试。然后我的web服务方法被调用。这简直是:
So when the message comes in I can see the inbound SOAP request when I debug at the BeforeDeserialization and AfterDeserialization, which is great. My web service method is then called. Which is simply:
[WebMethod()]
[EncryptionExtension]
public string HelloWorld()
{
return "Hello world";
}
然后过程跳回到我的SoapExtension。在BeforeSerialization和AfterSerialization把破发点,我看到,出站流包含什么。我并不感到惊讶,这是对BeforeSerialization空,但我觉得很奇怪,这是在AfterSerialization空。因为我需要出站流保持这样我就可以对它进行加密这就产生了一个问题。
The process then hops back into my SoapExtension. Putting break points at BeforeSerialization and AfterSerialization I see that the outbound stream contains nothing. I am not surprised that it is empty on the BeforeSerialization but i am surprised that it is empty at AfterSerialization. This creates a problem because I need to get hold of the outbound stream so I can encrypt it.
有人能告诉我为什么出站流是空的?我跟了这MSDN文章,其中indiciates它不应该是。
我缺少一些配置或别的东西吗?
Can someone tell me why the outbound stream is empty? I have followed this MSDN article which indiciates it shouldn't be http://msdn.microsoft.com/en-us/library/ms972410.aspx.Am I missing some configuration or something else?
推荐答案
我发现的的SoapExtension MSDN(谷歌搜索排名靠前也发现有例如code中的文档作为最高命中当中这个问题),所以这里有其他任何人试图使有时混淆或矛盾的文档的意义上编码的SOAP扩展了一些有益的建议。
I found this question among the top hits for a google search on "SoapExtension MSDN" (which also finds the doc with example code as the top hit), so here are some helpful suggestions to anyone else trying to make sense of the sometimes confusing or contradictory docs on coding Soap extensions.
如果您正在修改的序列化消息(流),你需要创建并从ChainStream覆盖返回不同的流。否则,你是说,你的扩展不会修改流,只是让它通过。该示例使用一个MemoryStream,这可能是你,因为怪异的设计用什么:当ChainStream叫你不知道你是否正在发送或接收,所以你必须要ppared来处理它无论哪种方式$ P $ 。我想,即使你只在一个方向处理它你仍然必须处理其他方向,并从一个流中的数据复制到另一个反正因为你插入自己在链不知道它是哪个方向。
If you are modifying the serialized message (as a stream) you need to create and return a different stream from the ChainStream override. Otherwise, you're saying that your extension doesn't modify the stream and just lets it pass through. The example uses a MemoryStream, and that's probably what you have to use because of the weird design: When ChainStream is called you don't know if you are sending or receiving, so you have to be prepared to handle it either way. I think even if you only process it in one direction you still have to handle the other direction and copy the data from one stream to the other anyway because you are inserting yourself in the chain without knowing which way it is.
private Stream _transportStream; // The stream closer to the network transport.
private MemoryStream _accessStream; // The stream closer to the message access.
public override Stream ChainStream(Stream stream)
{
// You have to save these streams for later.
_transportStream = stream;
_accessStream = new MemoryStream();
return _accessStream;
}
然后,你必须处理AfterSerialize和BeforeDeserialize案件ProcessMessage的。我让他们打电话ProcessTransmitStream(消息)和ProcessReceivedStream(消息)分别以帮助保持流程清晰。
Then you have to handle the AfterSerialize and BeforeDeserialize cases in ProcessMessage. I have them calling ProcessTransmitStream(message) and ProcessReceivedStream(message) respectively to help keep the process clear.
ProcessTransmitStream需要从_accessStream其输入(后第一次复位此的MemoryStream的当前位置为0),其输出写到_transportStream - 这可能允许非常有限的访问(无觅,等等),所以我第一次建议处理到本地MemoryStream的缓冲区,然后将其复制到_transportStream(其当前位置重置为0后)。 (或者,如果你处理它变成一个字节数组或字符串你只需要从直接写入到_transportStream。我用例是COM pression / DECOM pression所以我对处理这一切的流失之偏颇。 )
ProcessTransmitStream takes its input from _accessStream (after first resetting the Postion of this MemoryStream to 0) and writes its output to _transportStream--which may allow very limited access (no seek, etc), so I suggest processing first into a local MemoryStream buffer and then copying that (after resetting its Postion to 0) into the _transportStream. (Or if you process it into a byte array or string you can just write from that directly into the _transportStream. My use case was compression/decompression so I'm biased towards handling it all as streams.)
ProcessReceivedStream需要从_transportStream其输入和输出写入_accessStream。在这种情况下,你可能应该先_transportStream复制到本地缓存的MemoryStream(然后重置缓冲区的位置为0),它可以访问更方便。 (或者你可以读取整个_transportStream直接成字节数组或其他形式,如果这就是你需要它。)请确保您在返回前重置_accessStream.Position = 0,所以它是准备在链的下一个环节从中读出。
ProcessReceivedStream takes its input from _transportStream and writes its output to _accessStream. In this case you should probably first copy the _transportStream into a local MemoryStream buffer (and then reset the buffer's Position to 0) which you can access more conveniently. (Or you can just read the entire _transportStream directly into a byte array or other form if that's how you need it.) Make sure you reset the _accessStream.Position = 0 before returning so that it is ready for the next link in the chain to read from it.
这对改变序列化流。如果你不改变数据流,那么你不应该覆盖ChainStream(从而分机出流处理链的)。相反,你会做的BeforeSerialize和/或AfterDeserialize阶段的处理。在这些阶段,你不修改或访问流,但消息对象上,而不是工作本身,如在BeforeSerialize阶段添加自定义SOAPHEADER到message.Headers集合。
That's for changing the serialized stream. If you aren't changing the stream then you should not override ChainStream (thus taking your extension out of the chain of stream processing). Instead you would do your processing in the BeforeSerialize and/or AfterDeserialize stages. In those stages you don't modify or access the streams but instead work on the message object itself such as adding a custom SoapHeader to the message.Headers collection in the BeforeSerialize stage.
本的SOAPMessage类本身是抽象的,所以你真正得到要么是SoapClientMessage或SoapServerMessage。该文件说你在服务器端对客户端上SoapClientMessage和SoapServerMessage(在调试试验应能证实或纠正这一点)。他们似乎在你可以访问哪些方面类似pretty,但你必须转换为正确的正常访问;使用了错误的人会失败,并宣布为参数的ProcessMessage基本的SOAPMessage类型不给你访问任何东西。
The SoapMessage class itself is abstract, so what you really get is either a SoapClientMessage or a SoapServerMessage. The docs say you get a SoapClientMessage on the client side and a SoapServerMessage on the server side (experimenting in the debugger should be able to confirm or correct that). They seem pretty similar in terms of what you can access, but you have to cast to the right one to access it properly; using the wrong one would fail, and the base SoapMessage type declared for the parameter to ProcessMessage doesn't give you access to everything.
我还没有属性的东西看,但(这不会是什么,我的编码的一部分),所以我不能用怎么用这部分帮助。
I haven't looked at the attribute stuff yet (it won't be a part of what I'm coding), so I can't help with how to use that part.
这篇关于SOAP扩展流空序列化后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!