Опубликован: 11.05.2007 | Доступ: свободный | Студентов: 1698 / 235 | Оценка: 4.36 / 4.25 | Длительность: 16:06:00
Лекция 10:

Промежуточная среда .NET Remoting

8.6. Создание нестандартного канала

Одним из недостатков стандартных каналов среды Remoting является плохая поддержка асинхронного взаимодействия. Даже при вызове одностороннего метода удаленного объекта сервер и клиент Remoting должны быть запущены одновременно, поскольку оба канала требуют функционирующего соединения по TCP/IP. Поэтому в качестве примера полезной модификации среды Remoting можно рассмотреть создание собственного канала на основе службы MSMQ. В отличие от стандартных каналов TcpChannel и HttpChannel, данный канал обеспечивает асинхронный обмен между клиентом и сервером. Ограничимся реализацией канала для одностороннего удаленного вызова.

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

Простейший канал Remoting, использующий MSMQ

Рис. 8.6. Простейший канал Remoting, использующий MSMQ

Данный канал будет позволять асинхронный вызов методов с атрибутом System.Runtime.Remoting.Messaging.OneWayAttribute, причем время работы клиента и сервера может не совпадать.

Вновь создаваемый канал состоит из двух основных классов: клиентcкой части MsmqChannelSender, реализующей интерфейс IChannelSender, и серверной части MsmqChannelReceiver, реализующей интерфейс IChannelReceiver. Указанные классы используют описанные в разделе MSMQ классы MsmqClient и MsmqServer, причем необходимо использовать бинарное форматирование сообщений MSMQ.

// Файл SevaRemotingMsmq.cs
using System;
using System.IO;
using System.Collections;

using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Serialization.Formatters.Binary;
using System.Messaging;

using System.Text.RegularExpressions;

// использовать описанное в главе про MSMQ пространство имен 
// для работы c очередями сообщений
using Seva.Msmq;

// Набор классов для одностороннего удаленного вызова
// на основе Remoting / MSMQ
namespace Seva.Remoting.MsmqChannel
{   
    // константы с именами свойств сообщения
    public class MessageProperties 
    {   
        public const string Uri            = "__Uri";  
        public const string ObjectUri      = "__ObjectUri";                
    }
Листинг 8.4.

Класс MsmqBase является базовым классом для обеих частей канала. Он содержит некоторые общие для них свойства и метод Parse, выделяющий из полного URL удаленного объекта идентификатор объекта. URL при использовании данного канала должен иметь следующий вид

msmq://.\Private$\remoting_queue\endpoint

где .\Private$\remoting_queue – имя очереди (в данном случае – частной, локальной), а endpointидентификатор удаленного объекта.

// базовый класс для MsmqSender и MsmqReceiver
public class MsmqBase: MarshalByRefObject, IChannel
{        
    // обязательные для интерфейса IChannel свойства
    public int ChannelPriority { get { return 1;} }
    public string ChannelName { get{ return "msmq";} }              
              
    // разделяет URL на идентификаторы для объекта и канала
    public string Parse(string url, out string objectUri)
    {            
       return Utils.ParseUrl(url, out objectUri);            
    }    
   }

Конструктору класса MsmqChannelSender в параметре clientSinkProvider передается дополнительный поставщик, описанный в файле конфигурации, который следует вставить в цепочку поставщиков. Однако в данном случае клиентский канал может состоять из единственной цепочки сообщения, которая передает сообщение в MSMQ. Хотя в соответствии с идеологией Remoting следовало бы создать отдельную трубу форматирования, и отдельную – транспортную, для простоты примера можно ограничиться одной трубой без поддержки дополнительных поставщиков.

//  канал для клиента
public class MsmqChannelSender: MsmqBase, IChannelSender
 {
                                
    public MsmqChannelSender(IDictionary properties, 
         IClientChannelSinkProvider clientSinkProvider)
    {                        
        // поскольку в данном примере сообщение сразу направляется в MSMQ,
        // то дополнительные поставщики не поддерживаются            
        if (clientSinkProvider!=null)
        {
             throw new NotSupportedException(
                "Дополнительные поставщики не поддерживаются."); 
        }            
     }

Метод CreateMessageSink, единственный в интерфейсе IChannelSender, создает трубу сообщения.

public IMessageSink CreateMessageSink(string url, 
    object channelData, out string objectUri)
{      
    // выделить из URL идентификатор для удаленного объекта
    string remoteobjectUrl = Utils.ParseUrl(url, ChannelName,
        out objectUri);
    if (remoteobjectUrl == null) 
        return null;   
    // создание трубы
    return new MsmqClientChannelSink(remoteobjectUrl);       
    }
} // Seva.Remoting.MsmqChannel.Msmq.MsmqSender

Класс MsmqClientChannelSinkтранспортная труба клиента, передающая сериализованное сообщение в MSMQ.

// клиентская часть трубы канала
public class MsmqClientChannelSink: IMessageSink
{
    // клиент MSMQ, передающий объекты с интерфейсом IMessage 
    // ответы данный объект получать не будет, но указать 
    // отличный от void тип ответов необходимо
    private MsmqClient<IMessage, IMessage> msmqClient;
           
    // путь к очереди MSMQ и идентификатор удаленного объекта (endpoint)
    private string queuePath = null;
    private string objectUri = null;