Приемники и цепочки приемников

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

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

Приемники и цепочки приемников

Перед отправкой сообщения или после его получения каналы передают каждое сообщение по цепочке объектов приемников канала. Цепочка приемников содержит приемники, необходимые для выполнения базовых функций канала, например приемники модуля форматирования, транспорта или построения стека. Но цепочку приемников канала можно и изменить для решения специальных задач обработки сообщения или потока. Каждый приемник канала реализует интерфейс IClientChannelSink или IServerChannelSinkfrlrfSystemRuntimeRemotingChannelsIServerChannelSinkClassTopic. Кроме того, первый приемник канала на стороне клиента должен реализовывать интерфейс IMessageSinkfrlrfSystemRuntimeRemotingMessagingIMessageSinkClassTopic. Обычно он реализует интерфейс IClientFormatterSink (который наследует у IMessageSink, IChannelSinkBase и IClientChannelSink) и называется приемником модуля форматирования, поскольку он преобразует входящее сообщение в поток (объект IMessagefrlrfSystemRuntimeRemotingMessagingIMessageClassTopic).

Цепочка приемников канала обрабатывает все сообщения, пересылаемые из домена приложения или в него. У приемника канала имеется доступ к обрабатываемым сообщениям, и при последующей обработке используются сообщения, которые возвращаются в систему после обработки. Именно на этом уровне логичнее всего реализовывать службу ведения журнала или механизм фильтрации.

Каждый приемник канала обрабатывает поток, а затем передает его следующему приемнику канала, что означает, что приемники, расположенные до и после конкретного канала, должны знать, как обрабатывать получаемый ими поток.

tdzwhfy3.note(ru-ru,VS.100).gifПримечание
Приемники сообщений не должны создавать исключений. Один из способов решения этой проблемы для приемников сообщений — заключение кода метода в блоки try-catch.

Поставщики приемников каналов (объекты, которые реализуют интерфейс IClientChannelSinkProviderfrlrfSystemRuntimeRemotingChannelsIClientChannelSinkProviderClassTopic, IClientFormatterSinkProviderfrlrfSystemRuntimeRemotingChannelsIClientFormatterSinkProviderClassTopic или IServerChannelSinkProvider) отвечают за создание приемников каналов, которые обрабатывают сообщения удаленного взаимодействия .NET. При активации удаленного типа происходит получение из канала поставщика приемников каналов, после чего вызывается метод CreateSink поставщика приемников, чтобы получить первый приемник канала в цепочке.

Приемники каналов отвечают за передачу сообщений между клиентом и сервером. Кроме того, приемники каналов связываются в цепочки. При вызове метода CreateSink поставщика приемников этот поставщик выполняет следующие действия:

  • создает приемник канала;

  • вызывает метод CreateSink следующего поставщика приемников в цепочке;

  • проверяет, что текущий и следующий приемники связаны друг с другом;

  • возвращает приемник вызывающему объекту.

Приемники каналов отвечают за перенаправление всех получаемых вызовов следующему приемнику в цепочке и должны обеспечивать механизм для хранения ссылки на следующий приемник.

Приемники каналов обладают значительной гибкостью с точки зрения содержимого, которое они могут передавать по цепочке приемников. Например, приемники безопасности, отвечающие за проверку подлинности перед отправкой реального сериализованного сообщения, могут сохранять все сообщение, заменять поток содержимого собственным содержимым, а также пересылать его по цепочке приемников в домен удаленного приложения. На обратном пути приемник безопасности может перехватывать ответные сообщения, взаимодействуя с соответствующими приемниками безопасности в домене удаленного приложения. После достижения соглашения приемник безопасности отправителя может переслать исходный поток содержимого в домен удаленного приложения.

Обработка сообщений в цепочке приемников канала

Когда система удаленного взаимодействия .NET обнаруживает канал, который может обработать сообщение, канал передает сообщение приемнику модуля форматирования путем вызова метода

SyncProcessMessage (или AsyncProcessMessage). Приемник модуля форматирования создает массив заголовков транспорта и вызывает метод GetRequestStream следующего приемника. Этот вызов перенаправляется по цепочке приемников, и любой приемник может создать поток запроса, который будет передан обратно в приемник модуля форматирования. Если метод GetRequestStream возвращает пустую (NULL) ссылку (Nothing in Visual Basic), приемник модуля форматирования создает собственный приемник для сериализации. После возвращения этого вызова сообщение сериализуется и вызывается соответствующий метод обработки сообщения первого приемника канала в цепочке.

Приемники не могут записывать данные в поток, однако могут читать данные из потока и передавать новый поток нужному адресату. Кроме того, приемники могут добавлять заголовки в массив заголовков (если ранее они не вызывали метод GetRequestStream следующего приемника) и добавлять себя в стек приемников перед передачей вызова следующему приемнику. (Стек приемников позволяет выполнять обратные асинхронные вызовы вызывающего объекта после завершения вызова.) Когда вызов достигает транспортного приемника в конце цепочки, транспортный приемник по каналу отправляет заголовки и сериализованное сообщение на сервер, где весь процесс повторяется в обратном порядке. Транспортный приемник (на стороне сервера) извлекает заголовки и сериализованное сообщения из серверной части потока и перенаправляет их по цепочке приемников до тех пор, пока не будет достигнут приемник модуля форматирования. Приемник модуля форматирования десериализует сообщение и перенаправляет его в систему удаленного взаимодействия .NET, где оно преобразуется обратно в вызов метода и вызывается в серверном объекте.

Создание цепочек приемников каналов

Чтобы создать приемник канала, необходимо реализовать и настроить систему удаленного взаимодействия .NET, которая бы поддерживала реализацию интерфейса IServerChannelSinkProvider или IClientChannelSinkProvider, позволяющего создать пользовательскую реализацию интерфейса IClientChannelSink или IServerChannelSink или получить следующий приемник в цепочке. Для реализации пользовательских приемников канала можно использовать абстрактный класс BaseChannelSinkWithProperties.

Создание поставщика приемников каналов

Поставщики приемников каналов сервера или клиента могут передаваться приложениями в качестве параметров при вызове конструкторов каналов. Поставщики приемников каналов должны храниться в цепочке; разработчик отвечает за то, чтобы все поставщики приемников каналов были объединены в цепочку перед передачей внешнего поставщика в конструктор канала. Для этого в поставщике приемников каналов реализуется свойство Next. В следующем примере кода показано, как создать поставщик приемников каналов клиента. Полный пример см. в разделе Пример удаленного взаимодействия. Поставщик приемников каналов.

private Function CreateDefaultClientProviderChain() As IClientChannelSinkProvider
   Dim chain As New FirstClientFormatterSinkProvider            
   Dim sink As IClientChannelSinkProvider
   sink = chain
   sink.Next = New SecondClientFormatterSinkProvider
   sink = sink.Next
   return chain
End Function 
private IClientChannelSinkProvider CreateDefaultClientProviderChain(){
   IClientChannelSinkProvider chain = new FirstClientFormatterSinkProvider();            
   IClientChannelSinkProvider sink = chain;
   sink.Next = new SecondClientFormatterSinkProvider();
   sink = sink.Next;
   return chain;
} 
tdzwhfy3.note(ru-ru,VS.100).gifПримечание
Когда в файле конфигурации указано несколько поставщиков приемников каналов, система удаленного взаимодействия .NET объединяет их в цепочку в том порядке, в котором они указаны в файле конфигурации. Поставщики приемников каналов создаются при создании канала во время вызова метода Configure.

Приемники модуля форматирования

Приемники модуля форматирования сериализуют сообщение канала в поток сообщения (объект, реализующий интерфейс IMessage). Некоторые реализации приемника модуля форматирования используют типы модуля форматирования, предоставляемые системой (BinaryFormatterfrlrfSystemRuntimeSerializationFormattersBinaryBinaryFormatterClassTopic и SoapFormatterfrlrfSystemRuntimeSerializationFormattersSoapSoapFormatterClassTopic). В других реализациях могут использоваться собственные средства преобразования сообщения канала в поток.

Функция приемника модуля форматирования — создать необходимые заголовки и сериализовать сообщение в поток. После приемника модуля форматирования сообщение перенаправляется всем приемникам в цепочке при помощи вызовов методов SyncProcessMessage или AsyncProcessMessage. На данном этапе сообщение уже сериализовано и не может быть изменено.

tdzwhfy3.note(ru-ru,VS.100).gifПримечание
Приемники, которые должны создавать или изменять само сообщение, следует располагать в цепочке до приемника модуля форматирования. Это легко сделать, реализовав интерфейс IClientFormatterSink, тем самым сообщив системе, что имеется ссылка на приемник модуля форматирования. Настоящий приемник модуля форматирования может быть помещен в цепочку приемников позже.

На обратном пути приемник модуля форматирования преобразует поток сообщения обратно в объект сообщения канала (возвращаемое сообщение). Первый приемник канала на стороне клиента должен реализовывать интерфейс IClientFormatterSink. Когда метод CreateSink возвращает управление каналу, возвращаемая ссылка приводится к типу IClientFormatterSink, что позволяет вызвать метод SyncProcessMessage. Помните, что интерфейс IClientFormatterSink является унаследованным от интерфейса IMessageSink. Если выполнить приведение не удастся, система создаст исключение.

Пользовательские приемники каналов

На стороне клиента пользовательские приемники каналов помещаются в цепочку объектов между приемником модуля форматирования и последним транспортным приемником. Вставка пользовательского приемника в канал на стороне клиента или сервера позволяет обрабатывать объекты IMessage в одной из следующих точек:

  • в ходе процесса, который преобразует сообщение в поток и передает его по каналу;

  • в ходе процесса, в котором поток из канала передается последнему приемнику сообщений перед удаленным объектом на сервере или прокси-объектом (на клиенте).

Пользовательские приемники позволяют выполнять чтение или запись данных (в зависимости от типа вызова — входящий или исходящий) в потоке и при необходимости добавлять в заголовки дополнительные сведения. На этом этапе сообщение уже сериализовано модулем форматирования и не может быть изменено. Когда вызов сообщения перенаправляется транспортному приемнику в конце цепочки, транспортный приемник записывает заголовки в поток и перенаправляет поток транспортному приемнику на сервере, используя протокол передачи, заданный для канала.

Транспортные приемники

Транспортный приемник представляет собой последний приемник в цепочке клиента и первый приемник в цепочке сервера. Помимо передачи сериализованных сообщений транспортные приемники также отвечают за передачу заголовков на сервер и извлечение заголовков и потока, когда вызов возвращается с сервера. Эти приемники встроены в каналы и не могут расширяться.

Замена модуля форматирования по умолчанию

Поскольку канал является абстрактным сетевым механизмом, можно настроить систему удаленного взаимодействия .NET таким образом, чтобы объединить канал, реализуемый в системе, с произвольно выбранным модулем форматирования. Для этого можно воспользоваться конструктором канала, который принимает реализацию IDictionary свойств канала — модуль форматирования на сервере и модуль форматирования на клиенте. Кроме того, модуль форматирования можно задать в файле конфигурации. В следующем примере система удаленного взаимодействия .NET создает канал HttpChannel, но использует на клиенте приемник BinaryClientFormatterSink.

<configuration>
   <system.runtime.remoting>
      <application>
         <channels>
            <channel ref="http">
               <clientProviders>
                  <formatter ref="binary"/>
               </clientProviders>
         <channels>
      </application>
   </system.runtime.remoting>
</configuration> 

В следующем примере та же задача выполняется программным образом; удаленный тип интерфейса IService реализует методы GetServerString и GetServerTime:

Imports System
Imports System.Collections
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http

Public Class ClientProcess
  <MTAThread()> _
  Public Shared Sub Main()
      
    ' Note that any name/value pairs of configuration attributes can be 
    ' placed in this dictionary (the configuration system calls this same 
    ' constructor).
    Dim properties As New Hashtable()
    properties("name") = "HttpBinary"
     
    ChannelServices.RegisterChannel(New HttpChannel(properties, New BinaryClientFormatterSinkProvider(), Nothing))
    ' The last parameter above (Nothing) is the server sink provider chain 
    ' to obtain the default behavior (which includes SOAP and 
    ' binary formatters on the server side).
    Dim service As IService = CType(Activator.GetObject(GetType(IService), "http://computer:8080/SAService"), IService)
      
    Console.WriteLine("Server string is: " + service.GetServerString())
    Console.WriteLine("Server time is: " + service.GetServerTime())
  End Sub
   
End Class 
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

public class ClientProcess{

  public static void Main(string[] Args){
        
    // Note that any name/value pairs of configuration attributes can be 
    // placed in this dictionary (the configuration system calls this 
    // same HttpChannel constructor).
    IDictionary properties = new Hashtable();
    properties["name"] = "HttpBinary";

    // The last parameter below is the server sink provider chain 
    // to obtain the default behavior (which includes SOAP and binary 
    // formatters) on the server side.
    ChannelServices.RegisterChannel(new HttpChannel(properties, new BinaryClientFormatterSinkProvider(), null));

    IService service = (IService)Activator.GetObject(typeof(IService),"http://computer:8080/SAService");
        
    Console.WriteLine("Server string is: " + service.GetServerString());
    Console.WriteLine("Server time is: " + service.GetServerTime());      
  }
}

Полный текст примера данного сочетания канала и модуля форматирования с размещением в службах IIS см. в разделе Пример удаленного взаимодействия. Размещение в службах IIS.

Чтобы этот клиент использовал объект TcpChannel с объектом SoapClientFormatterSinkfrlrfSystemRuntimeRemotingChannelsSoapClientFormatterSinkClassTopic, необходимо изменить только пространства имен и вызов метода RegisterChannel****, как показано в следующем примере кода:

ChannelServices.RegisterChannel(New TcpChannel(properties, New SoapClientFormatterSinkProvider(), Nothing))
ChannelServices.RegisterChannel(new TcpChannel(properties, new SoapClientFormatterSinkProvider(), null));

См. также

Основные понятия

Размещение удаленных объектов в службах IIS
Пример удаленного взаимодействия. Размещение в службах IIS

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

Расширенное удаленное взаимодействие