リモート処理可能オブジェクト
リモート処理可能オブジェクトは、広範囲な分散環境でも完全に動作できるオブジェクトです。リモート処理可能オブジェクトには、主として次の 2 種類があります。
- 値渡しでマーシャリングされるオブジェクト。これはアプリケーション ドメインの外部にコピーされて渡されます。
- 参照渡しでマーシャリングされるオブジェクト。これに対してはプロキシが生成され、クライアントによってオブジェクトへのリモート アクセスに使用されます。
値渡しでマーシャリングされるオブジェクト
値渡しでマーシャリングされる (MBV: Marshal-By-Value) オブジェクトは、独自のシリアル化を実装する ISerializable による実装、または、システムにオブジェクトの自動的シリアル化を指示する SerializableAttribute による修飾、のいずれかの方法でシリアル化規則を宣言しますが、MarshalByRefObject を拡張することはありません。リモート処理システムはこれらのオブジェクトの完全なコピーを生成し、そのコピーを呼び出し元のアプリケーション ドメインに渡します。コピーが呼び出し元のアプリケーション ドメインに渡された後は、そのコピーに対する呼び出しはそのコピーに直接実行されます。また、引数として渡された MBV オブジェクトも値渡しになります。アプリケーション境界またはコンテキスト境界を越えてクラスのインスタンスを値渡しするときは、SerializableAttribute 属性を宣言すること、または ISerializable を実装すること以外、特に何も行う必要はありません。
メモ .NET Framework Version 1.1 以降では、リモート処理インフラストラクチャはサーバー上での特定の型の逆シリアル化を自動的には実行しません。これに該当するシナリオでは、サーバーの逆シリアル化のレベルを Full に設定して、サーバーが逆シリアル化を行い、MBV オブジェクトを使用できるようにする必要があります。詳細については、「.NET リモート処理での自動逆シリアル化」を参照してください。
MBV オブジェクトは、パフォーマンスや処理上の理由から、オブジェクトや実行できる機能の完全な状態をターゲットのアプリケーション ドメインに移動することが必要な場合に使用します。多くのシナリオでは、MBV オブジェクトを使用することで、ネットワーク境界、プロセス境界、アプリケーション ドメイン境界を越えて行われる、時間がかかり、リソースを消費するラウンドトリップを減らすことができます。MBV オブジェクトは、オブジェクトの生成元であるアプリケーション ドメインから、直接使用することもできます。この場合は、マーシャリングが行われないため、コピーも生成されず、アクセス効率が大幅に向上します。
その一方で、公開するオブジェクトが巨大な場合、完全なコピーを混雑したネットワーク内でやり取りすることは、アプリケーションにとって必ずしも良い選択とは言えません。そのうえ、コピーされたオブジェクトの状態を変更しても、元のアプリケーション ドメインにある元のオブジェクトには反映されません。抽象的なレベルでは、このシナリオは静的 HTML ページがクライアント ブラウザから要求された場合のシナリオに似ています。サーバーはファイルをコピーしてストリームに書き込み、送出後は一切関与しません。それ以降の要求は、単に別のコピーに対する別の要求として処理されます。
リモート処理システムでは、シリアル化可能なオブジェクトが広範に利用されます。リモート処理システムで ObjRef クラスによって表される、別のアプリケーション ドメインでのオブジェクトへの参照は、参照自身がシリアル化可能です。したがってリモート処理システムはこの参照を正しくコピーして、要求に送信できます。IMessage を実装したメッセージ オブジェクトの場合も同様です。これは、これらのメッセージ オブジェクトが、呼び出し情報やその他のオブジェクト参照に必要な情報の汎用のコンテナであるためです。また、単純にデータを転送するオブジェクトも、多くの場合シリアル化できるオブジェクトです。たとえば、DataSet は ISerializable を実装した MarshalByValueComponent を拡張します。
ユーザー定義例外のリモート処理
システム定義の例外は、すべて値渡しでマーシャリングされる型であり、ISerializable インターフェイスを実装しています。リモート オブジェクトがこの例外をスローするとき、リモート構成で許可されていれば、例外は自動的に呼び出し元にコピーされます。.NET Framework の Version 1.1 以降では、例外を呼び出し元に送る機能を有効にするには、<customErrors> 要素を off に設定する必要があります。
リモート オブジェクトによってスローされ、リモートの呼び出し元によってキャッチされる独自の例外型を作成するには、次の指示に従う必要があります。
- ISerializable を実装します。
- SerializableAttribute 属性をクラスに含めます。
- SerializationInfo オブジェクトと StreamingContext オブジェクトをパラメータとして受け取る逆シリアル化コンストラクタを実装します。
リモート サーバー オブジェクトによってスローされたときに、構成が適切であれば、呼び出し元にコピーバックされる簡単な実装のコード例 (C#) を次に示します。
[Serializable]
public class CustomRemotableException : RemotingException, ISerializable {
private string _internalMessage;
public CustomRemotableException(){
_internalMessage = String.Empty;
}
public CustomRemotableException(string message){
_internalMessage = message;
}
public CustomRemotableException(SerializationInfo info, StreamingContext context){
_internalMessage = (string)info.GetValue("_internalMessage", typeof(string));
}
public override void GetObjectData(SerializationInfo info, StreamingContext context){
info.AddValue("_internalMessage", _internalMessage);
}
// Returns the exception information.
public override string Message{
get {
return "This is your custom remotable exception returning: \""
+ _internalMessage
+ "\"";
}
}
}
参照渡しでマーシャリングされるオブジェクト
参照渡しでマーシャリングされる (MBR: Marshal-By-Reference) オブジェクトはリモート処理可能オブジェクトであり、System.MarshalByRefObject の拡張はできます。宣言したアクティベーションの種類に応じて、クライアントがそのアプリケーション ドメインで MBR オブジェクトのインスタンスを生成すると、.NET リモート処理インフラストラクチャが、呼び出し元のアプリケーション ドメイン内に MBR オブジェクトの代理のプロキシ オブジェクトを生成し、そのプロキシに対する参照を呼び出し元に返します。次に、クライアントはプロキシへの呼び出しを実行します。リモート処理はこれらの呼び出しをマーシャリングし、元のアプリケーション ドメインに返送し、実際のオブジェクトに対する呼び出しを行います。
メモ クライアントが MBR オブジェクトと同じアプリケーション ドメインにある場合、インフラストラクチャは MBR オブジェクトに対する直接の参照をクライアントに返し、マーシャリングのオーバーヘッドの発生を防ぎます。
MarshalByRefObject は、パラメータとして渡された場合は、呼び出しを受信すると別のアプリケーション ドメインでプロキシになります。MBR の戻り値と out パラメータは、同じ方法で機能します。
メモ .NET Framework Version 1.1 以降では、リモート処理インフラストラクチャはサーバー上での特定の型の逆シリアル化を自動的には実行しません。たとえば、パラメータとして渡される MBR オブジェクトがサポートされるようにするには、サーバーの逆シリアル化のレベルを Full に設定して、サーバーが逆シリアル化を行い、MBR パラメータを使用できるようにする必要があります。このシナリオや他のシナリオの詳細については、「.NET リモート処理での自動逆シリアル化」を参照してください。
MBR オブジェクトを使用するのは、オブジェクトや実行できる機能の状態を生成されたアプリケーション ドメイン内にとどめておく必要があるときです。たとえば、オペレーティング システム ハンドルとして使用する内部フィールドを持つオブジェクトは、MarshalByRefObject を拡張する必要があります。これは、オペレーティング システム ハンドルは、他のプロセスや他のコンピュータ内の他のアプリケーション ドメインでは意味がないためです。また、オブジェクトが極端に大きい場合、堅牢なサーバー上では問題ありませんが、33.6 kbps モデムで送信された場合は問題になる可能性があります。
コンテキスト バインド オブジェクト
コンテキスト バインド オブジェクトは System.ContextBoundObject クラスから継承された MBR オブジェクトで、このクラスは System.MarshalByRefObject から継承されています。コンテキストは、その内部にあるオブジェクトに対して実行時に高度な環境を提供する、アプリケーション ドメインの下位概念と考えることができます。たとえば、コンテキストは、オブジェクトが同時に複数のスレッドからアクセスされないことを保証できます。すべてのアプリケーション ドメインが、既定のコンテキストを持っています。ほとんどのマネージ コードは、同じアプリケーション ドメイン内でそのドメインの既定のコンテキストを使用してオブジェクトを生成したりメンバを直接呼び出したりするため、コンテキストに関連する問題が発生することはありません。ContextBoundObject から継承されたすべての型は、同じドメイン内または他のドメイン内にある他のコンテキストに対して、プロキシとして公開されます。
たとえば、ある型にメソッドがあり、このメソッドはトランザクションの一部であるため、それが生成されたコンテキスト固有の規則に限定されているとします。オブジェクトがそれ自体のコンテキストからアクセスされ、システムがそのオブジェクトとメソッドに関連付けられているトランザクションに対して規則を適用できるようにするには、この型を ContextBoundObject から継承する必要があります。ContextBoundObject が同じアプリケーション ドメインにある別のコンテキストから呼び出されると、呼び出し元に対してプロキシが生成されますが、コンテキスト間の通信はチャネル システムを通じて行われるのではないため、この状況での呼び出しの効率性が向上します。
各境界を越えるには処理時間が必要なため、サーバーをリモート処理可能オブジェクトのどの種類にするのかを決める前に、オブジェクトが越える境界を決める必要があります。特定のコンテキストに固有のオブジェクトだけが、そのコンテキストから直接アクセスできます。特定のアプリケーション ドメインに固有のオブジェクトにも同じことが当てはまります。いずれかのオブジェクトにリモートにアクセスするには、オブジェクト固有の境界の内部からサーバー オブジェクトを呼び出す前に、リモート処理システムがコンテキスト境界またはアプリケーション境界、またはその両方を正常に越える必要があります。オブジェクトを呼び出すときにコンテキストをチェックしなくてよい場合は、リモート型で ContextBoundObject を拡張しないようにする必要があります。この場合には、MarshalByRefObject の方がパフォーマンスが優れています。コンテキストのチェックが必要な場合は ContextBoundObject を拡張する必要がありますが、追加の境界はオブジェクトに対する呼び出しが行われる前に越える必要があります。
参照
リモート処理可能オブジェクトとリモート処理不可能オブジェクト | ContextBoundObject | リモート処理不可能オブジェクト