リモート処理の例 : 非同期リモート処理
リモート処理のシナリオでの非同期プログラミングのサンプル アプリケーションを次に示します。この例では、最初にリモート オブジェクトに対する同期デリゲートを作成し、応答を待機するスレッドを説明するためにこれを呼び出します。次に非同期デリゲートと ManualResetEvent オブジェクトを使用してリモート オブジェクトのメソッドを呼び出し、応答を待機します。
このアプリケーションは、1 台のコンピュータ上で、またはネットワーク経由で実行されます。このアプリケーションをネットワーク経由で実行するには、クライアント構成の "localhost" をリモート コンピュータの名前で置き換える必要があります。
注意
.NET Framework リモート処理では、既定では認証または暗号化を行いません。したがって、クライアントやサーバーとリモートで対話する前に、ID の確認に必要な手順をすべて実行することをお勧めします。.NET Framework リモート処理アプリケーションの実行には、FullTrust アクセス許可が必要です。そのため、承認されていないクライアントがサーバー上でのアクセスを許可された場合は、完全な信頼を与えられているものとして、コードを実行できてしまいます。インターネット インフォメーション サービス (IIS : Internet Information Services) でリモート型をホストするか、リモート型をホストするためのカスタム チャネル シンク ペアを構築することによって、常にエンドポイントを認証し、通信ストリームを暗号化してください。
このサンプルをコンパイルするには
コマンド プロンプトで次のコマンドを入力します。
csc /t:library /out:ServiceClass.dll ServiceClass.cs
vbc -r:ServiceClass.dll RemoteAsyncVB.vb
csc /r:ServiceClass.dll Server.cs
csc /r:ServiceClass.dll RemoteAsync.cs
同じディレクトリを指す 2 つのコマンド プロンプトを開きます。一方のコマンド プロンプトでは、「server」と入力します。もう一方のコマンド プロンプトでは、「RemoteAsyncVB」または「RemoteAsync」と入力します。
RemoteAsyncVB.vb
Imports System
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Messaging
Imports System.Threading
Imports Microsoft.VisualBasic
Public Class RemotingDelegates
Public Shared e As ManualResetEvent
' Declares two delegates, each of which represents
' a function that returns a string. The names are strictly
' for clarity in the code – there is no difference between
' the two delegates. (In fact, the same delegate type
' could be used for both synchronous and asynchronous
' calls.)
Delegate Function RemoteSyncDelegate() As String
Delegate Function RemoteAsyncDelegate() As String
<MTAThread()> _
Public Shared Sub Main()
e = New ManualResetEvent(False)
Console.WriteLine("Remote synchronous and asynchronous delegates.")
Console.WriteLine(New [String]("-"c, 80))
Console.WriteLine()
' Configuration is required in a remoting scenario, for both
' synchronous and asynchronous programming. You can use either
' a configuration file, as shown here, or method calls.
RemotingConfiguration.Configure("SyncAsync.exe.config")
' The remaining steps are identical to single-
' AppDomain programming. First, create the service class. In this
' case, the object is actually created on the server, and only a
' single instance is created. (See the server configuration file,
' ServerVB.exe.config.)
Dim obj As New ServiceClass()
If RemotingServices.IsTransparentProxy(obj) Then
Console.WriteLine("It's remote.")
Else
Console.WriteLine("Uh-oh. It's local.")
Return
End If
' This delegate is a remote synchronous delegate.
Dim RemoteSyncDel As New RemoteSyncDelegate(AddressOf obj.VoidCall)
' When invoked, program execution waits until the method returns.
' The return value is displayed to the console.
Console.WriteLine(RemoteSyncDel())
' Next, the remote asynchronous call.
' First, create an AsyncCallback delegate that represents
' the method to be executed when the asynchronous method has finished
' executing.
Dim RemoteCallback As New AsyncCallback(AddressOf RemotingDelegates.OurRemoteAsyncCallBack)
' Second, create the delegate to the method to
' executed asynchronously.
Dim RemoteDel As New RemoteAsyncDelegate(AddressOf obj.TimeConsumingRemoteCall)
' Finally, begin the method invocation.
' Note that execution on this thread continues immediately without
' waiting for the return of the method call.
Dim RemAr As IAsyncResult = RemoteDel.BeginInvoke(RemoteCallback, Nothing)
' If you want to block on the return:
' RemAr.AsyncWaitHandle.WaitOne();
' RemoteCallback(RemAr);
' Provide some feedback to indicate continued processing prior to
' the return of the asynchronous call.
Dim count As Integer = 0
While Not RemAr.IsCompleted
Console.Write("Not completed -- " & count & vbCr)
count += 1
' The callback is made on a low priority worker thread. Blocking
' the foreground thread for a millisecond each time enables the
' callback to execute.
Thread.Sleep(New TimeSpan(TimeSpan.TicksPerMillisecond))
End While
Console.WriteLine(vbCrLf & "Completed.")
End Sub 'Main
' This is the method that the server calls when asynchronous
' execution is complete. The method is represented by an AsyncCallBack
' delegate, which determines its signature.
Public Shared Sub OurRemoteAsyncCallBack(ByVal iar As IAsyncResult)
' The following nested cast looks confusing, because of the nature
' of the Visual Basic casting operator, CType. Note that you could
' get the same result with two separate casts:
' Dim ar As AsyncResult = CType(iar, AsyncResult)
' Dim del As RemoteAsyncDelegate = CType(ar.AsyncDelegate, RemoteAsyncDelegate)
' The first line casts the interface to an AsyncResult object to
' access the AsyncDelegate property (in the second
' line). This property returns a reference to the original delegate,
' which must be cast back to its own type.
Dim del As RemoteAsyncDelegate = CType(CType(iar, AsyncResult).AsyncDelegate, RemoteAsyncDelegate)
Console.WriteLine(vbCrLf & "Result of the remote AsyncCallBack: " & del.EndInvoke(iar))
Return
End Sub 'OurRemoteAsyncCallBack
End Class 'RemotingDelegates
RemoteAsync.cs
using System;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels;
using System.Threading;
public class RemotingDelegates : MarshalByRefObject{
public static ManualResetEvent e;
public delegate string RemoteSyncDelegate();
public delegate string RemoteAsyncDelegate();
// This is the call that the AsyncCallBack delegate references.
[OneWayAttribute]
public void OurRemoteAsyncCallBack(IAsyncResult ar){
RemoteAsyncDelegate del = (RemoteAsyncDelegate)((AsyncResult)ar).AsyncDelegate;
Console.WriteLine("\r\n**SUCCESS**: Result of the remote AsyncCallBack: " + del.EndInvoke(ar) );
// Signal the thread.
e.Set();
return;
}
public static void Main(string[] Args){
// IMPORTANT: .NET Framework remoting does not remote
// static members. This class must be an instance before
// the callback from the asynchronous invocation can reach this client.
RemotingDelegates HandlerInstance = new RemotingDelegates();
HandlerInstance.Run();
}
public void Run(){
// Enable this and the e.WaitOne call at the bottom if you
// are going to make more than one asynchronous call.
e = new ManualResetEvent(false);
Console.WriteLine("Remote synchronous and asynchronous delegates.");
Console.WriteLine(new String('-',80));
Console.WriteLine();
// This is the only thing you must do in a remoting scenario
// for either synchronous or asynchronous programming
// configuration.
RemotingConfiguration.Configure("SyncAsync.exe.config");
// The remaining steps are identical to single-
// AppDomain programming.
ServiceClass obj = new ServiceClass();
// This delegate is a remote synchronous delegate.
RemoteSyncDelegate Remotesyncdel = new RemoteSyncDelegate(obj.VoidCall);
// When invoked, program execution waits until the method returns.
// This delegate can be passed to another application domain
// to be used as a callback to the obj.VoidCall method.
Console.WriteLine(Remotesyncdel());
// This delegate is an asynchronous delegate. Two delegates must
// be created. The first is the system-defined AsyncCallback
// delegate, which references the method that the remote type calls
// back when the remote method is done.
AsyncCallback RemoteCallback = new AsyncCallback(this.OurRemoteAsyncCallBack);
// Create the delegate to the remote method you want to use
// asynchronously.
RemoteAsyncDelegate RemoteDel = new RemoteAsyncDelegate(obj.TimeConsumingRemoteCall);
// Start the method call. Note that execution on this
// thread continues immediately without waiting for the return of
// the method call.
IAsyncResult RemAr = RemoteDel.BeginInvoke(RemoteCallback, null);
// If you want to stop execution on this thread to
// wait for the return from this specific call, retrieve the
// IAsyncResult returned from the BeginIvoke call, obtain its
// WaitHandle, and pause the thread, such as the next line:
// RemAr.AsyncWaitHandle.WaitOne();
// To wait in general, if, for example, many asynchronous calls
// have been made and you want notification of any of them, or,
// like this example, because the application domain can be
// recycled before the callback can print the result to the
// console.
//e.WaitOne();
// This simulates some other work going on in this thread while the
// async call has not returned.
int count = 0;
while(!RemAr.IsCompleted){
Console.Write("\rNot completed: " + (++count).ToString());
// Make sure the callback thread can invoke callback.
Thread.Sleep(1);
}
}
}
Server.cs
using System;
using System.Runtime.Remoting;
public class Server{
public static void Main(){
RemotingConfiguration.Configure("server.exe.config");
Console.WriteLine("Waiting...");
Console.ReadLine();
}
}
ServiceClass.cs
using System;
using System.Runtime.Remoting;
public class ServiceClass : MarshalByRefObject{
public ServiceClass() {
Console.WriteLine("ServiceClass created.");
}
public string VoidCall(){
Console.WriteLine("VoidCall called.");
return "You are calling the void call on the ServiceClass.";
}
public int GetServiceCode(){
return this.GetHashCode();
}
public string TimeConsumingRemoteCall(){
Console.WriteLine("TimeConsumingRemoteCall called.");
for(int i = 0; i < 20000; i++){
Console.Write("Counting: " + i.ToString());
Console.Write("\r");
}
return "This is a time-consuming call.";
}
}
Server.exe.config
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="ServiceClass, ServiceClass"
mode="Singleton"
objectUri="ServiceClass.rem"
/>
</service>
<channels>
<channel
ref="http"
port="8080"
/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
SyncAsync.exe.config
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="ServiceClass, ServiceClass"
url="https://localhost:8080/ServiceClass.rem"
/>
</client>
<channels>
<channel
ref="http"
port="0"
/>
</channels>
</application>
</system.runtime.remoting>
</configuration>