いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

WCF入門-011 (基本的なサンプル, トレースログの出力)


今回は、トレースログの出力について。


WCFでは、様々ログを出力することができます。
その中でも、最も基本的なものがトレースログとなります。


ログの詳細な出力パターンについては、まだ勉強中なので・・・
今回は、とりあえず簡単な出力方法のみメモメモ。


トレースログの設定はアプリケーション構成ファイルで行います。
一から設定ファイルに記述するのは大変ですので、VisualStudio上で
app.configファイルを右クリックして表示できる「サービス構成エディタ」から
出力される元ネタをいじったほうが楽です。


「サービス構成エディタ」上にて、左のツリーの「診断」ノードをクリックすると
右のエリアが以下のような状態になります。

ここから、メッセージログの有効化をクリックするとログの設定が行えるようになります。
ファイルの保管場所とかちょこちょこ設定してから保存するとアプリケーション構成ファイルに
設定が出力されています。


その出力された設定を以下のようにします。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>
        <sources>
            <source name="System.ServiceModel.MessageLogging" switchValue="Information,ActivityTracing">
                <listeners>
                    <add name="ServiceModelMessageLoggingListener">
                        <filter type="" />
                    </add>
                </listeners>
            </source>
        </sources>
        <sharedListeners>
            <add initializeData="D:\Tmp\app_messages.svclog"
                 type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                 name="ServiceModelMessageLoggingListener" 
                 traceOutputOptions="LogicalOperationStack, DateTime">
                <filter type="" />
            </add>
        </sharedListeners>
    </system.diagnostics>
    <system.serviceModel>
        <diagnostics>
            <!-- ロギングするメッセージの設定 -->
            <!--   logEntireMessageをtrueにするとSOAPメッセージの本文も出力される。-->
            <!--   logMessagesAtServiceLevelをtrueにすると暗号化前のメッセージがログに出力される。-->
            <messageLogging logEntireMessage="true" 
                            logMalformedMessages="true"
                            logMessagesAtServiceLevel="true" 
                            logMessagesAtTransportLevel="false" />
        </diagnostics>
        <client>省略・・</client>
    </system.serviceModel>
</configuration>

system.serviceModel以下のmessageLogging要素にて、logEntireMessageをtrueにすることが重要。
これを設定しないと、SOAPメッセージの本文が出力されません。
明示的にSOAPヘッダにデータを設定するようサービスを設定していない限り
デフォルトでは、本文の方に設定されていますので、これを設定しないとデータがログで見れません。


あとは、logMessagesAtServiceLevelをtrueに設定して、暗号化前のデータをログに出力するように
設定しておきます。


後は、普通にアプリを作って確認。


以下、サンプルです。
まず、サービス定義。

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

namespace Gsf.Samples.WCF
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        string SayHello(string name);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace Gsf.Samples.WCF
{
    public class MyService : IMyService
    {
        public string SayHello(string name)
        {
            return string.Format("Hello {0}", name);
        }
    }
}


次にホストアプリ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

namespace Gsf.Samples.WCF
{
    class Program
    {
        static void Main()
        {
            using (var host = new ServiceHost(typeof(MyService)))
            {
                host.Open();

                Console.WriteLine("サービスが開始されました。");
                Console.WriteLine("press <ENTER> to exit...");
                Console.ReadLine();

                host.Close();
            }
        }
    }
}

ホスト側のアプリケーション構成ファイル。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Gsf.Samples.WCF.MyService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8091/WCFSample011/MyService"/>
          </baseAddresses>
        </host>
        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="Gsf.Samples.WCF.IMyService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>


次にクライアントアプリ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.ServiceModel;

namespace Client
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            lblResult.ResetText();
            ActiveControl = btnCallServiceMethod;
        }

        private void btnCallServiceMethod_Click(object sender, EventArgs e)
        {
            var client = new MyServiceRef.MyServiceClient();
            try
            {
                lblResult.Text = client.SayHello("WCF Study");
            }
            catch (CommunicationException ex)
            {
                lblResult.Text = ex.Message;
                client.Abort();
            }
            finally
            {
                if (client.State != CommunicationState.Closed)
                {
                    client.Close();
                }
            }
        }
    }
}

クライアント側のアプリケーション構成ファイル。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>
        <sources>
            <source name="System.ServiceModel.MessageLogging" switchValue="Information,ActivityTracing">
                <listeners>
                    <add name="ServiceModelMessageLoggingListener">
                        <filter type="" />
                    </add>
                </listeners>
            </source>
        </sources>
        <sharedListeners>
            <add initializeData="D:\Tmp\app_messages.svclog"
                 type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                 name="ServiceModelMessageLoggingListener" 
                 traceOutputOptions="LogicalOperationStack, DateTime">
                <filter type="" />
            </add>
        </sharedListeners>
    </system.diagnostics>
    <system.serviceModel>
        <diagnostics>
            <!-- ロギングするメッセージの設定 -->
            <!--   logEntireMessageをtrueにするとSOAPメッセージの本文も出力される。-->
            <!--   logMessagesAtServiceLevelをtrueにすると暗号化前のメッセージがログに出力される。-->
            <messageLogging logEntireMessage="true" 
                            logMalformedMessages="true"
                            logMessagesAtServiceLevel="true" 
                            logMessagesAtTransportLevel="false" />
        </diagnostics>
        <client>
            <endpoint address="http://localhost:8091/WCFSample011/MyService"
                      binding="basicHttpBinding"
                      contract="MyServiceRef.IMyService" />
        </client>
    </system.serviceModel>
</configuration>


実行すると、app.config側で指定したログ出力先にログファイルができています。

このファイルを開くと、「Service Trace Viewer」というアプリが起動します。
WCFでは、このアプリを利用してログを確認できます。


左のエリアから、アクティビティを選択すると該当するデータが右に表示されます。
今回は、一回呼び出しただけなので、メッセージは2つだけとなっています。


一つ目を選択すると、クライアントからサービス側にデータが渡っていることが確認できます。

<MessageLogTraceRecord>
        ・・・省略・・・
        <s:Body>
            <SayHello xmlns="http://tempuri.org/">
                <name>WCF Study</name>
            </SayHello>
        </s:Body>
    </s:Envelope>
</MessageLogTraceRecord>

二つ目を選択すると、サービス側からクライアント側にデータが送られてきている事が確認できます。

<MessageLogTraceRecord>
        ・・・省略・・・
        <s:Body>
            <SayHelloResponse xmlns="http://tempuri.org/">
                <SayHelloResult>Hello WCF Study</SayHelloResult>
            </SayHelloResponse>
        </s:Body>
    </s:Envelope>
</MessageLogTraceRecord>

サンプルは以下の場所にアップしてあります。
https://sites.google.com/site/gsfzero1/Home/WCFSample-011.zip?attredirects=0&d=1


================================
過去の記事については、以下のページからご参照下さい。