.NET Remotingの追跡サービスと独自の追跡ハンドラの実装はじめに追跡サービス(Tracking Service)とは、その名前から想像されるように、オブジェクトのライフサイクルに関係するさまざまな活動を追跡するものです。このサービスは.NET Remotingフレームワークの一部なので、.NET Remotingの概念を復習しておきましょう。 .NET RemotingMicrosoftの.NETフレームワークは、アプリケーションドメイン内のクライアントから別のアプリケーションドメイン内のオブジェクトにアクセスする仕組みを提供しています。これを可能にするのが.NET Remotingです。 .NET Remotingは非常に柔軟性の高いテクノロジであり、クライアントとサーバーがどこにあっても相互に通信できるようにします。クライアントとサーバーの場所は、同じコンピュータ上でも、同じネットワーク上の別のコンピュータでも、海を隔てた別の国のコンピュータでもかまいません。.NET Remotingのサービスやインフラストラクチャコンポーネントを利用することにより、アプリケーション開発者は複雑な要素を意識せずに済みます。 .NET Remotingでは各種のプロトコルやシリアル化形式、設定情報を使用できます。また.NET Remotingパイプライン内に独自の「フック」を設ければ、リモートフレームワークの既定の動作をカスタマイズすることもできます(追跡サービスは、こうしたフックの一例です)。 では.NET Remotingの仕組みはどうなっているのでしょうか。.NET Remotingの概念の一部は、従来の分散テクノロジ(DCOM、CORBAなど)から借りてきたものです。まず明確にしておきたいのは、.NET Remotingでは、オブジェクトは何らかの「リスナプロセス」を通じて外部に公開されるという点です。このリスナプロセスはコンソールアプリケーションかもしれませんし、WinFormアプリケーションやWindowsサービス、あるいはIISということもあります。リスナプロセスは、プログラムまたは設定ファイルを通じて公開されるオブジェクトを指定します。オブジェクトが公開されている場合、クライアントアプリケーションはリスナプロセスに接続してオブジェクトの生成を要求し、リスナプロセスは生成したオブジェクトをクライアントに返します。クライアントとサーバーのアプリケーションドメイン間の通信は、エンコードされたデータストリームをチャネル上で送受信することによって行われます。 チャネルチャネルの基本的な目的は、データをある場所から別の場所へ転送することです。.NETには既定で2つのチャネルが用意されています。1つはHTTPチャネル(System.Runtime.Remoting.Channels.Http)で、もう1つはTCPチャネル(System.Runtime.Remoting.Channels.Tcp)です。 TCPチャネルはHTTPチャネルよりも高速で、バイナリデータの転送に向いています。一方、HTTPチャネルはファイアウォールやインターネットを経由するときに適しています。使用できるのは、これらのチャネルに限りません。独自のチャネルを作成して.NET Remotingに組み込むこともできます。 フォーマッタフォーマッタとは、データやメッセージの体裁を送信用に整えるものです。フォーマットされたデータ/メッセージは、所定のチャネルを用いて他のアプリケーションドメインに転送されます。.NETには既定で2つのフォーマッタが用意されています。1つはSoapフォーマッタ(System.Runtime.Serialization.Formatters.Soap)で、もう1つはBinaryフォーマッタ(System.Runtime.Serialization.Formatters.Binary)です。 SoapフォーマッタはメッセージをSoap 1.1仕様に基づいてフォーマットし、Binaryフォーマッタはメッセージを純粋なバイナリ形式でフォーマットします。 リモート処理オブジェクトの種類.NET Remotingは2種類のオブジェクトをサポートしています。1つはサーバーアクティブ化オブジェクト(「既知のオブジェクト」とも呼ばれます)で、もう1つはクライアントアクティブ化オブジェクトです。 サーバーアクティブ化オブジェクト サーバーアクティブ化オブジェクトは、その名が示すとおり、サーバーによって生成され、その有効期間もサーバーによって管理されます。ここでポイントとなるのは、クライアントが この動作から1つ導かれることがあります。クライアントが サーバーアクティブ化オブジェクトは、2つのモードでアクティブにできます。
クライアントアクティブ化オブジェクト クライアントアクティブ化オブジェクトは、サーバーによって生成され、その有効期間はクライアントによって管理されます。サーバーアクティブ化オブジェクトとは対照的に、クライアントアクティブ化オブジェクトは、クライアントが 設定他の.NETテクノロジと同様、.NET Remotingも、その動作のために設定情報が必要です。リモート処理アプリケーションは、プログラムまたは.configファイルを通じて設定することができます。本稿では、.configファイルについて説明します。 .NET Remotingの設定情報は、次のXML形式の <configuration> <System.Runtime.Remoting> <application> </application> </System.Runtime.Remoting> </configuration> サーバーアクティブ化オブジェクトを公開する場合は、次の例のような <configuration> <system.runtime.remoting> <application> <service> <wellknown mode="SingleCall" type="MyObjects.Customer, MyObjects" objectUri="Customer"/> </service> <channels> <channel ref="tcp" port="1234"/> </channels> </application> </system.runtime.remoting> </configuration> この設定情報では 個々のサーバーアクティブ化オブジェクトについて、固有の クライアント側の対応する.configファイルは次のようになります。 <configuration> <system.runtime.remoting> <application name="MyClient"> <client> <wellknown type="MyObjects.Customer,MyObjects" url="tcp://localhost:1234/Customer"/> </client> <channels> <channel ref="tcp"/> </channels> </application> </system.runtime.remoting> </configuration> クライアント側の設定ファイルは、サーバー側の設定ファイルと若干異なります。ここでは、 クライアントアクティブ化オブジェクトの場合は、 <system.runtime.remoting> <application name="Data"> <service> <activated type="MyObjects.Customer,MyObjects"/> </service> <channels> <channel ref="tcp" port="1234"/> </channels> </application> </system.runtime.remoting> </configuration> クライアント側の対応する設定ファイルは次のようになります。 <configuration> <system.runtime.remoting> <application name="Data"> <client url="tcp://localhost:1234/Data"> <!-- You can only use one url @ a time --> <activated type="MyObjects.Customer,MyObjects"/> </client> <channels> <channel ref="tcp"/> </channels> </application> </system.runtime.remoting> </configuration> .NET追跡サービス.NET追跡サービスでは、.NET Remotingインフラストラクチャに独自のコードを組み込むことで、オブジェクトのマーシャリングに関する通知を受け取ることができます。例えば、.NET追跡サービスは、オブジェクトが別のアプリケーションドメインにマーシャリングされたときなどにイベントを発生させます。.NET追跡サービスが発生させるイベントの中には、MBR(Marshal-by-Ref)オブジェクトのマーシャリングプロセスに関係するイベントがあります。これらのイベントに関与するコンポーネントは、.NET Remotingインフラストラクチャに登録することでイベントを受け取ることができます。 .NET追跡サービスを利用すると、動作中のアプリケーションを自由に監視し、アプリケーションパターンを分析して、一定の負荷がかかったときの挙動やピーク時のオブジェクト数などを調べることができます。これらのイベントによって、.NET追跡サービスから有用な多くの情報が得られます。この情報をログに記録して、傾向分析やその他の調査に使うことができます。 .NET追跡サービスの唯一の制約は、「クライアントアクティブ化オブジェクトでのみ動作する」ことです。 .NETの他のプラグ可能アーキテクチャと同様、.NET追跡サービスを利用するコンポーネントの作成はとても簡単です。必要な作業は次の2ステップだけです。
以下、詳しく説明します。 ITrackingHandlerインターフェイス
このインターフェイスをクラス内で実装するときは次のようにします。 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 } } このコードを見ると、メソッド TrackingServicesヘルパークラス
次のコードは、.NET Remotingインフラストラクチャに独自の追跡ハンドラを登録する方法を示しています。
MyTrackingHandler objHandler = new MyTrackingHandler() ;
TrackingServices.RegisterTrackingHandler(objHandler) ;
ハンドラを登録すると、イベントが送られてくるようになります。イベントの受信を止めるには、次のように TrackingServices.UnregisterTrackingHandler(objHandler) ; 登録済みの追跡ハンドラを列挙するのも簡単です。次のコードは、現在登録されている追跡ハンドラの一覧を取得し、すべてのハンドラをスキャンします。 ITrackingHandler[] objHandlers = TrackingServices.RegisteredHandlers ; foreach (ITrackingHandler objHandler in objHandlers) { // Use objHandler here } 実用的なことをやってみようカスタム追跡ハンドラの作成に必要な基礎を学んだところで、次に実際のハンドラを書いてみましょう。 ここで作成するカスタム追跡ハンドラは、すべての情報をSQL Serverデータベースに記録します。これにより、データを分析し、アプリケーションのオブジェクト生成とマーシャリングを監視することができます。このデータに基づいて分析される項目は次のようなものです。
サンプルコードに含まれるプロジェクトは次のとおりです。
上記のプロジェクトの他に、「database.sql」ファイルが存在します。このファイルには、SQL Serverデータベース、データベーステーブル、およびストアドプロシージャを作成するSQLスクリプトが含まれています。 MyObjects.DLL MyObjectsアセンブリには 以下は、 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アセンブリには、 以下は、このカスタム追跡ハンドラのコードです。 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] = "" ; } } TrackingListener.exe「TrackingListener.exe」はサーバー側のリスナです。これが.NET Remotingパイプライン内に追跡ハンドラを作成してインストールし、オブジェクト生成要求を満たします。 以下は、 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() ; } } このコードはとても簡単です。 リスナプロセスの設定情報は「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」は、サーバー上で活動を起こすために 追跡ハンドラのテスト追跡ハンドラをテストするには、以下の作業を行う必要があります。 まず、データベーススクリプトを実行してデータベースと関連データベースオブジェクトを作成します。本稿では、SQL Serverとリスナが同じコンピュータ上で動作すると仮定していますが、SQL Serverが別のコンピュータで動いている場合は、追跡ハンドラクラス内の接続文字列を変更する必要があります。 もっとよい手として、接続文字列をリスナプロセスの.configファイルに入れておき、リスナからコンストラクタ経由でハンドラに渡すという方法も考えられます。 サンプルコードの解凍先ディレクトリからリスナプロセス「TrackingListener.exe」を実行します。リスナプロセスによって所定のチャネルが登録され、コンソールウィンドウが開きます。これで 「TrackingClient.exe」を起動し、ダイアログボックスの[Create object]ボタンをクリックします。これでCustomerインスタンスが生成され、.NET Remotingインフラストラクチャから追跡ハンドラの 切断イベントをテストするため、5分ほど待ちます(クライアントアクティブ化オブジェクトの場合は5分が既定のリース期限なので、それを経過するとプロキシからオブジェクトが切断されます)。すると、筆者のコンピュータでは、データベースの内容が次のようになりました。 なお、このデータベーステーブルの「activity」列には「M」、「U」、「D」という値が格納されます。これらの値は、発生した活動(M=マーシャリング、U=マーシャリング解除、D=切断)を表します。 結論.NETフレームワークとその関連テクノロジを利用すると、処理パイプライン内に独自のフックを設けることができます。.NET追跡ハンドラは、そうしたフックの例です。本稿で見たように、追跡ハンドラを書くのはとても簡単ですが、.NET Remoting、各種オブジェクト、設定ファイル、その他リモート処理要素についての基礎的な知識が必要です。 著者紹介Mansoor Ahmed Siddiqui(Mansoor Ahmed Siddiqui)
アメリカで活動するソフトウェアコンサルタント兼テクニカルライター。コンピュータ工学の学位を持ち、1997年からソフトウェア開発に携わる。専門分野はWebベースアプリケーション、クライアント/サーバーアプリケーション、およびn層アプリケーションの設計開発で、特に中間層とWin32プログラミングを得意とする。
Microsoft. NET Framework、ASP.NET、C#、Visual Studio .NET、Webサービス、ADO.NET、ASP、JavaScript、eXtensible Markup Language(XML)、Simple Object Access Protocol(SOAP)、Visual C++、Microsoft Foundation Class Library(MFC)、Active Template Library(ATL)、Visual Basic 6.0、ActiveX Data Objects(ADO)、COM/DCOM/COM+、Microsoft Transaction Server(MTS)、Microsoft Message Queue(MSMQ)、SQL Server 7.0/2000、OMGのUnified Modeling Language(UML)、Rational Software Corp.のRational Rose、Java、Java Server Page(JSP)、サーブレット、Enterprise JavaBeans(EJB)、Java 2 Platform Enterprise Edition(J2EE)についての専門知識を持つ。 現在はVisual Studio 7.0とMicrosoft .NETプラットフォームを使用。MCSD資格のほか、さまざまな言語のBrainbench認定資格を持つ。 テクニカルライティングの他には、音楽鑑賞、水泳、クリケット、ビリヤード、友人との付き合いを楽しむ。連絡先はmansoorasiddiqui@hotmail.comおよびICQ 151707288。 |