远程处理示例:在 Internet 信息服务 (IIS) 中承载

本主题介绍一项传统技术,保留该技术是为了向后兼容现有的应用程序,不建议对新的开发使用该技术。现在应该使用  Windows Communication Foundation (WCF) 来开发分布式应用程序。

下面的示例实现稍微复杂一些的基本 Web 服务。要使用 BinaryFormatter,因为这样负载更小,并且系统在序列化和反序列化流时所需的时间最少。此外,如果 Internet 信息服务 (IIS) 正在使用 Windows 集成身份验证(也称为 NTLM 身份验证),服务器将对客户端进行身份验证,然后将 IIS 能够进行身份验证的身份返回给客户端。最后,您可以通过以下方式帮助保护您的 Web 服务:在客户端配置文件中更改 URL 以使用“https”作为协议方案,并配置 IIS 对该虚拟目录要求安全套接字层 (SSL) 加密(示例没有演示这个过程)。

c2swb8ah.Caution(zh-cn,VS.100).gif警告:
.NET Framework 远程处理在默认情况下不进行身份验证或加密。因此,在与客户端或服务器进行远程交互之前,建议您先执行所有必要的步骤来确认它们的身份。由于 .NET Framework 远程处理应用程序需要 FullTrust 权限才能执行,因此未经授权的客户端一旦获得服务器的访问权限,它就可以像完全受信任的客户端那样执行代码。应始终验证终结点的身份并对通信流加密,通过在 IIS 中承载远程类型,或者通过生成自定义信道接收器对,可以完成这项工作。

编译和运行此示例

  1. 将所有文件保存在名为 RemoteIIS 的目录中。

  2. 通过在命令提示符处键入下列命令来编译整个示例:

    vbc /t:library ServiceClass.vb
    vbc /r:System.Runtime.Remoting.dll /r:ServiceClass.dll Client.vb
    
    csc /t:library ServiceClass.cs
    csc /r:System.Runtime.Remoting.dll /r:ServiceClass.dll Client.cs
    
  3. 创建 \bin 子目录,并将 ServiceClass.dll 复制到该目录中。

  4. 在 IIS 中创建一个应用程序。将该应用程序的别名命名为“HttpBinary”,并将源目录设置为“RemoteIIS”目录。

  5. 将此虚拟目录的身份验证方法设置为集成 Windows 身份验证(以前的 NTLM 身份验证)。如果选择了匿名访问,HttpContext.Current.User.Identity.Name 将是 null 并且 GetServerString 将返回 "***unavailable***" 作为用户的别名。为了避免这一情况的发生,请取消选择匿名访问。

  6. 确保启动了 IIS,在“RemoteIIS”目录中的命令提示符处,键入客户端。

此应用程序可以在一台计算机上运行,也可以在网络上运行。如果要在网络上运行此应用程序,必须用远程计算机的名称替换客户端配置中的“localhost”。

ServiceClass

Imports System
Imports System.Runtime.Remoting
Imports System.Web

Public Interface IService
    Function GetServerTime() As DateTime
    Function GetServerString() As String
End Interface

Public Class ServiceClass
    Inherits MarshalByRefObject
    Implements IService

    Private InstanceHash As Integer

    Public Sub New()
        InstanceHash = Me.GetHashCode()
    End Sub

    Public Function GetServerTime() As Date Implements IService.GetServerTime
        Return DateTime.Now
    End Function

    Public Function GetServerString() As String Implements IService.GetServerString
        ' Use the HttpContext to acquire what IIS thinks the client's identity is.
        Dim temp As String = HttpContext.Current.User.Identity.Name

        If (temp Is Nothing Or temp.Equals(String.Empty)) Then
            temp = "**unavailable**"
        End If

        Return "Hi there. You are being served by instance number: " _
            & InstanceHash.ToString() _
            & ". Your alias is: " _
            & temp
    End Function
End Class
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Threading;
using System.Web;

public interface IService
{
   DateTime GetServerTime();
   string GetServerString();
}

// IService exists to demonstrate the possibility of publishing only the interface.
public class ServiceClass : MarshalByRefObject, IService
{
   private int InstanceHash;

   public ServiceClass()
   {
      InstanceHash = this.GetHashCode();
   }

   public DateTime GetServerTime()
   {
      return DateTime.Now;
   }

   public string GetServerString()
   {
      // Use the HttpContext to acquire what IIS thinks the client's identity is.
      string temp = HttpContext.Current.User.Identity.Name;
      if (temp == null || temp.Equals(string.Empty))
         temp = "**unavailable**";
      return "Hi there. You are being served by instance number: " 
         + InstanceHash.ToString() 
         + ". Your alias is: " 
         + temp;
   }
}

Web.config

<configuration>
   <system.runtime.remoting>
      <application>
         <service>
            <wellknown 
               mode="SingleCall" objectUri="SAService.rem"
               type="ServiceClass, ServiceClass"/>
         </service>
         <channels>
            <channel ref="http"/>
         </channels>
      </application>
   </system.runtime.remoting>
</configuration>

客户端

Imports System
Imports System.Collections
Imports System.Net
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Security.Principal

Public Class Client

    Public Shared Sub Main()
        ' Tells the system about the remote object and customizes the HttpChannel
        ' to use the binary formatter (which understands that base64 encoding is needed).
        RemotingConfiguration.Configure("Client.exe.config", False)

        ' New proxy for the ServiceClass.
        ' If you publish only the IService interface, you must use Activator.GetObject.
        Dim service As ServiceClass = New ServiceClass()

        ' Programmatically customizes the properties given to the channel. This sample uses the
        '  application configuration file.
        Dim Props As IDictionary = ChannelServices.GetChannelSinkProperties(service)
        Props.Item("credentials") = CredentialCache.DefaultCredentials

        ' Reports the client identity name.
        Console.WriteLine("ConsoleIdentity: " & WindowsIdentity.GetCurrent().Name)

        ' Writes what the server returned.
        Console.WriteLine("The server says : " & service.GetServerString())
        Console.WriteLine("Server time is: " & service.GetServerTime())
    End Sub
End Class
using System;
using System.Collections;
using System.Net;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Security.Principal;

class Client
{
    static void Main(string[] args)
    {
        // Tells the system about the remote object and customizes the HttpChannel
        // to use the binary formatter (which understands that base64 encoding is needed).
        RemotingConfiguration.Configure("Client.exe.config", false);

        // New proxy for the ServiceClass.
        // If you publish only the IService interface, you must use Activator.GetObject.
        ServiceClass service = new ServiceClass();

        // Programmatically customizes the properties given to the channel. This sample uses the
        // application configuration file.
        IDictionary Props = ChannelServices.GetChannelSinkProperties(service);
        Props["credentials"] = CredentialCache.DefaultCredentials;

        // Reports the client identity name.
        Console.WriteLine("ConsoleIdentity: " + WindowsIdentity.GetCurrent().Name);

        // Writes what the server returned.
        Console.WriteLine("The server says : " + service.GetServerString());
        Console.WriteLine("Server time is: " + service.GetServerTime());
    }
}

Client.exe.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.remoting>
    <application>
      <channels>
        <channel ref="http" useDefaultCredentials="true" port="0">
          <clientProviders>
            <formatter 
               ref="binary"
                  />
          </clientProviders>
        </channel>
      </channels>
      <client>
        <wellknown 
           url="https://localhost:80/HttpBinary/SAService.rem"
           type="ServiceClass, ServiceClass"
            />
      </client>
    </application>
  </system.runtime.remoting>
</configuration>

另请参见

概念

远程应用程序的配置
在 Internet 信息服务 (IIS) 中承载远程对象

其他资源

远程处理示例