Journalise les messages SOAP à partir d’une application console

J’essaie de consigner les demandes et les réponses (l’enveloppe XML SOAP brute) entre une application console développée par moi-même et un service Web SOAP distant tiers spécifique dans une firebase database à des fins d’audit. .

Idéalement, j’aimerais recevoir la demande

    Albireo    

et la réponse

    Hello, Albireo.    

et enregistrez-les dans la firebase database.

Jusqu’à présent, chaque tutoriel sur le net que j’ai trouvé se résume à deux approches: la méthode SoapExtension et la méthode de traçage.

La méthode SoapExtension

La méthode SoapExtension est basée sur le guide SOAP Message Modification À l’aide d’extensions SOAP . Dans cette méthode, vous créez une classe héritant de SoapExtension et l’attachez dans la configuration de l’application. La méthode ProcessMessage de la classe vous permettra d’intercepter les messages SOAP.

Voici un exemple de la classe héritée de SoapExtension:

 namespace Playground.Client { using System; using System.Web.Services.Protocols; public class SoapLogger : SoapExtension { public override object GetInitializer(System.Type serviceType) { throw new NotImplementedException(); } public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAtsortingbute atsortingbute) { throw new NotImplementedException(); } public override void Initialize(object initializer) { throw new NotImplementedException(); } public override void ProcessMessage(SoapMessage message) { throw new NotImplementedException(); } } } 

Et voici comment cela est câblé dans la configuration:

                        

Le problème avec cette méthode est qu’elle semble ne fonctionner que pour les applications Web. Essayer de l’implémenter dans une application console ne donne aucun résultat.

La méthode de traçage

La méthode de traçage est basée sur le guide de configuration de la journalisation des messages . Dans cette méthode, vous activez le traçage .NET pour chaque communication SOAP / WCF de l’application et videz le journal quelque part (pour plus d’informations sur la configuration, consultez la rubrique Paramètres recommandés pour le traçage et le message. Enregistrement ).

Voici un exemple de configuration de traçage:

                                   

Le contenu de ServiceModel.svclog et MessageLogging.svclog peut être trouvé dans le Gist d’un GitHub, car il est trop volumineux pour y figurer.

Le problème avec cette méthode est qu’il enregistre chaque message SOAP / WCF dans l’application et il semble que les journaux générés ne sont pas vraiment utiles, ils contiennent une foule d’informations et je ne comprends pas si et comment filtrer uniquement ce qui m’intéresse, Le seul moyen pratique de les lire semble être Service Trace Viewer de Microsoft.

J’ai aussi essayé d’append un TraceListener personnalisé:

 namespace Playground.Client { using System; using System.Diagnostics; using System.IO; using System.Text; using System.Xml; using System.Xml.Linq; public class CustomTraceListener : TraceListener { public override void Write(ssortingng message) { File.AppendAllLines("CustomTraceListener.txt", new[] { message }); } public override void WriteLine(ssortingng message) { message = this.FormatXml(message); File.AppendAllLines("CustomTraceListener.txt", new[] { message }); } private ssortingng FormatXml(ssortingng message) { using (var ssortingngWriter = new SsortingngWriter()) { var xmlWriterSettings = new XmlWriterSettings(); xmlWriterSettings.Encoding = Encoding.UTF8; xmlWriterSettings.Indent = true; xmlWriterSettings.OmitXmlDeclaration = true; using (var xmlTextWriter = XmlWriter.Create(ssortingngWriter, xmlWriterSettings)) { XDocument.Parse(message).Save(xmlTextWriter); } return Convert.ToSsortingng(ssortingngWriter); } } } } 

Mais même si cela me permet d’intercepter les messages, cela n’enregistre aucune métadonnée:

   POST   uIDPo4bOsuSXlSVEkmfof4AP2psAAAAAlEIoNto3KEWKgCnIGryjp9f3wbRlp+ROhY9Oy6bed/cACQAA     http://tempuri.org/IGreeterService/SayHello 80101cc1-dfb5-4c8e-8d19-ec848ab69100    Albireo       http://tempuri.org/IGreeterService/SayHello http://localhost:8080/greeter   POST   uIDPo4bOsuSXlSVEkmfof4AP2psAAAAAlEIoNto3KEWKgCnIGryjp9f3wbRlp+ROhY9Oy6bed/cACQAA     80101cc1-dfb5-4c8e-8d19-ec848ab69100    Albireo     

Avec ces informations, il est impossible de reconstruire le stream de demandes / réponses car tous les messages sont mélangés.

Comparez-les au * .svclog généré par le XmlWriterTraceListener natif:

   0 3 0 8      ESP-DEV-9       http://tempuri.org/IGreeterService/SayHello http://localhost:8080/greeter   POST   uIDPo4bOsuSXlSVEkmfof4AP2psAAAAAlEIoNto3KEWKgCnIGryjp9f3wbRlp+ROhY9Oy6bed/cACQAA     80101cc1-dfb5-4c8e-8d19-ec848ab69100    Albireo           0 3 0 8      ESP-DEV-9       OK OK  207 text/xml; charset=utf-8 Tue, 16 Jul 2013 08:50:04 GMT Microsoft-HTTPAPI/2.0       Hello, Albireo.         

Ici, la établit une relation entre chaque demande et chaque réponse, permettant ainsi au développeur de reconstruire l’intégralité de la session.

Y a-t-il un moyen d’accomplir ce que j’essaie de faire?

Si le service est enregistré en tant que service Web WCF (et non en tant que service Web ASMX traditionnel), il est possible de le faire via IClientMessageInspector et IEndpointBehavior .

Vous devez d’abord créer une classe héritant de IClientMessageInspector qui gérera la journalisation des demandes et des réponses.

 namespace Playground.Sandbox { using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; public class MyClientMessageInspector : IClientMessageInspector { public object BeforeSendRequest( ref Message request, IClientChannel channel) { // TODO: log the request. // If you return something here, it will be available in the // correlationState parameter when AfterReceiveReply is called. return null; } public void AfterReceiveReply( ref Message reply, object correlationState) { // TODO: log the reply. // If you returned something in BeforeSendRequest // it will be available in the correlationState parameter. } } } 

Ensuite, vous devez créer une classe héritant de IEndpointBehavior qui enregistrera l’inspecteur dans le client.

 namespace Playground.Sandbox { using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; public class MyEndpointBehavior : IEndpointBehavior { public void Validate( ServiceEndpoint endpoint) { } public void AddBindingParameters( ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior( ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void ApplyClientBehavior( ServiceEndpoint endpoint, ClientRuntime clientRuntime) { var myClientMessageInspector = new MyClientMessageInspector(); clientRuntime.ClientMessageInspectors.Add(myClientMessageInspector); } } } 

Ensuite, lorsque vous souhaitez utiliser le comportement, vous pouvez l’enregistrer manuellement avant d’utiliser le service.

 namespace Playground.Sandbox { public static class Program { public static void Main() { using (var client = new MyWcfClient()) { var myEndpointBehavior = new MyEndpointBehavior(); client.Endpoint.Behaviors.Add(myEndpointBehavior); // TODO: your things with the client. } } } } 

Si vous ne souhaitez pas enregistrer le comportement manuellement ou si vous souhaitez qu’il soit toujours actif, vous pouvez l’enregistrer dans le fichier de configuration.

Vous devez d’abord créer une classe héritant de BehaviorExtensionElement . Cette classe indiquera au .NET Framework le comportement à appliquer et créera l’instance si nécessaire.

 namespace Playground.Sandbox { using System; using System.ServiceModel.Configuration; public class MyBehaviorExtensionElement : BehaviorExtensionElement { protected override object CreateBehavior() { var myEndpointBehavior = new MyEndpointBehavior(); return myEndpointBehavior; } public override Type BehaviorType { get { return typeof(MyEndpointBehavior); } } } } 

Ensuite, vous devez enregistrer BehaviorExtensionElement dans le fichier de configuration (seule la partie pertinente du fichier de configuration est affichée).

                        

Maintenant, vous pouvez utiliser le service sans enregistrer manuellement le comportement à chaque fois:

 namespace Playground.Sandbox { public static class Program { public static void Main() { using (var client = new MyWcfService()) { // TODO: your things with the client. } } } } 

Vous trouverez un guide sur la procédure à suivre dans l’article des inspecteurs de messages de MSDN.