远程处理示例:动态发布
本主题介绍一项传统技术,保留该技术是为了向后兼容现有的应用程序,不建议对新的开发使用该技术。 现在应该使用 Windows Communication Foundation (WCF) 来开发分布式应用程序。
.NET 远程处理仅支持对服务器激活的可远程处理类型使用默认构造函数。若要发布用特定构造函数创建的对象并对该特定实例的发布进行全面控制,可以通过编程方式发布该实例。
警告: |
---|
.NET 远程处理在默认情况下不进行身份验证或加密。因此,在与客户端或服务器进行远程交互之前,建议您先执行所有必要的步骤来验证它们的身份。因为 .NET 远程处理应用程序需要 FullTrust 权限才能执行,所以未经授权的客户端一旦获得服务器的访问权限,它就可以像完全受信任的客户端那样执行代码。应始终验证终结点的身份并对通信流加密。 有关更多信息,请参见远程处理的安全性。 |
编译和运行此示例
在命令提示符处,键入下列命令:
vbc -t:library remote.vb vbc -r:System.Runtime.Remoting.dll -r:remote.dll server.vb vbc -r:System.Runtime.Remoting.dll -r:remote.dll client.vb
csc -t:library remote.cs csc -r:System.Runtime.Remoting.dll -r:remote.dll server.cs csc -r:System.Runtime.Remoting.dll -r:remote.dll client.cs
打开指向同一目录的两个命令提示符。在一个命令提示符下,键入 server。在另一个命令提示符下,键入 client。
要停止分步骤发布可远程处理的对象,请在服务器的命令行提示符下按 ENTER,然后重新运行客户端,以便观察在不同阶段引发的不同异常。此应用程序可以在一台计算机上运行,也可以在网络上运行。若要在网络上运行此应用程序,请将客户端配置中的**“localhost”**替换为远程计算机的名称。
远程
Imports System
Public Class ServiceClass
Inherits MarshalByRefObject
Private m_startTime As DateTime
Public Sub New()
Console.WriteLine("ServiceClass created without constructor. Instance hash is " & Me.GetHashCode().ToString())
m_startTime = DateTime.Now
End Sub
Overrides Protected Sub Finalize()
Console.WriteLine("I'm being collected after " & (New TimeSpan(DateTime.Now.Ticks - m_startTime.Ticks)).ToString() & " seconds.")
MyBase.Finalize()
End Sub
Public Function GetServerTime() As DateTime
Console.WriteLine("Time requested by a client.")
Return DateTime.Now
End Function
Public ReadOnly Property InstanceHash() As Integer
Get
Return Me.GetHashCode()
End Get
End Property
End Class
using System;
using System.Collections.Generic;
using System.Text;
namespace Remote
{
public class ServiceClass : MarshalByRefObject
{
private DateTime m_startTime;
public ServiceClass()
{
Console.WriteLine("ServiceClass created without constructor. Instance hash is " + GetHashCode().ToString());
m_startTime = DateTime.Now;
}
~ServiceClass()
{
Console.WriteLine("I'm being collected after " + (new TimeSpan(DateTime.Now.Ticks - m_startTime.Ticks)).ToString() + " seconds.");
}
public DateTime GetServerTime()
{
Console.WriteLine("Time requested by a client.");
return DateTime.Now;
}
public int InstanceHash
{
get { return GetHashCode(); }
}
}
}
服务器
Imports System
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http
Module Module1
Sub Main()
Dim channel As New HttpChannel(8080)
ChannelServices.RegisterChannel(channel, False)
Dim object1 As New ServiceClass()
' Creates the single instance of ServiceClass. All clients
' will use this instance.
Dim ref1 As ObjRef = RemotingServices.Marshal(object1, "object1uri")
Console.WriteLine("ObjRef.URI: " & ref1.URI)
Console.WriteLine("Running. Press Enter to end publication.")
Console.ReadLine()
' This unregisters the object from publication, but leaves
' the channel listening.
RemotingServices.Disconnect(object1)
Console.WriteLine()
Console.WriteLine("Disconnected the object. Client now receives a RemotingException.")
Console.WriteLine("Press Enter to unregister the channel.")
Console.ReadLine()
' At this point, the ServerClass object still exists. The server
' could republish it.
' This unregisters the channel, but leaves the application
' domain running.
ChannelServices.UnregisterChannel(channel)
Console.WriteLine("Unregistered the channel. Client now receives a WebException.")
' The ServerClass object still exists. The server could
' reregister the channel and republish the object.
Console.WriteLine("The host application domain is still running. Press Enter to stop the process.")
Console.ReadLine()
' The ServiceClass object's Finalize method writes a message to
' the console. A single object will almost always succeed in
' running its Finalize method before the Console is finalized;
' in a larger application, you could ensure that all objects
' finalize before the application ends by calling the garbage
' collector and waiting.
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
End Module
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using Remote;
namespace Server
{
class Server
{
static void Main(string[] args)
{
HttpChannel channel = new HttpChannel(8080);
ChannelServices.RegisterChannel(channel, false);
ServiceClass object1 = new ServiceClass();
// Creates the single instance of ServiceClass. All clients
// will use this instance.
ObjRef ref1 = RemotingServices.Marshal(object1, "object1uri");
Console.WriteLine("ObjRef.URI: " + ref1.URI);
Console.WriteLine("Running. Press Enter to end publication.");
Console.ReadLine();
// This unregisters the object from publication, but leaves
// the channel listening.
RemotingServices.Disconnect(object1);
Console.WriteLine();
Console.WriteLine("Disconnected the object. Client now receives a RemotingException.");
Console.WriteLine("Press Enter to unregister the channel.");
Console.ReadLine();
// At this point, the ServerClass object still exists. The server
// could republish it.
// This unregisters the channel, but leaves the application
// domain running.
ChannelServices.UnregisterChannel(channel);
Console.WriteLine("Unregistered the channel. Client now receives a WebException.");
// The ServerClass object still exists. The server could
// reregister the channel and republish the object.
Console.WriteLine("The host application domain is still running. Press Enter to stop the process.");
Console.ReadLine();
// The ServiceClass object's Finalize method writes a message to
// the console. A single object will almost always succeed in
// running its Finalize method before the Console is finalized;
// in a larger application, you could ensure that all objects
// finalize before the application ends by calling the garbage
// collector and waiting.
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
客户端
Imports System
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Tcp
Imports System.Runtime.Remoting.Channels.Http
Public Class ClientProcess
<MTAThread()> _
Public Shared Sub Main()
Dim channel As New HttpChannel(0)
ChannelServices.RegisterChannel(channel, False)
' Registers the remote class. (This could be done with a
' configuration file instead of a direct call.)
RemotingConfiguration.RegisterWellKnownClientType(Type.GetType("ServiceClass, remote"), "https://localhost:8080/object1uri")
' Instead of creating a new object, this obtains a reference
' to the server's single instance of the ServiceClass object.
Dim object1 As ServiceClass = New ServiceClass()
Try
Console.WriteLine("ServerTime: " & object1.GetServerTime())
Catch ex As Exception
Console.WriteLine("Exception of type: " & ex.GetType.ToString & " occurred.")
Console.WriteLine("Details: " & ex.Message)
End Try
End Sub
End Class
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using Remote;
namespace Client
{
public class ClientProcess
{
[MTAThread]
public static void Main(string[] args)
{
HttpChannel channel = new HttpChannel();
ChannelServices.RegisterChannel(channel, false);
// Registers the remote class. (This could be done with a
// configuration file instead of a direct call.)
RemotingConfiguration.RegisterWellKnownClientType(
Type.GetType("Remote.ServiceClass, remote"),
"https://localhost:8080/object1uri");
// Instead of creating a new object, this obtains a reference
// to the server's single instance of the ServiceClass object.
ServiceClass object1 = new ServiceClass();
try
{
Console.WriteLine("ServerTime: " + object1.GetServerTime());
}
catch (Exception ex)
{
Console.WriteLine("Exception of type: " + ex.ToString() + " occurred.");
Console.WriteLine("Details: " + ex.Message);
}
}
}
}
另请参见
参考
RemotingServices.Marshal Method
RemotingServices.Disconnect Method
ChannelServices.UnregisterChannel Method