0

(IDispatchMessageInspectorを介して)カスタムメッセージインスペクターを実装して、WCFサービスのサーバー側で受信したメッセージをインターセプトし、メッセージの逆シリアル化と特定のビジネスロジックの適用を試みることができるようにしました。私が遭遇している問題は、MessageBufferの内容を新しいMemoryStreamに書き込んでから逆シリアル化しようとすると、「ルートレベルのデータが無効です。1行目、1行目」というエラーが表示されることです。インスペクターをスキップするとすべてが正常に機能するため、渡されるデータが有効であることを私は知っています。

サンプルコード:

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
    {
        MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
        request = buffer.CreateMessage();
        string msg = buffer.CreateMessage().ToString();

        var dc = new DataContractSerializer(typeof(Adder));

        using (var stream = new MemoryStream())
        {
            buffer.WriteMessage(stream);

            stream.Position = 0;

            //deserializing error occurs here
            var c = dc.ReadObject(stream);
        }

        return null;
    }

Adderクラス/インターフェースは次のとおりです。

    [DataContract(Name = "adder", Namespace = "http://test.com")]
public class Adder
{
    [DataMember(Name = "first")]
    public int First { get; set; }

    [DataMember(Name = "second")]
    public int Second { get; set; }
}

    [ServiceContract(Namespace = "http://test.com")]
public interface ITestSvc
{
    [OperationContract(Name = "add")]
    int Add(Adder adder);
}

何か提案がありますか、またはこれのためのより良いオプションがありますか?私の主な目標は、サービスに着信するすべてのWCF要求でXMLを(逆シリアル化されたオブジェクトで)読み取ることです。

4

3 に答える 3

5

リクエストオブジェクトには、ペイロードだけでなくWCFメッセージヘッダーも含まれています。ヘッダーを取り除く必要があります。そうすれば、メッセージ本文を逆シリアル化できるはずです。

たとえば、SOAPメッセージには次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>

</soap:Header>
<soap:Body>
  <!-- your payload -->
</soap:Body>

XMLナビゲーションを使用してbody要素にアクセスし、その要素を単独で逆シリアル化することができます。

編集:実際には、私があなたのためにトリックをするべきだと思うこの方法に偶然出くわしました:

Message.GetReaderAtBodyContents

于 2012-10-24T01:39:06.690 に答える
0

私はこれをしました。次のすべてのコードをクラスに貼り付けて、DeserializedResponse()を呼び出します。MyResponseObjectを、逆シリアル化しようとしているオブジェクトの名前に変更する必要があります。また、「 _requestInspector.Response」を独自の応答xml文字列変数に置き換える必要があります。GetSoapBodyInnerXml()メソッドは、Soap Envelopeを取り除き、逆シリアル化する応答xmlのみを返します。

    private MyResponseObject DeserializedResponse()
    {
        var rootAttribute = new XmlRootAttribute("MyResponseObject ");
        rootAttribute.Namespace = @"http://www.company.com/MyResponseObjectNamespace";

        XmlSerializer serializer = new XmlSerializer(typeof(MyResponseObject ), rootAttribute);
        string responseSoapBodyInnerXml = GetSoapBodyInnerXml(_requestInspector.Response);
        AddXmlDeclaration(ref responseSoapBodyInnerXml);
        MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(responseSoapBodyInnerXml));
        MyResponseObject resultingResponse = (MyResponseObject )serializer.Deserialize(memStream);

        return resultingResponse;
    }

    private string GetSoapBodyInnerXml(string soapMessage)
    {
        XDocument xDoc = XDocument.Parse(soapMessage);
        XNamespace nsSoap = @"http://schemas.xmlsoap.org/soap/envelope/";
        return xDoc.Descendants(nsSoap + CONST_SoapBody).Descendants().First().ToString();
    }

    private void AddXmlDeclaration(ref string xmlString)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xmlString);

        //Create an XML declaration. 
        XmlDeclaration xmldecl;
        xmldecl = doc.CreateXmlDeclaration("1.0", "UTF-8", null);

        //Add the new node to the document.
        XmlElement root = doc.DocumentElement;
        doc.InsertBefore(xmldecl, root);

        //Return updated xmlString with XML Declaration
        xmlString = doc.InnerXml;
    }
于 2014-01-10T17:30:27.180 に答える
-3

マイク・パークヒルが提案したように、私は結局メッセージヘッダールートに行きました。

于 2012-10-27T03:22:02.273 に答える