Я пытаюсь написать инструмент отладки, который позволяет пользователю для просмотра нового двоичного формата XML WCF (application/soap +msbin1) в виде простого текста. Когда я нашел класс XmlDictionaryReader, я подумал: Я бы сделал в считанные минуты, но это не работает, как ожидалось.
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();
}
}
Каждый образец «soap+msbin1», который я нашел в Интернете или сгенерировал самостоятельно, вызывает исключение синтаксического анализа в doc.Load().
Чтобы увидеть, что происходит, я создал простое тестовое приложение и атаковал проблему с другой стороны.
// 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;
}
}
Запуск запускает http-запрос, который выглядит так:
<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>
Я преобразовал этот XML в двоичный файл двумя разными способами. Во-первых, используя 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()
Затем с помощью WCF и того же сетевого сниффера:
@@ -1,7 +1,7 @@
// client
static void Main(string[] args)
{
- var binding = new CustomBinding(new TextMessageEncodingBindingElement(),
+ var binding = new CustomBinding(new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement());
Метод № 1 дал 397 байт бинарного мусора. Метод №2 показывает 169 байт очень разного бинарного мусора. За исключением нескольких строк, которые появляются в обоих выходных данных, я не вижу большого сходства в этих двух кодировках. Неудивительно, что XmlDictionaryReader не может понять вывод службы WCF!
Есть ли какой-то секрет расшифровки этого формата, или я вообще на неверном пути?