Ich denke, Sie haben gemeint, dass Sie das XML auf dem Client sehen und nicht auf dem Server verfolgen möchten. In diesem Fall finden Sie Ihre Antwort in der Frage, die ich oben verlinkt habe, sowie in Informationen zum Überprüfen oder Ändern von Nachrichten auf dem Client . Da in der .NET 4-Version dieses Artikels jedoch das C # fehlt und das .NET 3.5-Beispiel einige Verwirrung (wenn nicht einen Fehler) aufweist, wird es hier für Ihren Zweck erweitert.
using System.ServiceModel.Dispatcher;
publicclassMyMessageInspector : IClientMessageInspector
{ }
Die Methoden in dieser Schnittstelle BeforeSendRequestund AfterReceiveReplygeben Ihnen Zugriff auf die Anforderung und Antwort. Um den Inspektor zu verwenden, müssen Sie ihn einem IEndpointBehavior hinzufügen :
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.
Fügen Sie das Verhalten dem Endpunkt hinzu, nachdem Sie den Client instanziiert haben. Verwenden von Standardnamen aus dem WCF-Beispielprojekt:
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 an einer Kopie der Nachricht arbeiten. Weitere Informationen finden Sie unter Verwenden der Nachrichtenklasse .
Vielen Dank an Zach Bonhams Antwort auf eine andere Frage zum Auffinden dieser Links.
Ich habe sowohl Ihnen als auch Zach Bonhams Antwort eine positive Bewertung gegeben! Danke für die einfache Lösung. Ich habe es angeschlossen, um eine Datei basierend auf einer Konfiguration zu schreiben
Dies funktioniert, aber es macht nicht das, was ich (und das OP, nehme ich an) will, weil es Ihnen keinen Zugriff auf den rohen eingehenden Körper gibt, wie er auf der HTTP-Ebene angekommen ist. Das XML wurde validiert, bevor Sie es erhalten. Wenn der Webdienst (wie es manchmal vorkommt) mit einer HTML-Fehlerseite antwortet, muss ich den HTML-Code dieser Seite abrufen. Und was ich bekomme und absolut nicht brauche, ist ein Teil des XML, das weggelassen wird ("... Stream ..." in Message.ToString, und unvollständiges XML mit ReadOuterXml und ReadInnerXml aus dem XmlReader, das Sie für den Body erhalten können )
Luc VdV
Ähnlich wie bei @ LucVdVs Kommentar erhalten Sie hier nicht die eigentliche Anfrage. Es gibt kleine Unterschiede zwischen dem, was dies hervorbringt, und dem, was Fiddler Ihnen tatsächlich erzählt hat. Unterschiede, die so bedeutend sind, dass das Kopieren des Ergebnisses in SoapUI oder Postman beim Senden der Anfrage zu seltsamen Fehlern führt.
Asontu
29
Option 1
Verwenden Sie die Nachrichtenverfolgung / -protokollierung .
Seien Sie vorsichtig mit Fiddler, wenn Sie Sicherheitskonfigurationen auf paranoider Ebene verwenden (z. B. gegenseitige Zertifikate über SSL ). Das Vorhandensein eines Proxys verursacht diese Ausnahme: System.ServiceModel.Security.SecurityNegotiationException
user1778770
1
Ich weiß nicht, warum Option 1 bei mir nicht funktioniert hat. Es wurden verschiedene Konfigurationsoptionen für die Nachrichtenprotokollierung versucht, und der Text wird in SvcTraceViewer nicht angezeigt.
Shiv
Option 1 hat bei mir funktioniert. Ich konnte die gesamte ausgehende und eingehende SOAP-Nachricht sehen. Ich musste ein Service Level Flag setzen, um zu sehen, was ich wollte. logMessagesAtServiceLevel = "true"
Ich denke, dies ist auf dem Service-Endpunkt (Server) verfügbar. Gibt es eine Möglichkeit, dasselbe auf der Client-Seite zu erhalten, von der aus die Anfrage gesendet wird?
Himansz
3
Ich wollte dies nur der Antwort von Kimberly hinzufügen. Möglicherweise kann dies 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();
*/publicclassInspectorBehavior : IEndpointBehavior
{
publicvoidAddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
// No implementation necessary
}
publicvoidApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyMessageInspector());
}
publicvoidApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
// No implementation necessary
}
publicvoidValidate(ServiceEndpoint endpoint)
{
// No implementation necessary
}
}
publicclassMyMessageInspector : IClientMessageInspector
{
publicobjectBeforeSendRequest(ref Message request, IClientChannel channel)
{
// Do something with the SOAP requeststring request = request.ToString();
returnnull;
}
publicvoidAfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
// Do something with the SOAP replystring replySoap = reply.ToString();
}
}
Es gibt eine andere Möglichkeit, XML SOAP anzuzeigen - den benutzerdefinierten MessageEncoder . Der Hauptunterschied zu IClientMessageInspector besteht darin, dass es auf einer niedrigeren Ebene funktioniert, sodass der ursprüngliche Byte-Inhalt einschließlich aller fehlerhaften XML-Dateien erfasst wird.
Sie können auch als Beispiel sehen , wie ich habe es in meinem Projekt -
Verpackung textMessageEncoding, Logging - Encoder , kundenspezifische Bindungselement und Config .
Antworten:
Ich denke, Sie haben gemeint, dass Sie das XML auf dem Client sehen und nicht auf dem Server verfolgen möchten. In diesem Fall finden Sie Ihre Antwort in der Frage, die ich oben verlinkt habe, sowie in Informationen zum Überprüfen oder Ändern von Nachrichten auf dem Client . Da in der .NET 4-Version dieses Artikels jedoch das C # fehlt und das .NET 3.5-Beispiel einige Verwirrung (wenn nicht einen Fehler) aufweist, wird es hier für Ihren Zweck erweitert.
Sie können die Nachricht mit einem IClientMessageInspector abfangen, bevor sie ausgeht :
using System.ServiceModel.Dispatcher; public class MyMessageInspector : IClientMessageInspector { }
Die Methoden in dieser Schnittstelle
BeforeSendRequest
undAfterReceiveReply
geben Ihnen Zugriff auf die Anforderung und Antwort. Um den Inspektor zu verwenden, 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.
Fügen Sie das Verhalten dem Endpunkt hinzu, nachdem Sie den Client instanziiert haben. Verwenden von Standardnamen aus dem WCF-Beispielprojekt:
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 an einer Kopie der Nachricht arbeiten. Weitere Informationen finden Sie unter Verwenden der Nachrichtenklasse .
Vielen Dank an Zach Bonhams Antwort auf eine andere Frage zum Auffinden dieser Links.
quelle
Option 1
Verwenden Sie die Nachrichtenverfolgung / -protokollierung .
Schauen Sie hier und hier .
Option 2
Sie können Fiddler jederzeit verwenden , um die HTTP-Anforderungen und -Antworten anzuzeigen.
Option 3
Verwenden Sie die System.Net-Ablaufverfolgung .
quelle
OperationContext.Current.RequestContext.RequestMessage
Dieser Kontext ist während der Bearbeitung der Anfrage serverseitig zugänglich. Dies funktioniert nicht für Einwegoperationen
quelle
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(); }
quelle
Ich wollte dies nur der Antwort von Kimberly hinzufügen. Möglicherweise kann dies 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(); } }
quelle
Ich verwende die folgende Lösung für das IIS-Hosting im ASP.NET-Kompatibilitätsmodus. 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 die folgende (korrigieren Sie auch den Namespace-Namen):
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.
quelle
Es gibt eine andere Möglichkeit, XML SOAP anzuzeigen - den benutzerdefinierten MessageEncoder . Der Hauptunterschied zu IClientMessageInspector besteht darin, dass es auf einer niedrigeren Ebene funktioniert, sodass der ursprüngliche Byte-Inhalt einschließlich aller fehlerhaften XML-Dateien erfasst wird.
Um die Ablaufverfolgung mit diesem Ansatz zu implementieren, müssen Sie eine Standard- textMessageEncoding mit einem benutzerdefinierten Nachrichtencodierer als neues Bindungselement umschließen und diese benutzerdefinierte Bindung auf den Endpunkt in Ihrer Konfiguration anwenden .
Sie können auch als Beispiel sehen , wie ich habe es in meinem Projekt - Verpackung textMessageEncoding, Logging - Encoder , kundenspezifische Bindungselement und Config .
quelle