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

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

Конструктор клиентской трубы канала должен создать клиента MSMQ для передачи сообщений.

public MsmqClientChannelSink(string remoteObjectUri) 
{
    // выделение из URL пути к очереди и адреса объекта 
    queuePath = Utils.ParseUrl(remoteObjectUri, out objectUri);
    
    // создание клиента MSMQ, не ожидающего ответов от сервера
    // и использующего бинарный класс форматирования
    msmqClient = new MsmqClient<IMessage, IMessage>(queuePath, null, 
        QueueFormatter.Binary);   
}

public IMessage SyncProcessMessage(IMessage msg)
{
   throw new NotSupportedException(
   "Поддерживаются только методы с OneWayAttribute."); 
}

Метод AsyncProcessMessage используется для реализации асинхронного вызова. В данном примере он должен передать сообщение Remoting клиенту MSMQ.

public IMessageCtrl AsyncProcessMessage(IMessage message, 
    IMessageSink replySink)
{
    // свойство сообщения c адресом удаленного объекта
    message.Properties[MessageProperties.ObjectUri] = objectUri;
           
    // передача сообщения клиенту MSMQ для его отсылки серверу
    msmqClient.Send(message);       
    return null;    
}    

// данная труба - первая и последняя в цепочке
public IMessageSink NextSink
{ 
    get { return null;  }
}
    }  // Seva.Remoting.MsmqChannel.MsmqClientChannelSink

Принимающая сторона состоит из канала MsmqChannelReceiver.

public class MsmqChannelReceiver: MsmqBase, IChannelReceiver
{
    // Класс-сервер MSMQ для приема сообщений Remoting
    private MsmqServer<IMessage, IMessage> msmqServer;
          
    // Серверная труба канала
    private IServerChannelSink  sink;
            
    // Стек труб на стороне сервера
    private ServerChannelSinkStack stack;           
        
    // необходимое для реализации интерфейса свойство
    public object ChannelData 
    {
        get { return null; }
    }

Десериализация сообщения осуществляется в классе MsmqServer, поэтому цепочка труб сервера состоит только из стандартной трубы диспетчеризации. Для вызова метода ProcessMessage трубы диспетчеризации создается стек труб. Сервер ожидает сообщения из очереди, указанной в файле конфигурации.

public MsmqChannelReceiver(IDictionary properties,
    IServerChannelSinkProvider serverSinkProvider)
{
    // создать сервер MSMQ
    msmqServer = new MsmqServer<IMessage, IMessage>(
        properties["queue"].ToString(), QueueFormatter.Binary);
    msmqServer.ProcessMessage += OnReceive;
    
    if (serverSinkProvider!=null)
    {
        throw new NotSupportedException(
            "Поставщики не поддерживаются."); 
    }

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

sink = ChannelServices.CreateServerChannelSinkChain(null, this);
            
            // создание стека труб                                    
            stack = new ServerChannelSinkStack();
            stack.Push(sink, null);           
            // Начать ожидание собщений в очереди
            StartListening(null);
        }            

        // метод интерфейса IChannelReceiver, возваращает все URL для данного URI
        public virtual string[] GetUrlsForUri(string objectURI)
        {
            return new string[] {objectURI};
        }
                        
        // обработка пришедшего сообщения MSMQ
        private IMessage OnReceive(Object sender, IMessage request, 
            MessageQueue queueResponse)
	 {                    
            return ProcessMessage(request);
	 }		
        
        // методы, управляющие прослушивание канала
        public void StartListening(Object data)
        {
            msmqServer.BeginReceive();
        }
		        
        public void StopListening(Object data)
        {
            msmqServer.EndReceive();
        }
Листинг 8.5.

Метод ProcessMessage обрабатывает пришедшее сообщение .NET Remoting. В данном классе достаточно передать его дальше в трубу канала для передачи, в итоге, диспетчеру сообщений Remoting.

private IMessage ProcessMessage(IMessage request)
{
    IMessage response = null;
    // если в сообщении не указан URI объекта, то ничего не делать
    object uri = request.Properties[MessageProperties.ObjectUri];    
    if (uri == null) return null;
 
    string url = uri.ToString();   
    
    // Необходимо заполнить свойство сообщения __URI
    request.Properties[MessageProperties.Uri] = uri;  
    
    // Передача сообщения в трубу канала
    Stream responseStream = null;
    ITransportHeaders responseHeaders = null;
    sink.ProcessMessage(stack, request, null, null,  
    out response, out responseHeaders, out responseStream); 
    return response;
}
    } // Seva.Remoting.MsmqChannel.MsmqReceiver