调用上下文(CallContext)提供了用于存储属性集的数据槽,可以让我们在调用服务器方法时将一些额外数据一并传送过去。当然,这些额外数据有点限制,就是必须要实现 ILogicalThreadAffinative 接口。调用上下文在应用程序域边界被克隆,其数据槽不在其他逻辑线程上的调用上下文之间共享。

我们利用这个特性写一个简单的身份验证例子。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Services;

namespace Learn.Library.Remoting
{
  public class RemotingTest2
  {
    /// <summary>
    /// 身份验证类型
    /// </summary>
    [Serializable]
    public class Identity : ILogicalThreadAffinative
    {
      private string username;
      private string password;

      public Identity(string username, string password)
      {
        this.username = username;
        this.password = password;
      }

      public string Username
      {
        get { return username; }
        set { username = value; }
      }

      public string Password
      {
        get { return password; }
        set { password = value; }
      }
    }

    /// <summary>
    /// 远程类型
    /// </summary>
    public class Data : MarshalByRefObject
    {
      public void Test()
      {
        // 执行身份验证      
        Identity identity = CallContext.GetData("identity") as Identity;
        if (identity != null && identity.Username == "user1" && identity.Password == "pass")
        {
          Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
        }
      }
    }

    /// <summary>
    /// 服务器端代码
    /// </summary>
    static void Server()
    {
      AppDomain server = AppDomain.CreateDomain("server");
      server.DoCallBack(delegate
      {
        TcpServerChannel channel = new TcpServerChannel(801);
        ChannelServices.RegisterChannel(channel, false);

        RemotingConfiguration.ApplicationName = "test";
        RemotingConfiguration.RegisterActivatedServiceType(typeof(Data));
      });
    }

    /// <summary>
    /// 客户端代码
    /// </summary>
    static void Client()
    {
      TcpClientChannel channel = new TcpClientChannel();
      ChannelServices.RegisterChannel(channel, false);
      RemotingConfiguration.RegisterActivatedClientType(typeof(Data), "tcp://localhost:801/test");

      // 传送身份验证数据
      CallContext.SetData("identity", new Identity("user1", "pass"));
      Data data = new Data();
      data.Test();
    }

    static void Main()
    {
      Server();
      Client();
    }
  }
}

数据槽中的数据可以双向传输,也就是说我们可以从服务器返回更多的信息给客户端。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Services;

namespace Learn.Library.Remoting
{
  public class RemotingTest2
  {
    [Serializable]
    public class ServerTime : ILogicalThreadAffinative
    {
      private DateTime time;

      public ServerTime(DateTime time)
      {
        this.time = time;
      }

      public DateTime Time
      {
        get { return time; }
      }
    }

    /// <summary>
    /// 远程类型
    /// </summary>
    public class Data : MarshalByRefObject
    {
      public void Test()
      {
        CallContext.SetData("ExInfo", new ServerTime(DateTime.Now));
        Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
      }
    }

    /// <summary>
    /// 服务器端代码
    /// </summary>
    static void Server()
    {
      AppDomain server = AppDomain.CreateDomain("server");
      server.DoCallBack(delegate
      {
        TcpServerChannel channel = new TcpServerChannel(801);
        ChannelServices.RegisterChannel(channel, false);

        RemotingConfiguration.ApplicationName = "test";
        RemotingConfiguration.RegisterActivatedServiceType(typeof(Data));
      });
    }

    /// <summary>
    /// 客户端代码
    /// </summary>
    static void Client()
    {
      TcpClientChannel channel = new TcpClientChannel();
      ChannelServices.RegisterChannel(channel, false);
      RemotingConfiguration.RegisterActivatedClientType(typeof(Data), "tcp://localhost:801/test");

      Data data = new Data();
      data.Test();
      Console.WriteLine((CallContext.GetData("ExInfo") as ServerTime).Time);
    }

    static void Main()
    {
      Server();
      Client();
    }
  }