このWebサービスをコード内で呼び出しており、XMLを確認したいのですが、それを公開するプロパティが見つかりません。
サーバーでトレースするのではなく、クライアントでXMLを表示することを意味していると思います。その場合、あなたの答えは私が上でリンクした質問にあり、また クライアントでメッセージを検査または修正する方法 にあります。しかし、その記事の.NET 4バージョンにはC#がなく、.NET 3.5の例には(バグではないにしても)多少の混乱があるため、ここでは目的に合わせて展開します。
IClientMessageInspector を使用して、メッセージが送信される前にインターセプトできます。
_using System.ServiceModel.Dispatcher;
public class MyMessageInspector : IClientMessageInspector
{ }
_
そのインターフェイスのメソッドBeforeSendRequest
およびAfterReceiveReply
を使用すると、要求と応答にアクセスできます。インスペクターを使用するには、それを IEndpointBehavior に追加する必要があります。
_using System.ServiceModel.Description;
public class InspectorBehavior : IEndpointBehavior
{
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyMessageInspector());
}
}
_
そのインターフェイスの他のメソッドも、それらの機能を使用する場合を除き、空の実装のままにしておくことができます。詳細については、ハウツーをお読みください。
クライアントをインスタンス化した後、動作をエンドポイントに追加します。サンプルWCFプロジェクトのデフォルト名を使用:
_ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
client.Endpoint.Behaviors.Add(new InspectorBehavior());
client.GetData(123);
_
MyMessageInspector.BeforeSendRequest()
;にブレークポイントを設定します。 request.ToString()
は、XMLを表示するためにオーバーロードされます。
メッセージをまったく操作する場合は、メッセージのコピーを作成する必要があります。詳細については、 メッセージクラスの使用 を参照してください。
これらのリンクを見つけるための別の質問で Zach Bonhamの答え に感謝します。
単純にリクエストメッセージをトレースできます。
OperationContext context = OperationContext.Current;
if (context != null && context.RequestContext != null)
{
Message msg = context.RequestContext.RequestMessage;
string reqXML = msg.ToString();
}
OperationContext.Current.RequestContext.RequestMessage
このコンテキストは、リクエストの処理中にアクセス可能なサーバー側です。これは一方向の操作では機能しません
キンバリーからの答えにこれを加えたかっただけです。 IEndpointBehaviourインターフェイスが必要とするすべてのメソッドを実装しないことで、時間を節約し、コンパイルエラーを回避できる可能性があります。
宜しくお願いします
ニッキー
/*
// 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();
}
}
XMLを見る別の方法がありますSOAP- custom MessageEncoder 。IClientMessageInspectorとの主な違いは、それが下位レベルで動作するため、任意の不正な形式のxml。
このアプローチを使用してトレースを実装するには、標準の textMessageEncoding を custom message encoder as new binding element にラップし、そのカスタムバインディングを適用する必要があります config のエンドポイント。
また、プロジェクトでどのようにそれを行ったかを例として見ることができます- wrapping textMessageEncoding、ロギング encoder 、カスタムバインディング element および config 。
IIS ASP.NET互換モードでのホスティングに以下のソリューションを使用しています。RodneyVianaの MSDNブログ に感謝します。
AppSettingsの下のweb.configに以下を追加します。
<add key="LogPath" value="C:\\logpath" />
<add key="LogRequestResponse" value="true" />
Global.asax.csを以下で置き換えます(名前空間名も修正します):
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);
}
}
}
要求と応答のXMLを使用してLogPathフォルダーにログファイルを作成する必要があります。