public static void UseApplicationInsight(this OptionsConfigurer configurer, Container container) { configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var step = new ApplicationInsightsStep(container); return(new PipelineStepInjector(pipeline) .OnReceive(step, PipelineRelativePosition.Before, typeof(SimpleRetryStrategyStep)) ); }); }
/// <summary> /// Configures Rebus to encrypt outgoing messages and be able to decrypt incoming messages using custom encryption provider. /// Please note that it's only the message bodies that are encrypted, thus everything included in the message headers will be visible to eavesdroppers. /// Custom encrypotion providers are configured by building on the returned configurer, e.g. like so: /// <code> /// Configure.With(...) /// .(...) /// .Options(o => { /// o.EnableCustomEncryption() /// .Use***(); /// }) /// .Start(); /// </code> /// </summary> public static StandardConfigurer <IEncryptor> EnableCustomEncryption(this OptionsConfigurer configurer) { configurer.Register(c => new EncryptMessagesOutgoingStep(c.Get <IEncryptor>())); configurer.Register(c => new DecryptMessagesIncomingStep(c.Get <IEncryptor>())); configurer.Decorate <IPipeline>(c => new PipelineStepInjector(c.Get <IPipeline>()) .OnReceive(c.Get <DecryptMessagesIncomingStep>(), PipelineRelativePosition.Before, typeof(DeserializeIncomingMessageStep)) .OnSend(c.Get <EncryptMessagesOutgoingStep>(), PipelineRelativePosition.After, typeof(SerializeOutgoingMessageStep))); return(StandardConfigurer <IEncryptor> .GetConfigurerFrom(configurer)); }
public static void AutomaticallyFlowUserContext(this OptionsConfigurer configurer, Container container) { configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var step = new UserFlowStep(container); return(new PipelineStepInjector(pipeline) .OnReceive(step, PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep)) .OnSend(step, PipelineRelativePosition.Before, typeof(SerializeOutgoingMessageStep))); }); }
public void When_configuring_instance_without_configurer_it_should_throw() { OptionsConfigurer configurer = null; // ReSharper disable once ExpressionIsAlwaysNull Action act = () => configurer.EnableCorrelate(new DependencyResolverAdapter(_ => null)); // Assert act.Should() .Throw <ArgumentNullException>() .Where(exception => exception.ParamName == nameof(configurer)); }
public void When_configuring_instance_without_configurer_it_should_throw() { OptionsConfigurer configurer = null; // ReSharper disable once ExpressionIsAlwaysNull Action act = () => configurer.EnableCorrelate(new ServiceCollection().BuildServiceProvider()); // Assert act.Should() .Throw <ArgumentNullException>() .Where(exception => exception.ParamName == nameof(configurer)); }
public static void Apply(this OptionsConfigurer configurer, ServiceBusOptions options) { if (options.NumberOfWorkers != null) { configurer.SetNumberOfWorkers(options.NumberOfWorkers.Value); } if (options.MaxParallelism != null) { configurer.SetMaxParallelism(options.MaxParallelism.Value); } }
public void Apply(OptionsConfigurer configurer) { if (NumberOfWorkers != null) { configurer.SetNumberOfWorkers(NumberOfWorkers.Value); } if (MaxParallelism != null) { configurer.SetMaxParallelism(MaxParallelism.Value); } }
/// <summary> /// Enables compression of outgoing messages if the size exceeds the specified number of bytes /// (defaults to <see cref="DefaultBodyThresholdBytes"/>) /// </summary> public static OptionsConfigurer EnableCompression(this OptionsConfigurer configurer, int bodySizeThresholdBytes = DefaultBodyThresholdBytes) { configurer.Register(c => new Zipper()); configurer.Register(c => new UnzipMessagesIncomingStep(c.Get <Zipper>())); configurer.Register(c => new ZipMessagesOutgoingStep(c.Get <Zipper>(), bodySizeThresholdBytes)); configurer.Decorate <IPipeline>(c => new PipelineStepInjector(c.Get <IPipeline>()) .OnReceive(c.Get <UnzipMessagesIncomingStep>(), PipelineRelativePosition.Before, typeof(DeserializeIncomingMessageStep)) .OnSend(c.Get <ZipMessagesOutgoingStep>(), PipelineRelativePosition.After, typeof(SerializeOutgoingMessageStep))); return(configurer); }
/// <summary> /// Configures the timespans to wait when backing off polling the transport during idle times. <paramref name="backoffTimes"/> /// must be a sequence of timespans, which indicates the time to wait for each second elapsed being idle. When the idle time /// exceeds the number of timespans, the last timespan will be used. /// </summary> public static OptionsConfigurer SetBackoffTimes(this OptionsConfigurer configurer, IEnumerable <TimeSpan> backoffTimes) { var list = backoffTimes.ToList(); if (!list.Any()) { throw new ArgumentException("Please specify at least one TimeSpan when you customize the backoff times! You could for example specify new[] { TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5) } in order to wait 0.5s and 1s during the first two seconds of inactivity, and then 5 seconds poll interval forever thereafter"); } configurer.Register <IBackoffStrategy>(c => new SimpleCustomizedBackoffStrategy(list)); return(configurer); }
/// <summary> /// Configures Rebus to execute handlers inside a <see cref="TransactionScope"/> /// </summary> public static OptionsConfigurer HandleMessagesInsideTransactionScope(this OptionsConfigurer configurer) { configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var stepToInject = new TransactionScopeIncomingStep(); return(new PipelineStepInjector(pipeline) .OnReceive(stepToInject, PipelineRelativePosition.Before, typeof(DispatchIncomingMessageStep))); }); return(configurer); }
/// <summary> /// Configures the timespans to wait when backing off polling the transport during idle times. <paramref name="backoffTimes"/> /// must be a sequence of timespans, which indicates the time to wait for each second elapsed being idle. When the idle time /// exceeds the number of timespans, the last timespan will be used. /// </summary> public static void SetBackoffTimes(this OptionsConfigurer configurer, params TimeSpan[] backoffTimes) { if (configurer == null) { throw new ArgumentNullException(nameof(configurer)); } if (backoffTimes == null) { throw new ArgumentNullException(nameof(backoffTimes)); } SetBackoffTimes(configurer, (IEnumerable <TimeSpan>)backoffTimes); }
/// <summary> /// Makes Rebus "legacy compatible", i.e. enables wire-level compatibility with older Rebus versions. WHen this is enabled, /// all endpoints need to be old Rebus endpoints or new Rebus endpoints with this feature enabled /// </summary> public static void EnableLegacyCompatibility(this OptionsConfigurer configurer) { configurer.Register <ISerializer>(c => { var specialSettings = LegacySubscriptionMessagesBinder.JsonSerializerSettings; var legacyEncoding = Encoding.UTF7; var jsonSerializer = new JsonSerializer(specialSettings, legacyEncoding); return(jsonSerializer); }); configurer.Decorate(c => { var pipeline = c.Get <IPipeline>(); // map headers of incoming message from v1 to v2 pipeline = new PipelineStepConcatenator(pipeline) .OnReceive(new MapLegacyHeadersIncomingStep(), PipelineAbsolutePosition.Front); // unpack object[] of transport message pipeline = new PipelineStepInjector(pipeline) .OnReceive(new UnpackLegacyMessageIncomingStep(), PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep)); // pack into object[] pipeline = new PipelineStepInjector(pipeline) .OnSend(new PackLegacyMessageOutgoingStep(), PipelineRelativePosition.Before, typeof(SerializeOutgoingMessageStep)); pipeline = new PipelineStepInjector(pipeline) .OnSend(new MapLegacyHeadersOutgoingStep(), PipelineRelativePosition.Before, typeof(SendOutgoingMessageStep)); //pipeline = new PipelineStepInjector(pipeline) // .OnReceive(new HandleLegacySubscriptionRequestIncomingStep(c.Get<ISubscriptionStorage>(), c.Get<LegacySubscriptionMessageSerializer>()), PipelineRelativePosition.Before, typeof(MapLegacyHeadersIncomingStep)); return(pipeline); }); configurer.Decorate(c => { var transport = c.Get <ITransport>(); if (transport is MsmqTransport) { c.Get <IRebusLoggerFactory>() .GetCurrentClassLogger() .Info("MSMQ transport detected - changing to UTF7 for serialized message header encoding"); ((MsmqTransport)transport).UseLegacyHeaderSerialization(); } return(transport); }); }
public void With_null_configurer_it_should_throw() { OptionsConfigurer configurer = null; // ReSharper disable once ExpressionIsAlwaysNull // ReSharper disable once ObjectCreationAsStatement Action act = () => configurer.ValidateMessages(Mock.Of <IValidatorFactory>(), _ => { }); // Assert act.Should() .Throw <ArgumentNullException>() .Which.ParamName.Should() .Be(nameof(configurer)); }
/// <summary> /// Decorates the current <see cref="IFailFastChecker"/> with a filter that causes Rebus to fail fast on exceptions of type /// <typeparamref name="TException"/> (optionally also requiring it to satisfy the when <paramref name="when"/>) /// </summary> public static void FailFastOn <TException>(this OptionsConfigurer configurer, Func <TException, bool> when = null) where TException : Exception { if (configurer == null) { throw new ArgumentNullException(nameof(configurer)); } configurer.Decorate <IFailFastChecker>(c => { var failFastChecker = c.Get <IFailFastChecker>(); return(new FailFastOnSpecificExceptionTypeAndPredicate <TException>(failFastChecker, when)); }); }
private static OptionsConfigurer ConfigurePipeline(this OptionsConfigurer configurer) { configurer.Decorate <IPipeline>(ctx => { IPipeline pipeline = ctx.Get <IPipeline>(); CorrelateOutgoingMessageStep outgoingStep = ctx.Get <CorrelateOutgoingMessageStep>(); CorrelateIncomingMessageStep incomingStep = ctx.Get <CorrelateIncomingMessageStep>(); return(new PipelineStepInjector(pipeline) .OnSend(outgoingStep, PipelineRelativePosition.Before, typeof(FlowCorrelationIdStep)) .OnReceive(incomingStep, PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep))); }); return(configurer); }
/// <summary> /// Enables message auditing whereby Rebus will forward to the audit queue a copy of each properly handled message and /// each published message /// </summary> public static StandardConfigurer <ISagaSnapshotStorage> EnableSagaAuditing(this OptionsConfigurer configurer) { configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var sagaSnapshotStorage = GetSagaSnapshotStorage(c); var transport = GetTransport(c); return(new PipelineStepInjector(pipeline) .OnReceive(new SaveSagaDataSnapshotStep(sagaSnapshotStorage, transport), PipelineRelativePosition.Before, typeof(LoadSagaDataStep))); }); return(configurer.GetConfigurer <ISagaSnapshotStorage>()); }
public static void UseDistributeTracingFlow(this OptionsConfigurer configurer) { configurer.Decorate <IPipeline>(c => { var outgoingStep = new SetTraceParentOutgoingStep(); var incomingStep = new GetTraceParentIncomingStep(); var pipeline = c.Get <IPipeline>(); return(new PipelineStepInjector(pipeline) .OnReceive(incomingStep, PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep)) .OnSend(outgoingStep, PipelineRelativePosition.Before, typeof(SerializeOutgoingMessageStep))); }); }
public static OptionsConfigurer RegisterOutgoingStep(this OptionsConfigurer configurer, IOutgoingStep stepToInject, PipelineRelativePosition position = PipelineRelativePosition.Before, Type anchorStep = null) { anchorStep = anchorStep ?? typeof(SendOutgoingMessageStep); configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); return(new PipelineStepInjector(pipeline) .OnSend(stepToInject, position, anchorStep)); }); return(configurer); }
/// <summary> /// Configures Rebus to execute handlers inside a <see cref="TransactionScope"/>, using the transaction options /// given by <paramref name="transactionOptions"/> for the transaction scope /// </summary> public static void HandleMessagesInsideTransactionScope(this OptionsConfigurer configurer, TransactionOptions transactionOptions) { if (configurer == null) { throw new ArgumentNullException(nameof(configurer)); } configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var stepToInject = new TransactionScopeIncomingStep(transactionOptions); return(new PipelineStepInjector(pipeline) .OnReceive(stepToInject, PipelineRelativePosition.Before, typeof(DispatchIncomingMessageStep))); }); }
/// <summary> /// Initiates the configuration of the handler ordering - call <see cref="ReorderingConfiguration.First{THandler}"/> in /// order to specify the handler that will be put first in the pipeline if it is present /// </summary> public static ReorderingConfiguration SpecifyOrderOfHandlers(this OptionsConfigurer configurer) { var configuration = new ReorderingConfiguration(); configurer.Register(c => new HandlerReorderingStep(configuration)); configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var step = c.Get <HandlerReorderingStep>(); return(new PipelineStepInjector(pipeline) .OnReceive(step, PipelineRelativePosition.Before, typeof(DispatchIncomingMessageStep))); }); return(configuration); }
/// <summary> /// Enables message auditing whereby Rebus will forward to the audit queue a copy of each properly handled message and /// each published message /// </summary> public static void EnableMessageAuditing(this OptionsConfigurer configurer, string auditQueue) { if (configurer == null) { throw new ArgumentNullException("configurer"); } if (string.IsNullOrWhiteSpace(auditQueue)) { throw new ArgumentNullException("auditQueue"); } configurer.Register(c => new AuditingSteps(auditQueue, c.Get <ITransport>())); configurer.Decorate <IPipeline>(c => new PipelineStepInjector(c.Get <IPipeline>()) .OnReceive(c.Get <AuditingSteps>(), PipelineRelativePosition.After, typeof(DispatchIncomingMessageStep)) .OnSend(c.Get <AuditingSteps>(), PipelineRelativePosition.After, typeof(SendOutgoingMessageStep))); }
/// <summary> /// Configures Rebus to use Correlate as the Correlation ID provider by resolving Correlate dependencies using the specified <paramref name="dependencyResolverAdapter"/>. /// </summary> /// <param name="configurer">The options configurer.</param> /// <param name="dependencyResolverAdapter">The dependency resolver adapter to resolve Correlate dependencies with.</param> /// <returns>The <see cref="OptionsConfigurer"/> instance.</returns> public static OptionsConfigurer EnableCorrelate(this OptionsConfigurer configurer, DependencyResolverAdapter dependencyResolverAdapter) { if (configurer == null) { throw new ArgumentNullException(nameof(configurer)); } if (dependencyResolverAdapter == null) { throw new ArgumentNullException(nameof(dependencyResolverAdapter)); } // Register Correlate steps using custom resolver. return(configurer .RegisterSteps(dependencyResolverAdapter) .ConfigurePipeline()); }
public static void EnableOpenTelemetry(this OptionsConfigurer configurer) { configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var step = new OutgoingDiagnosticsStep(); return(new PipelineStepInjector(pipeline).OnSend(step, PipelineRelativePosition.Before, typeof(SerializeOutgoingMessageStep))); }); configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var step = new IncomingDiagnosticsStep(); return(new PipelineStepInjector(pipeline).OnReceive(step, PipelineRelativePosition.Before, typeof(DeserializeIncomingMessageStep))); }); }
/// <summary> /// Enables idempotent sagas. When enabled, sagas derived from <see cref="IdempotentSaga{TSagaData}"/> can be truly idempotent. /// This means that the saga instance stores the IDs of all handled messages, including all outgoing messages send when handling /// each incoming message - this way, the saga instance can guard itself against handling the same message twice, while still /// preserving externally visible behavior even when a message gets handled more than once. /// </summary> public static void EnableIdempotentSagas(this OptionsConfigurer configurer) { configurer.Decorate <IPipeline>(c => { var transport = c.Get <ITransport>(); var pipeline = c.Get <IPipeline>(); var incomingStep = new IdempotentSagaIncomingStep(transport); var outgoingStep = new IdempotentSagaOutgoingStep(); var injector = new PipelineStepInjector(pipeline) .OnReceive(incomingStep, PipelineRelativePosition.Before, typeof(DispatchIncomingMessageStep)) .OnSend(outgoingStep, PipelineRelativePosition.After, typeof(SendOutgoingMessageStep)); return(injector); }); }
private static OptionsConfigurer RegisterSteps(this OptionsConfigurer configurer, IResolutionContext?resolver = null) { configurer.Register(ctx => new CorrelateOutgoingMessageStep( (resolver ?? ctx).Get <ICorrelationContextAccessor>(), (resolver ?? ctx).Get <ICorrelationIdFactory>(), ctx.Get <IRebusLoggerFactory>() ) ); configurer.Register(ctx => new CorrelateIncomingMessageStep( (resolver ?? ctx).Get <IAsyncCorrelationManager>(), ctx.Get <IRebusLoggerFactory>() ) ); return(configurer); }
/// <summary> /// Replaces the worker factory with one based on TPL /// </summary> public static void UseTplToReceiveMessages(this OptionsConfigurer configurer) { configurer.Register <IWorkerFactory>(c => { var transport = c.Get <ITransport>(); var loggerFactory = c.Get <IRebusLoggerFactory>(); return(new TplWorkerFactory( transport, loggerFactory, c.Get <IPipelineInvoker>(), c.Get <Options>(), c.Get <RebusBus>, c.Get <BusLifetimeEvents>(), c.Get <IBackoffStrategy>() )); }); }
/// <summary> /// Enables async/await-based request/reply whereby a request can be sent using the <see cref="SendRequest{TReply}"/> method /// which can be awaited for a corresponding reply. /// </summary> public static void EnableSynchronousRequestReply(this OptionsConfigurer configurer, int replyMaxAgeSeconds = 10) { configurer.Register(c => { var rebusLoggerFactory = c.Get <IRebusLoggerFactory>(); var asyncTaskFactory = c.Get <IAsyncTaskFactory>(); var replyMaxAge = TimeSpan.FromSeconds(replyMaxAgeSeconds); var step = new ReplyHandlerStep(Messages, rebusLoggerFactory, asyncTaskFactory, replyMaxAge); return(step); }); configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var step = c.Get <ReplyHandlerStep>(); return(new PipelineStepInjector(pipeline) .OnReceive(step, PipelineRelativePosition.Before, typeof(ActivateHandlersStep))); }); }
/// <summary> /// Enables message validation for incoming messages using FluentValidation. /// <para> /// When an incoming message fails to validate, by default it is wrapped in a <see cref="IValidationFailed{TMessage}"/> message and dispatched to handlers implementing this wrapped message type. Use the <paramref name="onFailed"/> builder to configure if messages should be handled differently (f.ex. move to error queue, drop, etc.). /// </para> /// </summary> /// <param name="configurer">The options configurer.</param> /// <param name="validatorFactory">The FluentValidation validator factory to resolve message validators from.</param> /// <param name="onFailed">A builder to configure how messages should be handled when validation fails.</param> public static void ValidateIncomingMessages(this OptionsConfigurer configurer, IValidatorFactory validatorFactory, Action <ValidationConfigurer>?onFailed = null) { if (configurer is null) { throw new ArgumentNullException(nameof(configurer)); } if (validatorFactory is null) { throw new ArgumentNullException(nameof(validatorFactory)); } var opts = new ValidationConfigurer(configurer); onFailed?.Invoke(opts); configurer.Register(ctx => { IRebusLoggerFactory loggerFactory = ctx.Get <IRebusLoggerFactory>(); return(new ValidateIncomingStep( loggerFactory.GetLogger <ValidateIncomingStep>(), validatorFactory, ctx.Get <IReadOnlyDictionary <Type, IValidationFailedStrategy> >(), // By default, handle as IValidationFailed<> ctx.Get <WrapAsValidationFailed>() )); }); configurer.Decorate <IPipeline>(ctx => { IPipeline pipeline = ctx.Get <IPipeline>(); var pipelineInjector = new PipelineStepInjector(pipeline); ValidateIncomingStep incomingStep = ctx.Get <ValidateIncomingStep>(); pipelineInjector.OnReceive( incomingStep, PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep) ); return(pipelineInjector); }); }
/// <summary> /// Propagates the ClaimsPrincipal through the message bus so that its there during message evaluation /// </summary> public static void AutomaticallyPropagateCurrentClaimsPrincipal(this OptionsConfigurer configurer) { if (!configurer.Has <IClaimsPrinicpalSerializer>()) { configurer.Register <IClaimsPrinicpalSerializer>(c => new DefaultClaimsPrinicpalSerializer()); } configurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var serializer = c.Get <IClaimsPrinicpalSerializer>(); var outgoingStep = new CapturePrincipalInOutgoingMessage(serializer); var incomingStep = new RestorePrincipalFromIncomingMessage(serializer); return(new PipelineStepInjector(pipeline) .OnSend(outgoingStep, PipelineRelativePosition.After, typeof(AssignTypeHeaderStep)) .OnReceive(incomingStep, PipelineRelativePosition.Before, typeof(ActivateHandlersStep))); }); }
/// <summary> /// Configures the simple retry strategy, using the specified error queue address and number of delivery attempts /// </summary> /// <param name="optionsConfigurer">(extension method target)</param> /// <param name="errorQueueAddress">Specifies the name of the error queue</param> /// <param name="maxDeliveryAttempts">Specifies how many delivery attempts should be made before forwarding a failed message to the error queue</param> /// <param name="secondLevelRetriesEnabled">Specifies whether second level retries should be enabled - when enabled, the message will be dispatched wrapped in an <see cref="IFailed{TMessage}"/> after the first <paramref name="maxDeliveryAttempts"/> delivery attempts, allowing a different handler to handle the message. Dispatch of the <see cref="IFailed{TMessage}"/> is subject to the same <paramref name="maxDeliveryAttempts"/> delivery attempts</param> /// <param name="errorDetailsHeaderMaxLength">Specifies a MAX length of the error details to be enclosed as the <see cref="Headers.ErrorDetails"/> header. As the enclosed error details can sometimes become very long (especially when using many delivery attempts), depending on the transport's capabilities it might sometimes be necessary to truncate the error details</param> /// <param name="errorTrackingMaxAgeMinutes">Specifies the max age of in-mem error trackings, for tracked messages that have not had any activity registered on them.</param> public static void SimpleRetryStrategy(this OptionsConfigurer optionsConfigurer, string errorQueueAddress = SimpleRetryStrategySettings.DefaultErrorQueueName, int maxDeliveryAttempts = SimpleRetryStrategySettings.DefaultNumberOfDeliveryAttempts, bool secondLevelRetriesEnabled = false, int errorDetailsHeaderMaxLength = int.MaxValue, int errorTrackingMaxAgeMinutes = SimpleRetryStrategySettings.DefaultErrorTrackingMaxAgeMinutes ) { if (optionsConfigurer == null) { throw new ArgumentNullException(nameof(optionsConfigurer)); } optionsConfigurer.Register(c => { var settings = new SimpleRetryStrategySettings( errorQueueAddress, maxDeliveryAttempts, secondLevelRetriesEnabled, errorDetailsHeaderMaxLength, errorTrackingMaxAgeMinutes ); return(settings); }); if (secondLevelRetriesEnabled) { optionsConfigurer.Decorate <IPipeline>(c => { var pipeline = c.Get <IPipeline>(); var errorTracker = c.Get <IErrorTracker>(); var incomingStep = new FailedMessageWrapperStep(errorTracker); var outgoingStep = new VerifyCannotSendFailedMessageWrapperStep(); return(new PipelineStepInjector(pipeline) .OnReceive(incomingStep, PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep)) .OnSend(outgoingStep, PipelineRelativePosition.Before, typeof(SerializeOutgoingMessageStep))); }); } }