【 Set-MessageInspector 関数 】
WCF クライアントが要求メッセージを送信する前、応答メッセージを受信した後の 2 箇所に独自の処理を追加します。
追加した処理からは、要求メッセージまたは応答メッセージの検査・変更を行うことができます。
これにより、例えば、SOAP メッセージをログに記録することができます。
[ パラメータ ]
・target
SvcUtil.exe が生成したクライアントクラス ( ClientBase ジェネリッククラスの派生クラス ) のインスタンスを指定します。
または、チャネルファクトリのインスタンスを指定します。
・beforeSendRequest
WCF クライアントが要求メッセージを送信する前に行う処理を指定します。
beforeSendRequest に指定する関数内では、要求メッセージ (System.ServiceModel.Channels.Message) を第一引数から取得できます。
また、WCF クライアント オブジェクト チャネル (System.ServiceModel.IClientChannel) を第二引数から取得できます。
関数が戻り値を返した場合、戻り値は afterReceiveReply に指定した関数の第二引数に、相関状態データとして渡されます。
・afterReceiveReply
WCF クライアントが応答メッセージを受信した後に行う処理を指定します。
afterReceiveReply に指定する関数内では、応答メッセージ (System.ServiceModel.Channels.Message) を第一引数から取得できます。
また、相関状態データ (System.Object) を第二引数から取得できます。
[ 戻り値 ]
なし
[ コード ]
function Set-MessageInspector
{
param ($target, [ScriptBlock]$beforeSendRequest, [ScriptBlock]$afterReceiveReply)
trap { break; }
function Compile-MessageInspectorCode
{
$source =
@"
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Management.Automation;
using System.Management.Automation.Internal;
using System.Management.Automation.Runspaces;
internal sealed class PSClientMessageInspector : IClientMessageInspector
{
private static object InvokeScript(ScriptBlock target, params object[] args)
{
StringBuilder argsTextBuilder = new StringBuilder();
if (args != null)
{
for (int i = 0; i <= args.Length; i++)
{
argsTextBuilder.AppendFormat("`$invokeArgs[{0}] ", i);
}
}
string invokeCommandText = string.Format("`$invokeArgs = `$Input | % {{ `$_; }}; &{{{0}}} {1}", target, argsTextBuilder);
Command invokeCommand = new Command(invokeCommandText, true, true);
using (Pipeline invokePipeline = Runspace.DefaultRunspace.CreateNestedPipeline())
{
invokePipeline.Commands.Add(invokeCommand);
Collection<PSObject> invokeResult = invokePipeline.Invoke(args);
object result = null;
if ((invokeResult != null) && (invokeResult.Count != 0))
{
result = (invokeResult.Count == 1) ? (object)invokeResult[0] : (object)invokeResult;
}
return result;
}
}
private readonly ScriptBlock _beforeSendRequestScriptBlock;
private readonly ScriptBlock _afterReceiveReplyScriptBlock;
public PSClientMessageInspector(ScriptBlock beforeSendRequestScriptBlock, ScriptBlock afterReceiveReplyScriptBlock)
{
this._beforeSendRequestScriptBlock = beforeSendRequestScriptBlock;
this._afterReceiveReplyScriptBlock = afterReceiveReplyScriptBlock;
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (this._beforeSendRequestScriptBlock == null)
{
return null;
}
return PSClientMessageInspector.InvokeScript(this._beforeSendRequestScriptBlock, request, channel);
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
if (this._afterReceiveReplyScriptBlock == null)
{
return;
}
PSClientMessageInspector.InvokeScript(this._afterReceiveReplyScriptBlock, reply, correlationState);
}
}
public sealed class PSClientMessageInspectorBehavior : IEndpointBehavior
{
private readonly PSClientMessageInspector _inspector;
public PSClientMessageInspectorBehavior(ScriptBlock beforeSendRequestScriptBlock, ScriptBlock afterReceiveReplyScriptBlock)
{
this._inspector = new PSClientMessageInspector(beforeSendRequestScriptBlock, afterReceiveReplyScriptBlock);
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(this._inspector);
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
"@;
$references =
@(
[System.Reflection.Assembly]::LoadWithPartialName("System.ServiceModel").Location,
[System.Reflection.Assembly]::LoadWithPartialName("System.Management.Automation").Location
);
Compile-CSCode $source $references | Out-Null;
}
$behaviors = $target.Endpoint.Behaviors;
if ($() -eq $behaviors)
{
throw "引数 client が、 System.ServiceModel.ClientBase``1 の派生型、または System.ServiceModel.ChannelFactory``1 の派生型ではありません。";
}
if ($() -eq ("PSClientMessageInspectorBehavior" -as [Type]))
{
Compile-MessageInspectorCode;
}
$inspectorBehavior = New-Object "PSClientMessageInspectorBehavior" @($beforeSendRequest, $afterReceiveReply);
$behaviors.Add($inspectorBehavior);
}
[ 注意 ]
・この関数は、内部で Compile-CSCode 関数 を使用しています。
Compile-CSCode 関数が使用できない場合、この関数は実行に失敗します。
・この関数で取得できる SOAP メッセージは、実際にネットワーク上で通信される SOAP メッセージとは異なる場合がありますので注意してください。
例えば、バインディングにWS-Security が適用されているとネットワーク上で通信される SOAP メッセージは暗号化されますが、この関数で取得した SOAP メッセージは暗号化前もしくは復号後のものになります。
ネットワーク上で実際に通信される SOAP メッセージを調べるには、Microsoft Network Monitor 等のツールを使用してください。
[ 使用例 ]
$client = New-WCFClient Sample.WCF.ServiceClient "C:\Work\WCF\Client.dll.config";
$beforeSendRequest =
{
param ($request, $channel)
return [DateTime]::Now;
};
$afterReceiveReply =
{
param ($reply, $correlationState)
"requested time: {0}" -f $correlationState | Write-Host;
$reply | Write-Host;
};
Set-MessageInspector $client $beforeSendRequest $afterReceiveReply;
このコマンドは、New-WCFClient 関数 を使用して生成されたWCF クライアントのインスタンスに、応答の SOAP メッセージをコンソール出力するための独自の処理を追加します。
応答の SOAP メッセージの出力時には、要求メッセージを送信した日時も出力します。
【 ダウンロード 】
自作の PowerShell 関数は、以下の記事からまとめてダウンロードできます。
YokoKen.PowerShell.Scripts
これは便利ですね。
使わせていただきます
2007.12.20 23:23 URL | Anthony #- [ 編集 ]
どうぞ使ってやってください^^
ただ、一つ重要なことを書き忘れてました。記事内の [ 注意 ] に追記しておきましたので、ご一読願います。 ( これじゃちょっと使えないか・・・ orz )
2007.12.21 13:29 URL | よこけん #Ay6tTHf6 [ 編集 ]
トラックバックURL↓
http://csharper.blog57.fc2.com/tb.php/194-5c458091