SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

.NET Remotingの追跡サービスと独自の追跡ハンドラの実装

アプリケーションのオブジェクト生成とマーシャリングを監視する

.NET追跡サービス

 .NET追跡サービスでは、.NET Remotingインフラストラクチャに独自のコードを組み込むことで、オブジェクトのマーシャリングに関する通知を受け取ることができます。例えば、.NET追跡サービスは、オブジェクトが別のアプリケーションドメインにマーシャリングされたときなどにイベントを発生させます。.NET追跡サービスが発生させるイベントの中には、MBR(Marshal-by-Ref)オブジェクトのマーシャリングプロセスに関係するイベントがあります。これらのイベントに関与するコンポーネントは、.NET Remotingインフラストラクチャに登録することでイベントを受け取ることができます。

 .NET追跡サービスを利用すると、動作中のアプリケーションを自由に監視し、アプリケーションパターンを分析して、一定の負荷がかかったときの挙動やピーク時のオブジェクト数などを調べることができます。これらのイベントによって、.NET追跡サービスから有用な多くの情報が得られます。この情報をログに記録して、傾向分析やその他の調査に使うことができます。

 .NET追跡サービスの唯一の制約は、「クライアントアクティブ化オブジェクトでのみ動作する」ことです。

 .NETの他のプラグ可能アーキテクチャと同様、.NET追跡サービスを利用するコンポーネントの作成はとても簡単です。必要な作業は次の2ステップだけです。

  • ItrackingHandlerインターフェイスを実装する.NETクラスを作成する(このクラスを追跡ハンドラと呼ぶことにします)。
  • TrackingServicesクラスを使用して、このクラスを.NET Remotingインフラストラクチャに登録する。

 以下、詳しく説明します。

ITrackingHandlerインターフェイス

 ItrackingHandlerインターフェイスはSystem.Runtime.Remoting.Services名前空間に含まれます。このインターフェイスを実装するクラスを使えば、オブジェクトのマーシャリングイベントを受け取ることができます。このインターフェイスには次のメソッドがあります。

メソッド説明
MarshaledObjectマーシャリング対象オブジェクトを追跡ハンドラに知らせる。
UnmarshaledObjectマーシャリング解除対象オブジェクトを追跡ハンドラに知らせる。
DisconnectedObject切断対象オブジェクト(リース期限の切れたオブジェクトなど)を追跡ハンドラに知らせる。

 このインターフェイスをクラス内で実装するときは次のようにします。

Public class MyTrackingHandler : ITrackingHandler
{
   public void MarshaledObject(object obj, ObjRef or)
   {
     // Write your code here; most probably you would log the
     // information
   }

   public void UnmarshaledObject(object obj, ObjRef or)
   {
     // Write your code here; most probably you would log the
     // information
   }

   public void DisconnectedObject(object obj)
   {
     // Write your code here; most probably you would log the
     // information
   }
}

 このコードを見ると、メソッドMarshaledObjectUnmarshaledObjectが共に2つのパラメータ(objectObjRef)を取るのに対し、メソッドDisconnectedObjectはパラメータを1つ(object)しか取らないことが分かります。objectパラメータは、操作(マーシャリング、マーシャリング解除、切断)の対象となるオブジェクトの参照です。ObjRefパラメータは、クライアントアプリケーションでのプロキシ生成に必要なすべての情報が入っているオブジェクトの参照です。ObjRefの参照先オブジェクトには、サーバーオブジェクトの型、サーバー上のオブジェクト位置など、プロキシに必須の接続・転送関連の情報が含まれています。

TrackingServicesヘルパークラス

 TrackingServicesは、System.Runtime.Remoting.Services名前空間に含まれるヘルパークラスです。このクラスを使用して追跡ハンドラを操作します。以下に、このクラスの主なメソッドを示します。

メソッド説明
RegisterTrackingHandlerオブジェクトマーシャリングイベント対象ハンドラの一覧に追跡ハンドラを追加する。
UnregisterTrackingHandlerオブジェクトマーシャリングイベント対象ハンドラの一覧から追跡ハンドラを削除する。
RegisteredHandlersITrackingHandler型配列(現在登録されている追跡ハンドラの参照が入っている)を返す。

 次のコードは、.NET Remotingインフラストラクチャに独自の追跡ハンドラを登録する方法を示しています。

MyTrackingHandler objHandler = new MyTrackingHandler() ;
TrackingServices.RegisterTrackingHandler(objHandler) ;

 ハンドラを登録すると、イベントが送られてくるようになります。イベントの受信を止めるには、次のようにUnregisterTrackingHandlerメソッドを呼び出す必要があります(objHandlerが登録済みの追跡ハンドラを指しているものと仮定)。

TrackingServices.UnregisterTrackingHandler(objHandler) ;

 登録済みの追跡ハンドラを列挙するのも簡単です。次のコードは、現在登録されている追跡ハンドラの一覧を取得し、すべてのハンドラをスキャンします。

ITrackingHandler[] objHandlers = TrackingServices.RegisteredHandlers ;
foreach (ITrackingHandler objHandler  in objHandlers)
{
 // Use objHandler here
}

実用的なことをやってみよう

 カスタム追跡ハンドラの作成に必要な基礎を学んだところで、次に実際のハンドラを書いてみましょう。

 ここで作成するカスタム追跡ハンドラは、すべての情報をSQL Serverデータベースに記録します。これにより、データを分析し、アプリケーションのオブジェクト生成とマーシャリングを監視することができます。このデータに基づいて分析される項目は次のようなものです。

  • 一定期間中に操作(マーシャリング、マーシャリング解除、切断)の対象となったオブジェクトの数
  • 操作(マーシャリング、マーシャリング解除、切断)の対象となった各オブジェクトの状態
  • オブジェクトの生成に使われたURI

 サンプルコードに含まれるプロジェクトは次のとおりです。

  • MyObjects
  • TrackingHandlers
  • TrackingListener
  • TrackingClient

 上記のプロジェクトの他に、「database.sql」ファイルが存在します。このファイルには、SQL Serverデータベース、データベーステーブル、およびストアドプロシージャを作成するSQLスクリプトが含まれています。

MyObjects.DLL

 MyObjectsアセンブリにはCustomerというクラスが入っており、これが「TrackingListener.exe」でリモート処理クライアントに公開されます。

 Customerは、既定のToStringメソッドをオーバーライドした簡単なC#クラスです。これでオブジェクトの内部状態を取得できます。オブジェクトの状態を取得するには、[serializable]属性を用いてシリアル化可能とマークするか、Iserializableインターフェイスを実装する方法も考えられますが、ここではToStringメソッドを使うことにしました。

 以下は、Customerクラスのコードです。

public class Customer : MarshalByRefObject
{
  private string mstrName ;
  private string mstrAddress ;
  private string mstrPhone ;
  private DateTime mdtDOB ;
  public Customer()
  {
    //
    // TODO: Add constructor logic here
    //
    mstrName = "Mansoor Siddiqui" ;
    mstrAddress = "9999 Street, Apt 9, City State, USA" ;
    mstrPhone = "999-999-9999" ;
    mdtDOB = DateTime.Parse("01/01/1980") ;
   }

   public override string ToString()
   {
    string strState ;
    strState = Name + "|" + Address + "|" + Phone + "|" +
     DOB.ToLongDateString() ;
    return strState;
   }

   // Rest of the code has been skipped due to length
}

TrackingHandlers.DLL

 TrackingHandlersアセンブリには、MyTrackingHandlerというカスタム追跡ハンドラが入っています。前述のように、クラスを追跡ハンドラにするためにはItrackingHandlerインターフェイスを実装する必要があります。

 以下は、このカスタム追跡ハンドラのコードです。

public class MyTrackingHandler : ITrackingHandler
{
 private Database mobjDatabase ;
 private string mstrConnectionString ;

 public MyTrackingHandler()
 {
 //
 // TODO: Add constructor logic here
 //
  mobjDatabase = new Database() ;
  mstrConnectionString = "Data Source=localhost;uid=sa;pwd=;Initial
Catalog=TrackingDB" ;
 }

 public void MarshaledObject(object obj, ObjRef or)
 {
  object[] arrobjParameters = new Object[7] ;
  arrobjParameters[0] = "M" ;
  FillParameters(arrobjParameters, obj, or) ;
  mobjDatabase.ExecuteCommand(mstrConnectionString,
                           "usp_Add_TrackingLog", arrobjParameters) ;
 }

 public void DisconnectedObject(object obj)
 {
  object[] arrobjParameters = new Object[7] ;
  arrobjParameters[0] = "D" ;
  FillParameters(arrobjParameters, obj, null) ;
  mobjDatabase.ExecuteCommand(mstrConnectionString,
                            "usp_Add_TrackingLog", arrobjParameters) ;
 }

 public void UnmarshaledObject(object obj, ObjRef or)
 {
  object[] arrobjParameters = new Object[7] ;
  arrobjParameters[0] = "U" ;
  FillParameters(arrobjParameters, obj, or) ;
  mobjDatabase.ExecuteCommand(mstrConnectionString,
                             "usp_Add_TrackingLog", arrobjParameters);
 }

 private void FillParameters(object[] r_objArray, object obj,
ObjRef or)
 {
  r_objArray[1] = DateTime.Now ;
  r_objArray[2] = obj.ToString() ;
  r_objArray[3] = obj.GetHashCode() ;
  if (or != null)
  {
   if (or.TypeInfo != null)
   {
     r_objArray[4] = or.TypeInfo.ToString() ;
     r_objArray[5] = or.TypeInfo.TypeName ;
   }
   else
   {
     r_objArray[4] = "" ;
     r_objArray[5] = "" ;
   }

   if (or.URI != null)
     r_objArray[6] = or.URI.ToString() ;
   else
     r_objArray[6] = "" ;            
  }
  else
  {
   r_objArray[4] = "" ;
   r_objArray[5] = "" ;
   r_objArray[6] = "" ;
  }
 }

 MarshaledObjectUnmarshaledObjectDisconnectedObjectの3つのメソッドのコードによって情報がデータベースに保存されます。

TrackingListener.exe

 「TrackingListener.exe」はサーバー側のリスナです。これが.NET Remotingパイプライン内に追跡ハンドラを作成してインストールし、オブジェクト生成要求を満たします。

 以下は、TrackingListenerクラスのコードです。

class TrackingListener
{
  [STAThread]
  static void Main(string[] args)
  {
   RemotingConfiguration.Configure("TrackingListener.exe.config") ;
   TrackingServices.RegisterTrackingHandler(new
                        TrackingHandlers.MyTrackingHandler()) ;
   Console.WriteLine("Press enter to terminate ...") ;
   Console.ReadLine() ;
  }
}

 このコードはとても簡単です。RemotingConfiguration.Configureメソッドは、.configファイルを使用するアプリケーションから呼び出されます。このメソッドを呼び出すと、アプリケーションは設定ファイルに指定された情報に基づいて設定されます。

 リスナプロセスの設定情報は「TrackingListener.exe.config」ファイルに指定されています。以下は.configファイルの抜粋です。

<configuration>
 <system.runtime.remoting>
  <application name="TrackingTest">
   <service>
    <activated type="MyObjects.Customer, MyObjects"/>
   </service>
   <channels>
    <channel ref="tcp" port="9000"/>
   </channels>
  </application>
 </system.runtime.remoting>
</configuration>

 クライアントアクティブ化オブジェクトが公開され、ポート9000のTCPチャネルを通じてこのオブジェクトにアクセスできることが分かります。

TrackingClient.exe

 「TrackingClient.exe」は、サーバー上で活動を起こすためにCustomerクラスのインスタンスを生成するだけのWinFormアプリケーションです。

追跡ハンドラのテスト

 追跡ハンドラをテストするには、以下の作業を行う必要があります。

 まず、データベーススクリプトを実行してデータベースと関連データベースオブジェクトを作成します。本稿では、SQL Serverとリスナが同じコンピュータ上で動作すると仮定していますが、SQL Serverが別のコンピュータで動いている場合は、追跡ハンドラクラス内の接続文字列を変更する必要があります。

 もっとよい手として、接続文字列をリスナプロセスの.configファイルに入れておき、リスナからコンストラクタ経由でハンドラに渡すという方法も考えられます。

 サンプルコードの解凍先ディレクトリからリスナプロセス「TrackingListener.exe」を実行します。リスナプロセスによって所定のチャネルが登録され、コンソールウィンドウが開きます。これでCustomerオブジェクトを生成する準備ができました。

 「TrackingClient.exe」を起動し、ダイアログボックスの[Create object]ボタンをクリックします。これでCustomerインスタンスが生成され、.NET Remotingインフラストラクチャから追跡ハンドラのMarshaledObjectメソッドが呼び出されます。オブジェクトの生成に成功したら、データベースのTrackingLogテーブルを調べます。筆者のコンピュータでは、データベーステーブルの内容は次のようになりました。

 切断イベントをテストするため、5分ほど待ちます(クライアントアクティブ化オブジェクトの場合は5分が既定のリース期限なので、それを経過するとプロキシからオブジェクトが切断されます)。すると、筆者のコンピュータでは、データベースの内容が次のようになりました。

 なお、このデータベーステーブルの「activity」列には「M」、「U」、「D」という値が格納されます。これらの値は、発生した活動(M=マーシャリング、U=マーシャリング解除、D=切断)を表します。

結論

 .NETフレームワークとその関連テクノロジを利用すると、処理パイプライン内に独自のフックを設けることができます。.NET追跡ハンドラは、そうしたフックの例です。本稿で見たように、追跡ハンドラを書くのはとても簡単ですが、.NET Remoting、各種オブジェクト、設定ファイル、その他リモート処理要素についての基礎的な知識が必要です。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Mansoor Ahmed Siddiqui(Mansoor Ahmed Siddiqui)

アメリカで活動するソフトウェアコンサルタント兼テクニカルライター。コンピュータ工学の学位を持ち、1997年からソフトウェア開発に携わる。専門分野はWebベースアプリケーション、クライアント/サーバーアプリケーション、およびn層アプリケーションの設計開発で、特に中間層とWin32プログラミングを得意とする。Microsoft. NET Framework、ASP.NET、C#、Visual Studio ....

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/363 2006/08/22 15:45

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー