/// <summary> /// Отправляет NMS-сообщение <paramref name="query"/> и ожидает ответа. /// Асинхронная операция. /// </summary> /// <typeparam name="TMessage">Тип сообщения, потомок NmsMessage.</typeparam> /// <param name="query">Сообщение-запрос.</param> /// <param name="options">Параметры асинхронной операции.</param> /// <returns> /// <see cref="Task{TResult}"/> асинхронная операция - ответное сообщение. /// </returns> /// <exception cref="AggregateException">Призошла ошибка в асинхронном коде. См. <see cref="Exception.InnerException"/></exception> /// <exception cref="TimeoutException">Ошибка по таймауту.</exception> /// <exception cref="TaskCanceledException">Операция прервана пользователем.</exception> /// <exception cref="NibusResponseException">Ошибка NiBUS.</exception> public async Task <TMessage> WaitForNmsResponseAsync <TMessage>(TMessage query, NibusOptions options = null) where TMessage : NmsMessage { //Contract.Requires(!IsDisposed); //Contract.Requires( // query.Datagram.Destanation.Type == AddressType.Hardware // || query.Datagram.Destanation.Type == AddressType.Net); options = GetDefaultOrClone(options); // Последнее сообщение в BroadcastBlock всегда остается! Незабываем его фильтровать. NmsMessage lastMessage; IncomingMessages.TryReceive(null, out lastMessage); var wob = new WriteOnceBlock <NmsMessage>(m => m); using (IncomingMessages.LinkTo( wob, m => !ReferenceEquals(lastMessage, m) && m.IsResponse && m.ServiceType == query.ServiceType && (query.Id == 0 || m.Id == query.Id) && (query.Datagram.Destanation == Address.Empty || m.Datagram.Source == query.Datagram.Destanation))) { for (var i = 0; i < options.Attempts; i++) { await OutgoingMessages.SendAsync(query); try { var response = (TMessage)await wob.ReceiveAsync(options.Timeout, options.Token).ConfigureAwait(false); if (response.ErrorCode != 0) { throw new NibusResponseException(response.ErrorCode); } return(response); } catch (TimeoutException) { Logger.Debug("Timeout {0}", i + 1); if (i < options.Attempts - 1) { continue; } throw; } } } // Эта точка недостижима при attempts > 0! throw new InvalidOperationException(); }
private async Task <NmsRead> GetNmsReadResponseAsync( NmsMessage lastMessage, Address target, int id, NibusOptions options) { var wob = new WriteOnceBlock <NmsMessage>(m => m); using (IncomingMessages.LinkTo( wob, m => !ReferenceEquals(lastMessage, m) && m.IsResponse && m.ServiceType == NmsServiceType.Read && m.Id == id && (target == Address.Empty || m.Datagram.Source == target))) { var response = (NmsRead)await wob.ReceiveAsync(options.Timeout, options.Token).ConfigureAwait(false); if (response.ErrorCode != 0) { throw new NibusResponseException(response.ErrorCode); } return(response); } }