web-dev-qa-db-fra.com

Comment puis-je obtenir le XML SOAP demande d'une demande de service Web WCF?

J'appelle ce service Web dans le code et j'aimerais voir le code XML, mais je ne peux pas trouver une propriété qui l'expose.

63
Diskdrive

Je pense que vous vouliez dire que vous voulez voir le code XML sur le client, pas le tracer sur le serveur. Dans ce cas, votre réponse se trouve dans la question précitée, ainsi qu’à Comment inspecter ou modifier des messages sur le client . Mais, étant donné que la version .NET 4 de cet article ne contient pas de C # et que l'exemple .NET 3.5 présente une certaine confusion (si ce n'est un bogue), il est développé ici pour vous.

Vous pouvez intercepter le message avant sa disparition à l'aide d'un IClientMessageInspector :

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

Les méthodes de cette interface, BeforeSendRequest et AfterReceiveReply, vous permettent d'accéder à la demande et d'y répondre. Pour utiliser l'inspecteur, vous devez l'ajouter à un IEndpointBehavior :

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

Vous pouvez laisser les autres méthodes de cette interface sous forme d'implémentations vides, à moins que vous ne souhaitiez également utiliser leurs fonctionnalités. Lisez le guide pour plus de détails.

Après avoir instancié le client, ajoutez le comportement au noeud final. Utilisation de noms par défaut à partir de l'exemple de projet WCF:

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

Définissez un point d'arrêt dans MyMessageInspector.BeforeSendRequest(); request.ToString() est surchargé pour afficher le code XML.

Si vous voulez manipuler les messages, vous devez travailler sur une copie du message. Voir Utilisation de la classe de message pour plus de détails.

Merci à la réponse de Zach Bonham à une autre question pour trouver ces liens. 

124
Kimberly

Option 1

Utilisez suivi des messages/journalisation

Regardez ici et ici .


Option 2

Vous pouvez toujours utiliser Fiddler pour voir les requêtes et les réponses HTTP.


Option 3

Utilisez Suivi System.Net .

28
Aliostad

Nous pouvons simplement suivre le message de demande en tant que.

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 

ce contexte est accessible côté serveur lors du traitement de la requête . Cela ne fonctionne pas pour les opérations à sens unique

6
Alexus1024

Je voulais juste ajouter ceci à la réponse de Kimberly. Cela permettra peut-être de gagner du temps et d'éviter des erreurs de compilation en ne mettant pas en œuvre toutes les méthodes requises par l'interface IEndpointBehaviour.

Meilleures salutations

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

Il existe un autre moyen de voir XML SOAP - custom MessageEncoder . La principale différence avec IClientMessageInspector est qu’il fonctionne au niveau inférieur, de sorte qu’il capture le contenu en octets original, y compris tout xml mal formé.

Pour implémenter le traçage à l'aide de cette approche, vous devez envelopper un textMessageEncoding standard avec encodeur de message personnalisé en tant que nouvel élément binding et appliquer cette liaison personnalisée au noeud final de votre config .

Vous pouvez également voir, à titre d'exemple, comment je l'ai fait dans mon projet - wrapping textMessageEncoding, journalisation encoder , liaison personnalisée element et config .

0
baur

J'utilise la solution ci-dessous pour l'hébergement IIS en mode de compatibilité ASP.NET. Crédits à Rodney Viana/ Blog MSDN .

Ajoutez ce qui suit à votre configuration web sous appSettings:

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

Remplacez votre global.asax.cs par ci-dessous (corrigez également le nom de l'espace de nom):

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);
        }

    }
}

Il convient de créer un fichier journal dans le dossier LogPath avec une requête et une réponse XML.

0
Manish Jain