Export (0) Print
Expand All

Remoting Example: Asynchronous Remoting

This topic is specific to a legacy technology that is retained for backward compatibility with existing applications and is not recommended for new development. Distributed applications should now be developed using the  Windows Communication Foundation (WCF).

The following sample application demonstrates asynchronous programming in a remoting scenario. The example first creates a synchronous delegate to a remote object and invokes it to illustrate the thread waiting on the return. It then uses asynchronous delegates and a ManualResetEvent object to invoke a remote object method and wait for the response.

This application runs on a single computer or across a network. If you want to run this application over a network, you must replace "localhost" in the client configuration with the name of the remote computer.

0sa925ka.Caution(en-us,VS.100).gifCaution:
.NET Framework remoting does not do authentication or encryption by default. Therefore, it is recommended that you take all necessary steps to make certain of the identity of clients or servers before interacting with them remotely. Because .NET Framework remoting applications require FullTrust permissions to execute, if an unauthorized client were granted access on your server, the client could execute code as though it were fully trusted. Always authenticate your endpoints and encrypt the communication streams, either by hosting your remoted types in Internet Information Services (IIS) or by building a custom channel sink pair to do this work.

To compile this sample

  1. Type the following commands at the command prompt:

    csc /t:library ServiceClass.cs
    csc /r:ServiceClass.dll Server.cs
    csc /r:ServiceClass.dll Client.cs
    
  2. Open two command prompts that point to the same directory. In one, type server. In the other, type client.

ServiceClass

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

Imports System
Imports System.Runtime.Remoting

Public Class Server

    Public Shared Sub Main()
        RemotingConfiguration.Configure("server.exe.config", False)
        Console.WriteLine("Waiting...")
        Console.ReadLine()
    End Sub

End Class
using System;
using System.Runtime.Remoting;

public class Server
{
    public static void Main(string[] args)
    {
        RemotingConfiguration.Configure("server.exe.config", false);
        Console.WriteLine("Waiting...");
        Console.ReadLine();
    }
}

Server.exe.config

<?xml version="1.0" encoding="utf-8" ?>
<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>

Client

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using Shared;

public class Client : MarshalByRefObject
{
    public static ManualResetEvent e;

    // 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.

    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.
        Client clientApp = new Client();
        clientApp.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("Client.exe.config", false);

        // 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);
        }
    }
}

Client.exe.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <client>
        <wellknown 
           type="ServiceClass, ServiceClass"
           url="http://localhost:8080/ServiceClass.rem"
            />
      </client>
      <channels>
        <channel 
           ref="http" 
           port="0"
            />
      </channels>
    </application>
  </system.runtime.remoting>
</configuration>

See Also

Community Additions

ADD
Show:
© 2014 Microsoft