Freigeben über


Remotingbeispiel: Asynchrones Remoting

Mit der folgenden Beispielanwendung wird die asynchrone Programmierung in einem Remotingszenario veranschaulicht. Zunächst wird in diesem Beispiel ein synchroner Delegat zu einem Remoteobjekt erstellt und dann aufgerufen, um den Thread, der auf die Rückgabe wartet, darzustellen. Anschließend wird mithilfe asynchroner Delegaten und des ManualResetEvent-Objekts eine Remoteobjektmethode aufgerufen und auf die Antwort gewartet.

Diese Anwendung wird auf einem einzelnen Computer oder über ein Netzwerk ausgeführt. Wenn Sie die Anwendung über ein Netzwerk ausführen möchten, müssen Sie "localhost" in der Clientkonfiguration durch den Namen des Remotecomputers ersetzen.

Warnung

.NET Framework Remoting führt standardmäßig keine Authentifizierung oder Verschlüsselung aus. Daher empfiehlt es sich, alle erforderlichen Schritte auszuführen, um die Identität von Clients und Servern vor der Remoteinteraktion eindeutig zu bestimmen. Da für die Ausführung von .NET Framework Remoting-Anwendungen die Berechtigung FullTrust erforderlich ist, könnte ein nicht autorisierter Client, dem der Zugriff auf den Server gewährt wurde, Code so ausführen, als ob er vollständig vertrauenswürdig wäre. Authentifizieren Sie stets die Endpunkte, und verschlüsseln Sie die Kommunikationsstreams, entweder durch Hosten der Remotetypen in Internetinformationsdienste (Internet Information Services, IIS), oder indem Sie für diese Aufgabe ein benutzerdefiniertes Channelempfängerpaar erstellen.

So kompilieren Sie dieses Beispiel

  1. Geben Sie an der Eingabeaufforderung die folgenden Befehle ein:

    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. Öffnen Sie zwei Eingabeaufforderungen, die auf dasselbe Verzeichnis zeigen. Geben Sie an der einen Eingabeaufforderung server ein und an der anderen RemoteAsyncVB oder 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>

Siehe auch

Konzepte

Asynchrones Remoting

Weitere Ressourcen

Remotingbeispiele