Remoting Example: CallContext

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

This sample uses the CallContext class and the ILogicalThreadAffinative interface to pass data between a remoting client application and a remoting server application.

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.

6z5ezzh0.Caution(en-us,VS.100).gifCaution:
.NET 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 Remoting applications require FullTrust permissions to execute, if an unauthorized client were granted access on your server, the client could execute code as if it were fully trusted. Always authenticate your clients and encrypt the communication streams. For more information see Security in Remoting.

To compile this sample

  1. Type the following commands at the command prompt:

    vbc /r:System.Runtime.Remoting.dll /t:library MyRemoteType.vb
    vbc /r:System.Runtime.Remoting.dll /r:MyRemoteType.dll client.vb
    vbc /r:System.Runtime.Remoting.dll /r:MyRemoteType.dll server.vb
    
    csc /r:System.Runtime.Remoting.dll /t:library MyRemoteType.cs
    csc /r:System.Runtime.Remoting.dll /r:MyRemoteType.dll client.cs
    csc /r:System.Runtime.Remoting.dll /r:MyRemoteType.dll server.cs
    

MyRemoteType

Imports System
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Messaging

Namespace [Shared]
    Public Class MyRemoteType
    Inherits MarshalByRefObject

    Private starttime As DateTime

    Public Sub New()
        Console.WriteLine("A MyRemoteObject instance has been created.")
        starttime = DateTime.Now
    End Sub

    Protected Overrides Sub Finalize()
        Console.WriteLine("MyRemoteObject being collected after " & (New TimeSpan(DateTime.Now.Ticks - starttime.Ticks)).ToString() & " seconds.")
    End Sub

    Public Function GetServerTime() As DateTime
        Console.WriteLine("Time requested by a client.")

        ' This call overwrites the client's CallContextString.
        CallContext.SetData("ServerThreadData", New CallContextString("This is the server side replacement."))
        Return DateTime.Now
    End Function
End Class

'  One method of communicating between client and server is 
'  to use the CallContext. Calling CallContext.SetData essentially puts the data
'  in a Thread Local Store. This means that the information is available 
'  to that thread or that "logical" thread (across application domains) only.
<Serializable()> _
Public Class CallContextString
    Implements ILogicalThreadAffinative

    Dim _str As String = ""

    Public Sub New(ByVal str As String)
        _str = str
        Console.WriteLine("CallContextString created.")
    End Sub

    Public Overrides Function ToString() As String
        Return _str
    End Function
End Class
End Namespace
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;

namespace Shared
{
    public class MyRemoteType : MarshalByRefObject 
    {
        private DateTime starttime;

        public MyRemoteType()
        {
            Console.WriteLine("A MyRemoteObject instance has been created.");
            starttime = DateTime.Now;
        }

        ~MyRemoteType()
        {
            Console.WriteLine("MyRemoteObject being collected after " + (new TimeSpan(DateTime.Now.Ticks - starttime.Ticks)).ToString() + " seconds.");
        }

        public DateTime GetServerTime()
        {
            Console.WriteLine("Time requested by a client.");

            // This call overwrites the client's CallContextString.
            CallContext.SetData("ServerThreadData", new CallContextString("This is the server side replacement."));
            return DateTime.Now;
        }
    }

    //  One method of communicating between client and server is 
    //  to use the CallContext. Calling CallContext.SetData essentially puts the data
    //  in a Thread Local Store. This means that the information is available 
    //  to that thread or that "logical" thread (across application domains) only.
    [Serializable]
    public class CallContextString : ILogicalThreadAffinative
    {
        String _str = "";

        public CallContextString(String str)
        {
            _str = str;
            Console.WriteLine("CallContextString created.");
        }

        public override String ToString()
        {
            return _str;
        }
    }
}

Client

Imports System
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http
Imports System.Runtime.Remoting.Contexts
Imports System.Runtime.Remoting.Messaging
Imports [Shared]

Public Class Client
    Public Shared Sub Main()
        ' Register Channel
        Dim channel As HttpChannel = New HttpChannel()
        ChannelServices.RegisterChannel(channel, False)

        ' Register MyRemoteObject
        RemotingConfiguration.RegisterWellKnownClientType( _
                GetType(MyRemoteType), _
                "https://localhost:8080/MyRemoteObject")

        ' Add a CallContextString object to the call context
        CallContext.SetData("ServerThreadData", New CallContextString("This is the thread data inserted on the client thread."))

        Console.WriteLine("CallContextString prior to the call: " & CallContext.GetData("ServerThreadData").ToString())
        Dim service As MyRemoteType = New MyRemoteType()
        Console.WriteLine("Server time is: " & service.GetServerTime().ToLongTimeString())
        Console.WriteLine("CallContextString after the call: " & CallContext.GetData("ServerThreadData").ToString())
    End Sub
End Class
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using Shared;

namespace Client
{
    public class Client
    {
        public static void Main(string[] args)
        {
            // Register Channel
            HttpChannel channel = new HttpChannel();
            ChannelServices.RegisterChannel(channel, false);

            // Register MyRemoteObject
            RemotingConfiguration.RegisterWellKnownClientType(
                typeof(MyRemoteType),
                "https://localhost:8080/MyRemoteObject");

            // Add a CallContextString object to the call context
            CallContext.SetData("ServerThreadData", new CallContextString("This is the thread data inserted on the client thread."));

            Console.WriteLine("CallContextString prior to the call: " + CallContext.GetData("ServerThreadData").ToString());
            MyRemoteType service = new MyRemoteType();
            Console.WriteLine("Server time is: " + service.GetServerTime().ToLongTimeString());
            Console.WriteLine("CallContextString after the call: " + CallContext.GetData("ServerThreadData").ToString());
        }
    }
}

Server

Imports System
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http
Imports [Shared]

Public Class Server

    Public Shared Sub Main()
        ' Register channel
        Dim channel As HttpChannel = New HttpChannel(8080)
        ChannelServices.RegisterChannel(channel, False)

        ' Register MyRemoteObject
        RemotingConfiguration.RegisterWellKnownServiceType( _
            GetType(MyRemoteType), _
            "MyRemoteObject", _
            WellKnownObjectMode.SingleCall)

        Console.WriteLine("Press enter to stop this process.")
        Console.ReadLine()
    End Sub

End Class
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using Shared;

namespace Server
{
    class Server
    {
        static void Main(string[] args)
        {
            // Register channel
            HttpChannel channel = new HttpChannel(8080);
            ChannelServices.RegisterChannel(channel, false);

            // Register MyRemoteObject
            RemotingConfiguration.RegisterWellKnownServiceType(
                typeof(MyRemoteType),
                "MyRemoteObject",
                WellKnownObjectMode.SingleCall);

            Console.WriteLine("Press enter to stop this process.");
            Console.ReadLine();
        }
    }
}

See Also

Other Resources

Remoting Examples