Ich versuche, ein Buch zu schreiben. Fehlersuchwerkzeug die es dem Benutzer ermöglicht, das neue binäre XML-Format von WCF (application/soap +msbin1) in Klartext anzuzeigen. Sobald ich die XmlDictionaryReader Klasse Ich dachte, ich wäre in wenigen Minuten fertig, aber es funktioniert nicht wie erwartet.
private string DecodeBinaryXML(byte[] binaryBuffer)
{
if (binaryBuffer == null)
{
return "";
}
try
{
var doc = new XmlDocument();
using (var binaryReader = XmlDictionaryReader.CreateBinaryReader(binaryBuffer, XmlDictionaryReaderQuotas.Max))
{
doc.Load(binaryReader);
binaryReader.Close();
}
var textBuffer = new StringBuilder();
var settings = new XmlWriterSettings()
{
// lots of code not relevant to the question
};
using (var writer = XmlWriter.Create(textBuffer, settings))
{
doc.Save(writer);
writer.Close();
}
return textBuffer.ToString();
}
catch (Exception ex)
{
// just display errors in the text viewer
return ex.ToString();
}
}
Jedes einzelne "soap+msbin1"-Beispiel, das ich online gefunden oder selbst erstellt habe, löst eine Parse-Exception aus bei doc.Load() .
Um zu sehen, was los war, habe ich eine einfache Testanwendung erstellt und das Problem aus der anderen Richtung angegangen.
// client
static void Main(string[] args)
{
var binding = new CustomBinding(new TextMessageEncodingBindingElement(),
new HttpTransportBindingElement());
var proxy = ChannelFactory<IService1>.CreateChannel(binding,
new EndpointAddress("http://ipv4.fiddler:25381/Service1.svc"));
Console.WriteLine(proxy.Echo("asdf"));
}
// shared interface
[ServiceContract()]
public interface IService1
{
[OperationContract]
string Echo(string input);
}
// server
public class Service1 : IService1
{
public string Echo(string input)
{
return "WCF says hi to: " + input;
}
}
Die Ausführung löst eine http-Anfrage aus, die wie folgt aussieht:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IService1/Echo</a:Action>
<a:MessageID>urn:uuid:21a33e81-bfab-424f-a2e5-5116101a7319</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://ipv4.fiddler:25381/Service1.svc</a:To>
</s:Header>
<s:Body>
<Echo xmlns="http://tempuri.org/">
<input>asdf</input>
</Echo>
</s:Body>
</s:Envelope>
Ich habe dieses XML konvertiert in binär auf zwei verschiedene Arten. Erstens, mit XmlDictionaryWriter:
$fs = [system.io.file]::Create("c:\temp\soap.bin")
$writer = [system.xml.xmldictionarywriter]::CreateBinaryWriter($fs)
$xml = [xml] (gc C:\temp\soap.xml)
$xml.Save($writer)
$writer.Close(); $fs.Close()
Dann, mit WCF und demselben Netzwerk-Sniffer:
@@ -1,7 +1,7 @@
// client
static void Main(string[] args)
{
- var binding = new CustomBinding(new TextMessageEncodingBindingElement(),
+ var binding = new CustomBinding(new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement());
Methode Nr. 1 ergab 397 Byte binär aussehenden Datenmüll. Methode #2 zeigt 169 Bytes sehr unterschiedlichen binären Müll. Abgesehen von einigen Zeichenfolgen, die in beiden Ausgaben vorkommen, sehe ich keine große Ähnlichkeit zwischen den beiden Kodierungen. Kein Wunder also, dass XmlDictionaryReader die Ausgabe eines WCF-Dienstes nicht verstehen kann!
Gibt es ein Geheimnis für die Entschlüsselung dieses Formats, oder bin ich auf dem völlig falschen Weg?