/// <summary> /// Builds a <see cref="IMessagingHubConnection">connection</see> with the configured parameters /// </summary> /// <returns>An inactive connection with the Messaging Hub. Call <see cref="IMessagingHubConnection.ConnectAsync"/> to activate it</returns> public IMessagingHubConnection Build() { var channelBuilder = ClientChannelBuilder.Create(() => _transportFactory.Create(EndPoint), EndPoint) .WithSendTimeout(SendTimeout) .WithEnvelopeBufferSize(ChannelBuffer) .AddCommandModule(c => new ReplyPingChannelModule(c)); channelBuilder = channelBuilder .AddBuiltHandler( (c, t) => { if (Throughput > 0) { ThroughputControlChannelModule.CreateAndRegister(c, Throughput); } return(Task.CompletedTask); }) .AddBuiltHandler( (c, t) => { if (ChannelCount > 1) { FillEnvelopeRecipientsChannelModule.CreateAndRegister(c); } return(Task.CompletedTask); }); var establishedClientChannelBuilder = new EstablishedClientChannelBuilder(channelBuilder) .WithIdentity(Identity) .WithAuthentication(GetAuthenticationScheme()) .WithCompression(Compression) .AddEstablishedHandler(SetPresenceAsync) .AddEstablishedHandler(SetReceiptAsync) .WithEncryption(Encryption); if (Instance != null) { establishedClientChannelBuilder = establishedClientChannelBuilder.WithInstance(Instance); } var onDemandClientChannelFactory = new OnDemandClientChannelFactory(establishedClientChannelBuilder); return(new MessagingHubConnection(SendTimeout, MaxConnectionRetries, onDemandClientChannelFactory, ChannelCount)); }
/// <summary> /// Creates a new instance of ChannelBase /// </summary> /// <param name="transport">The transport.</param> /// <param name="sendTimeout">The channel send timeout.</param> /// <param name="consumeTimeout">The channel consume timeout. Each envelope received from the transport must be consumed in the specified timeout or it will cause the channel to be closed.</param> /// <param name="closeTimeout">The channel close timeout.</param> /// <param name="envelopeBufferSize">Size of the envelope buffer.</param> /// <param name="fillEnvelopeRecipients">Indicates if the from and to properties of sent and received envelopes should be filled with the session information if not defined.</param> /// <param name="autoReplyPings">Indicates if the channel should reply automatically to ping request commands. In this case, the ping command are not returned by the ReceiveCommandAsync method.</param> /// <param name="remotePingInterval">The interval to ping the remote party.</param> /// <param name="remoteIdleTimeout">The timeout to close the channel due to inactivity.</param> /// <param name="channelCommandProcessor">The channel command processor.</param> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentException"> /// Invalid send timeout /// or /// Invalid consume timeout /// or /// Invalid close timeout /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"></exception> protected ChannelBase( ITransport transport, TimeSpan sendTimeout, TimeSpan?consumeTimeout, TimeSpan closeTimeout, int envelopeBufferSize, bool fillEnvelopeRecipients, bool autoReplyPings, TimeSpan?remotePingInterval, TimeSpan?remoteIdleTimeout, IChannelCommandProcessor channelCommandProcessor) { if (sendTimeout == default(TimeSpan)) { throw new ArgumentException("Invalid send timeout", nameof(sendTimeout)); } if (consumeTimeout != null && consumeTimeout.Value == default(TimeSpan)) { throw new ArgumentException("Invalid consume timeout", nameof(consumeTimeout)); } if (closeTimeout == default(TimeSpan)) { throw new ArgumentException("Invalid close timeout", nameof(closeTimeout)); } if (envelopeBufferSize <= 0) { envelopeBufferSize = DataflowBlockOptions.Unbounded; } Transport = transport ?? throw new ArgumentNullException(nameof(transport)); Transport.Closing += Transport_Closing; _sendTimeout = sendTimeout; _consumeTimeout = consumeTimeout; _closeTimeout = closeTimeout; _consumerCts = new CancellationTokenSource(); _syncRoot = new object(); var dataflowBlockOptions = new ExecutionDataflowBlockOptions() { BoundedCapacity = envelopeBufferSize, MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded, EnsureOrdered = false }; _transportBuffer = new BufferBlock <Envelope>(dataflowBlockOptions); _messageConsumerBlock = new TransformBlock <Envelope, Message>(e => ConsumeMessageAsync(e), dataflowBlockOptions); _commandConsumerBlock = new TransformBlock <Envelope, Command>(e => ConsumeCommandAsync(e), dataflowBlockOptions); _notificationConsumerBlock = new TransformBlock <Envelope, Notification>(e => ConsumeNotificationAsync(e), dataflowBlockOptions); _sessionConsumerBlock = new TransformBlock <Envelope, Session>(e => ConsumeSession(e), dataflowBlockOptions); _messageBuffer = new BufferBlock <Message>(dataflowBlockOptions); _commandBuffer = new BufferBlock <Command>(dataflowBlockOptions); _notificationBuffer = new BufferBlock <Notification>(dataflowBlockOptions); _sessionBuffer = new BufferBlock <Session>(dataflowBlockOptions); _drainEnvelopeBlock = DataflowBlock.NullTarget <Envelope>(); _transportBuffer.LinkTo(_messageConsumerBlock, PropagateCompletionLinkOptions, e => e is Message); _transportBuffer.LinkTo(_commandConsumerBlock, PropagateCompletionLinkOptions, e => e is Command); _transportBuffer.LinkTo(_notificationConsumerBlock, PropagateCompletionLinkOptions, e => e is Notification); _transportBuffer.LinkTo(_sessionConsumerBlock, PropagateCompletionLinkOptions, e => e is Session); _messageConsumerBlock.LinkTo(_messageBuffer, PropagateCompletionLinkOptions, e => e != null); _messageConsumerBlock.LinkTo(_drainEnvelopeBlock, e => e == null); _commandConsumerBlock.LinkTo(_commandBuffer, PropagateCompletionLinkOptions, e => e != null); _commandConsumerBlock.LinkTo(_drainEnvelopeBlock, e => e == null); _notificationConsumerBlock.LinkTo(_notificationBuffer, PropagateCompletionLinkOptions, e => e != null); _notificationConsumerBlock.LinkTo(_drainEnvelopeBlock, e => e == null); _sessionConsumerBlock.LinkTo(_sessionBuffer, PropagateCompletionLinkOptions, e => e != null); _sessionConsumerBlock.LinkTo(_drainEnvelopeBlock, e => e == null); _channelCommandProcessor = channelCommandProcessor ?? new ChannelCommandProcessor(); MessageModules = new List <IChannelModule <Message> >(); NotificationModules = new List <IChannelModule <Notification> >(); CommandModules = new List <IChannelModule <Command> >(); if (autoReplyPings) { CommandModules.Add(new ReplyPingChannelModule(this)); } if (fillEnvelopeRecipients) { FillEnvelopeRecipientsChannelModule.CreateAndRegister(this); } if (remotePingInterval != null) { RemotePingChannelModule.CreateAndRegister(this, remotePingInterval.Value, remoteIdleTimeout); } }
/// <summary> /// Creates a new instance of ChannelBase /// </summary> /// <param name="transport">The transport.</param> /// <param name="sendTimeout">The channel send timeout.</param> /// <param name="consumeTimeout">The channel consume timeout. Each envelope received from the transport must be consumed in the specified timeout or it will cause the channel to be closed.</param> /// <param name="closeTimeout">The channel close timeout.</param> /// <param name="envelopeBufferSize">Size of the envelope buffer.</param> /// <param name="fillEnvelopeRecipients">Indicates if the from and to properties of sent and received envelopes should be filled with the session information if not defined.</param> /// <param name="autoReplyPings">Indicates if the channel should reply automatically to ping request commands. In this case, the ping command are not returned by the ReceiveCommandAsync method.</param> /// <param name="remotePingInterval">The interval to ping the remote party.</param> /// <param name="remoteIdleTimeout">The timeout to close the channel due to inactivity.</param> /// <exception cref="System.ArgumentNullException"></exception> protected ChannelBase( ITransport transport, TimeSpan sendTimeout, TimeSpan?consumeTimeout, TimeSpan closeTimeout, int envelopeBufferSize, bool fillEnvelopeRecipients, bool autoReplyPings, TimeSpan?remotePingInterval, TimeSpan?remoteIdleTimeout) { if (transport == null) { throw new ArgumentNullException(nameof(transport)); } if (sendTimeout == default(TimeSpan)) { throw new ArgumentException("Invalid send timeout", nameof(sendTimeout)); } if (consumeTimeout != null && consumeTimeout.Value == default(TimeSpan)) { throw new ArgumentException("Invalid consume timeout", nameof(consumeTimeout)); } if (closeTimeout == default(TimeSpan)) { throw new ArgumentException("Invalid close timeout", nameof(closeTimeout)); } if (envelopeBufferSize <= 0) { throw new ArgumentOutOfRangeException(nameof(envelopeBufferSize)); } Transport = transport; Transport.Closing += Transport_Closing; _sendTimeout = sendTimeout; _consumeTimeout = consumeTimeout; _closeTimeout = closeTimeout; _consumerCts = new CancellationTokenSource(); _syncRoot = new object(); var options = new DataflowBlockOptions() { BoundedCapacity = envelopeBufferSize }; _messageBuffer = new BufferBlock <Message>(options); _commandBuffer = new BufferBlock <Command>(options); _notificationBuffer = new BufferBlock <Notification>(options); _sessionBuffer = new BufferBlock <Session>(new DataflowBlockOptions() { BoundedCapacity = 1 }); _pendingCommandsDictionary = new ConcurrentDictionary <string, TaskCompletionSource <Command> >(); MessageModules = new List <IChannelModule <Message> >(); NotificationModules = new List <IChannelModule <Notification> >(); CommandModules = new List <IChannelModule <Command> >(); if (autoReplyPings) { CommandModules.Add(new ReplyPingChannelModule(this)); } if (fillEnvelopeRecipients) { FillEnvelopeRecipientsChannelModule.CreateAndRegister(this); } if (remotePingInterval != null) { RemotePingChannelModule.CreateAndRegister(this, remotePingInterval.Value, remoteIdleTimeout); } }
/// <summary> /// Creates a new instance of ChannelBase /// </summary> /// <param name="transport">The transport.</param> /// <param name="sendTimeout">The channel send timeout.</param> /// <param name="consumeTimeout">The channel consume timeout. Each envelope received from the transport must be consumed in the specified timeout or it will cause the channel to be closed.</param> /// <param name="closeTimeout">The channel close timeout.</param> /// <param name="envelopeBufferSize">Size of the envelope buffer.</param> /// <param name="fillEnvelopeRecipients">Indicates if the from and to properties of sent and received envelopes should be filled with the session information if not defined.</param> /// <param name="autoReplyPings">Indicates if the channel should reply automatically to ping request commands. In this case, the ping command are not returned by the ReceiveCommandAsync method.</param> /// <param name="remotePingInterval">The interval to ping the remote party.</param> /// <param name="remoteIdleTimeout">The timeout to close the channel due to inactivity.</param> /// <param name="channelCommandProcessor">The channel command processor.</param> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentException"> /// Invalid send timeout /// or /// Invalid consume timeout /// or /// Invalid close timeout /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"></exception> protected ChannelBase( ITransport transport, TimeSpan sendTimeout, TimeSpan?consumeTimeout, TimeSpan closeTimeout, int envelopeBufferSize, bool fillEnvelopeRecipients, bool autoReplyPings, TimeSpan?remotePingInterval, TimeSpan?remoteIdleTimeout, IChannelCommandProcessor channelCommandProcessor) { if (closeTimeout == default) { throw new ArgumentException("Invalid close timeout", nameof(closeTimeout)); } if (envelopeBufferSize <= 0) { envelopeBufferSize = -1; } Transport = transport ?? throw new ArgumentNullException(nameof(transport)); Transport.Closing += Transport_Closing; _closeTimeout = closeTimeout; _channelCommandProcessor = channelCommandProcessor ?? new ChannelCommandProcessor(); // Modules MessageModules = new List <IChannelModule <Message> >(); NotificationModules = new List <IChannelModule <Notification> >(); CommandModules = new List <IChannelModule <Command> >(); if (autoReplyPings) { CommandModules.Add(new ReplyPingChannelModule(this)); } if (fillEnvelopeRecipients) { FillEnvelopeRecipientsChannelModule.CreateAndRegister(this); } if (remotePingInterval != null) { _remotePingChannelModule = RemotePingChannelModule.CreateAndRegister(this, remotePingInterval.Value, remoteIdleTimeout); } _receiverChannel = new ReceiverChannel( this, Transport, _channelCommandProcessor, MessageModules, NotificationModules, CommandModules, HandleConsumerExceptionAsync, envelopeBufferSize, consumeTimeout, _closeTimeout); _senderChannel = new SenderChannel( this, Transport, MessageModules, NotificationModules, CommandModules, HandleSenderExceptionAsync, envelopeBufferSize, sendTimeout, _closeTimeout); }