wake-up-neo.com

Wie bekomme ich das XML? SOAP Anfrage einer WCF-Webservice-Anfrage?

Ich rufe diesen Web-Service im Code an und möchte XML sehen, aber ich kann keine Eigenschaft finden, die es verfügbar macht.

63
Diskdrive

Ich denke, Sie meinten damit, dass Sie XML am Client sehen und nicht am Server verfolgen möchten. In diesem Fall finden Sie Ihre Antwort in der oben verlinkten Frage sowie unter So überprüfen Sie Nachrichten auf dem Client . Da jedoch in der .NET 4-Version dieses Artikels C # fehlt und das .NET 3.5-Beispiel einige Verwirrung (wenn nicht einen Fehler) enthält, wird es hier für Sie erweitert.

Sie können die Nachricht abfangen, bevor sie mit einem IClientMessageInspector ausgeht:

using System.ServiceModel.Dispatcher;
public class MyMessageInspector : IClientMessageInspector
{ }

Die Methoden in dieser Schnittstelle, BeforeSendRequest und AfterReceiveReply, geben Ihnen Zugriff auf die Anfrage und Antwort. Um den Inspektor verwenden zu können, müssen Sie ihn einem IEndpointBehavior hinzufügen:

using System.ServiceModel.Description;
public class InspectorBehavior : IEndpointBehavior
{
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new MyMessageInspector());
    }
}

Sie können die anderen Methoden dieser Schnittstelle als leere Implementierungen belassen, es sei denn, Sie möchten auch deren Funktionalität verwenden. Lesen Sie die Anleitung für weitere Details.

Nachdem Sie den Client instanziiert haben, fügen Sie das Verhalten dem Endpunkt hinzu. Standardnamen aus dem WCF-Beispielprojekt verwenden:

ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
client.Endpoint.Behaviors.Add(new InspectorBehavior());
client.GetData(123);

Setzen Sie einen Haltepunkt in MyMessageInspector.BeforeSendRequest(); request.ToString() ist überladen, um das XML anzuzeigen.

Wenn Sie die Nachrichten überhaupt bearbeiten möchten, müssen Sie eine Kopie der Nachricht bearbeiten. Weitere Informationen finden Sie unter Using the Message Class .

Vielen Dank an Zach Bonhams Antwort bei einer anderen Frage für das Auffinden dieser Links. 

124
Kimberly

Option 1

Verwenden Sie Message Tracing/Logging

Schauen Sie nach hier und hier .


Option 2

Sie können immer Fiddler verwenden, um die HTTP-Anforderungen und die Antwort anzuzeigen.


Option 3

Verwenden Sie System.Net Tracing .

28
Aliostad

Einfach können wir die Anforderungsnachricht als verfolgen.

OperationContext context = OperationContext.Current;

if (context != null && context.RequestContext != null)

{

Message msg = context.RequestContext.RequestMessage;

string reqXML = msg.ToString();

}
6
Shebin
OperationContext.Current.RequestContext.RequestMessage 

dieser Kontext ist serverseitig während der Verarbeitung der Anforderung zugänglich. Dies funktioniert nicht für Einwegoperationen

6
Alexus1024

Ich wollte das nur zur Antwort von Kimberly hinzufügen. Möglicherweise kann dies etwas Zeit sparen und Kompilierungsfehler vermeiden, da nicht alle Methoden implementiert werden, die für die IEndpointBehaviour-Schnittstelle erforderlich sind.

Freundliche Grüße

Nicki

    /*
        // This is just to illustrate how it can be implemented on an imperative declarared binding, channel and client.

        string url = "SOME WCF URL";
        BasicHttpBinding wsBinding = new BasicHttpBinding();                
        EndpointAddress endpointAddress = new EndpointAddress(url);

        ChannelFactory<ISomeService> channelFactory = new ChannelFactory<ISomeService>(wsBinding, endpointAddress);
        channelFactory.Endpoint.Behaviors.Add(new InspectorBehavior());
        ISomeService client = channelFactory.CreateChannel();
    */    
        public class InspectorBehavior : IEndpointBehavior
        {
            public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
            {
                // No implementation necessary  
            }

            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
            {
                clientRuntime.MessageInspectors.Add(new MyMessageInspector());
            }

            public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
            {
                // No implementation necessary  
            }

            public void Validate(ServiceEndpoint endpoint)
            {
                // No implementation necessary  
            }  

        }

        public class MyMessageInspector : IClientMessageInspector
        {
            public object BeforeSendRequest(ref Message request, IClientChannel channel)
            {
                // Do something with the SOAP request
                string request = request.ToString();
                return null;
            }

            public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
            {
                // Do something with the SOAP reply
                string replySoap = reply.ToString();
            }
        }
1
Nicki

Es gibt eine andere Möglichkeit, XML SOAP - custom MessageEncoder anzuzeigen. Der Hauptunterschied zu IClientMessageInspector besteht darin, dass es auf einer niedrigeren Ebene arbeitet und somit den ursprünglichen Byte-Inhalt einschließlich fehlerhafter XML-Dateien erfasst.

Um die Ablaufverfolgung mithilfe dieses Ansatzes zu implementieren, müssen Sie eine Standard- textMessageEncoding mit custom message encoder als neues binding-Element umschließen und diese benutzerdefinierte Bindung auf den Endpunkt in config anwenden.

Sie können auch als Beispiel sehen, wie ich dies in meinem Projekt - wrapping textMessageEncoding, Protokollierung encoder , benutzerdefinierte Bindung element und config durchgeführt habe.

0
baur

Ich verwende eine Lösung für IIS, die im ASP.NET-Kompatibilitätsmodus hostet. Dank an Rodney Vianas MSDN-Blog .

Fügen Sie Ihrer web.config unter appSettings Folgendes hinzu:

<add key="LogPath" value="C:\\logpath" />
<add key="LogRequestResponse" value="true" />

Ersetzen Sie Ihre global.asax.cs durch unten (auch Namensraumnamen festlegen):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;

using System.Text;
using System.IO;
using System.Configuration;

namespace Yournamespace
{
    public class Global : System.Web.HttpApplication
    {
        protected static bool LogFlag;
        protected static string fileNameBase;
        protected static string ext = "log";

        // One file name per day
        protected string FileName
        {
            get
            {
                return String.Format("{0}{1}.{2}", fileNameBase, DateTime.Now.ToString("yyyy-MM-dd"), ext);
            }
        }

        protected void Application_Start(object sender, EventArgs e)
        {
            LogFlag = bool.Parse(ConfigurationManager.AppSettings["LogRequestResponse"].ToString());
            fileNameBase = ConfigurationManager.AppSettings["LogPath"].ToString() + @"\C5API-";   
        }

        protected void Session_Start(object sender, EventArgs e)
        {

        }

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            if (LogFlag) 
            {                
                // Creates a unique id to match Rquests with Responses
                string id = String.Format("Id: {0} Uri: {1}", Guid.NewGuid(), Request.Url);
                FilterSaveLog input = new FilterSaveLog(HttpContext.Current, Request.Filter, FileName, id);
                Request.Filter = input;
                input.SetFilter(false);
                FilterSaveLog output = new FilterSaveLog(HttpContext.Current, Response.Filter, FileName, id);
                output.SetFilter(true);
                Response.Filter = output;
            }
        }

        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {

        }

        protected void Application_Error(object sender, EventArgs e)
        {

        }

        protected void Session_End(object sender, EventArgs e)
        {

        }

        protected void Application_End(object sender, EventArgs e)
        {

        }
    }

    class FilterSaveLog : Stream
    {

        protected static string fileNameGlobal = null;
        protected string fileName = null;

        protected static object writeLock = null;
        protected Stream sinkStream;
        protected bool inDisk;
        protected bool isClosed;
        protected string id;
        protected bool isResponse;
        protected HttpContext context;

        public FilterSaveLog(HttpContext Context, Stream Sink, string FileName, string Id)
        {
            // One lock per file name
            if (String.IsNullOrWhiteSpace(fileNameGlobal) || fileNameGlobal.ToUpper() != fileNameGlobal.ToUpper())
            {
                fileNameGlobal = FileName;
                writeLock = new object();
            }
            context = Context;
            fileName = FileName;
            id = Id;
            sinkStream = Sink;
            inDisk = false;
            isClosed = false;
        }

        public void SetFilter(bool IsResponse)
        {


            isResponse = IsResponse;
            id = (isResponse ? "Reponse " : "Request ") + id;

            //
            // For Request only read the incoming stream and log it as it will not be "filtered" for a WCF request
            //
            if (!IsResponse)
            {
                AppendToFile(String.Format("at {0} --------------------------------------------", DateTime.Now));
                AppendToFile(id);

                if (context.Request.InputStream.Length > 0)
                {
                    context.Request.InputStream.Position = 0;
                    byte[] rawBytes = new byte[context.Request.InputStream.Length];
                    context.Request.InputStream.Read(rawBytes, 0, rawBytes.Length);
                    context.Request.InputStream.Position = 0;

                    AppendToFile(rawBytes);
                }
                else
                {
                    AppendToFile("(no body)");
                }
            }

        }

        public void AppendToFile(string Text)
        {
            byte[] strArray = Encoding.UTF8.GetBytes(Text);
            AppendToFile(strArray);

        }

        public void AppendToFile(byte[] RawBytes)
        {
            bool myLock = System.Threading.Monitor.TryEnter(writeLock, 100);


            if (myLock)
            {
                try
                {

                    using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                    {
                        stream.Position = stream.Length;
                        stream.Write(RawBytes, 0, RawBytes.Length);
                        stream.WriteByte(13);
                        stream.WriteByte(10);

                    }

                }
                catch (Exception ex)
                {
                    string str = string.Format("Unable to create log. Type: {0} Message: {1}\nStack:{2}", ex, ex.Message, ex.StackTrace);
                    System.Diagnostics.Debug.WriteLine(str);
                    System.Diagnostics.Debug.Flush();


                }
                finally
                {
                    System.Threading.Monitor.Exit(writeLock);


                }
            }


        }


        public override bool CanRead
        {
            get { return sinkStream.CanRead; }
        }

        public override bool CanSeek
        {
            get { return sinkStream.CanSeek; }
        }

        public override bool CanWrite
        {
            get { return sinkStream.CanWrite; }
        }

        public override long Length
        {
            get
            {
                return sinkStream.Length;
            }
        }

        public override long Position
        {
            get { return sinkStream.Position; }
            set { sinkStream.Position = value; }
        }

        //
        // For WCF this code will never be reached
        //
        public override int Read(byte[] buffer, int offset, int count)
        {
            int c = sinkStream.Read(buffer, offset, count);
            return c;
        }

        public override long Seek(long offset, System.IO.SeekOrigin direction)
        {
            return sinkStream.Seek(offset, direction);
        }

        public override void SetLength(long length)
        {
            sinkStream.SetLength(length);
        }

        public override void Close()
        {

            sinkStream.Close();
            isClosed = true;
        }

        public override void Flush()
        {

            sinkStream.Flush();
        }

        // For streamed responses (i.e. not buffered) there will be more than one Response (but the id will match the Request)
        public override void Write(byte[] buffer, int offset, int count)
        {
            sinkStream.Write(buffer, offset, count);
            AppendToFile(String.Format("at {0} --------------------------------------------", DateTime.Now));
            AppendToFile(id);
            AppendToFile(buffer);
        }

    }
}

Es sollte eine Protokolldatei im Ordner LogPath mit Anforderungs- und Antwort-XML erstellen.

0
Manish Jain