Пример удаленного взаимодействия. Динамическая публикация

Этот раздел относится к технологии прежних версий, которая сохраняется для обеспечения обратной совместимости с существующими приложениями и не рекомендуется для разработки новых приложений. Сейчас распределенные приложения следует создавать с помощью  Windows Communication Foundation (WCF).

Система удаленного взаимодействия .NET поддерживает для удаленных типов, активируемых сервером, только конструкторы по умолчанию. Чтобы опубликовать объект после его создания с помощью заданного конструктора и полностью контролировать публикацию данного экземпляра, можно выполнять публикацию программным образом.

1t63e8ff.Caution(ru-ru,VS.100).gifВнимание!
По умолчанию при удаленном взаимодействии .NET Framework проверка подлинности и шифрование не выполняются. Поэтому рекомендуется принять все необходимые меры для проверки удостоверений клиентов и серверов до удаленного взаимодействия с ними. Поскольку для запуска приложений, использующих удаленное взаимодействие .NET Framework, требуются разрешения FullTrust, если неавторизованный клиент получит доступ к серверу, клиент сможет запускать код так, как если бы он был полностью доверенным. Необходимо всегда проверять подлинность конечных точек и шифровать потоки передачи данных. Дополнительные сведения см. в разделе Безопасность удаленного взаимодействия.

Компиляция и выполнение образца

  1. В командной строке введите следующие команды:

    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
    
  2. Откройте два окна командной строки и перейдите в них в один каталог. В первом окне введите server. Во втором окне введите client.

  3. Чтобы поэтапно прекратить публикацию удаленного объекта, нажмите клавишу ВВОД в командной строке сервера и повторно запустите клиент, чтобы просмотреть различные исключения, вызываемые на разных этапах. Это приложение выполняется на одном компьютере или в сети. Чтобы выполнить это приложение в сети, необходимо в конфигурации клиента заменить "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"), "http://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"),
                "http://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

Другие ресурсы

Примеры удаленного взаимодействия