public void GetSpecificConfigurationTypeWithIncorrectTypeProducesNothing() { var genericType = typeof(NonSerializedAttribute); var actual = ServiceBusQueueCommandPublisherConfiguration <object> .GetSpecificConfigurationType(genericType); actual.Should().BeNull("because the generic type did not correspond to a specific type"); }
public void GetSpecificConfigurationTypeProducesWithASpecificTypeProducesTheCorrectType() { var expectedType = typeof(ProcessOrderServiceBusQueueCommandPublisherConfiguration); var actual = ServiceBusQueueCommandPublisherConfiguration <object> .GetSpecificConfigurationType(expectedType); actual.Should().NotBeNull("because the specific type should have been located"); actual.ShouldBeEquivalentTo(expectedType, "because the correct type should have been located"); }
/// <summary> /// Creates a client that can be used for publishing to the queue. /// </summary> /// /// <param name="configuration">The configuration to use for queue client creation.</param> /// /// <returns>The queue client to use for publishing commands.</returns> /// protected virtual QueueClient CreateQueueClient(ServiceBusQueueCommandPublisherConfiguration <T> configuration) { var client = QueueClient.CreateFromConnectionString(configuration.ServiceBusConnectionString, configuration.QueueName); client.RetryPolicy = new RetryExponential( TimeSpan.FromSeconds(configuration.RetryMinimalBackoffTimeSeconds), TimeSpan.FromSeconds(configuration.RetryMaximumlBackoffTimeSeconds), configuration.RetryMaximumAttempts); return(client); }
/// <summary> /// Initializes a new instance of the <see cref="ServiceBusQueueCommandPublisher{T}" /> class. /// </summary> /// /// <param name="logger">The logger to use for any telemetry.</param> /// <param name="configuration">The configuration to use for command publication.</param> /// public ServiceBusQueueCommandPublisher(ILogger logger, ServiceBusQueueCommandPublisherConfiguration <T> configuration) { this.Log = logger ?? throw new ArgumentNullException(nameof(logger)); this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); this.queueClient = new Lazy <QueueClient>(() => this.CreateQueueClient(this.configuration), LazyThreadSafetyMode.PublicationOnly); this.serializer = new JsonSerializer { ContractResolver = new CamelCasePropertyNamesContractResolver() }; this.serializer.Converters.Add(new StringEnumConverter()); }
public async Task PublishAsyncSendsAMessage() { var called = false; var configuration = new ServiceBusQueueCommandPublisherConfiguration <ProcessOrder>(); Func <BrokeredMessage, Instant?, Task> sendMessage = (message, publishTime) => { called = true; return(Task.CompletedTask); }; var testPublisher = new TestPublisher <ProcessOrder>(Mock.Of <ILogger>(), configuration, sendMessage); await testPublisher.PublishAsync(new ProcessOrder()); called.Should().BeTrue("because a message should have been sent to the queue"); }
public async Task PublishAsynPublishesAtTheRequestedTime() { var scheduledTime = default(Instant?); var configuration = new ServiceBusQueueCommandPublisherConfiguration <ProcessOrder>(); Func <BrokeredMessage, Instant?, Task> sendMessage = (message, publishTime) => { scheduledTime = publishTime; return(Task.CompletedTask); }; var testPublisher = new TestPublisher <ProcessOrder>(Mock.Of <ILogger>(), configuration, sendMessage); var expectedTime = Instant.FromDateTimeUtc(new DateTime(2012, 08, 24, 05, 15, 44, DateTimeKind.Utc)); await testPublisher.PublishAsync(new ProcessOrder(), expectedTime); scheduledTime.HasValue.Should().BeTrue("because the scheduled time should be set"); scheduledTime.Value.ShouldBeEquivalentTo(expectedTime, "because the scheduled time should honor the requested publish time"); }
public void ClientCreationSetsTheRetryPolicy() { var configuration = new ServiceBusQueueCommandPublisherConfiguration <ProcessOrder> { ServiceBusConnectionString = "Endpoint=sb://someorderfulfillment.servicebus.windows.net/;SharedAccessKeyName=Fulfillment-App;SharedAccessKey=3L/M5xPb7Lh4KSXJAj6h/8egK9EEZdKyYdt0at21mLI=", QueueName = "fake-queue", RetryMaximumAttempts = 2, RetryMinimalBackoffTimeSeconds = 3, RetryMaximumlBackoffTimeSeconds = 4 }; var publisher = new ServiceBusQueueCommandPublisher <ProcessOrder>(Mock.Of <ILogger>(), configuration); var client = (QueueClient)typeof(ServiceBusQueueCommandPublisher <ProcessOrder>).GetMethod("CreateQueueClient", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(publisher, new [] { configuration }); var policy = client.RetryPolicy as RetryExponential; policy.Should().NotBeNull("because the retry policy should have been set"); policy.MaxRetryCount.Should().Be(configuration.RetryMaximumAttempts, "because the configuration should have been used to set the max attempts"); policy.MaximumBackoff.TotalSeconds.Should().Be(configuration.RetryMaximumlBackoffTimeSeconds, "because configuration should have been used to set the max backoff time"); policy.MinimalBackoff.TotalSeconds.Should().Be(configuration.RetryMinimalBackoffTimeSeconds, "because the configuration should have been used to set the min backoff time"); }
/// <summary> /// Performs the tasks needed to configure dependency injection for use with Web API /// and other consumers of the HTTP configuration. /// </summary> /// /// <param name="config">The HTTP configuration to be used for DI configuration.</param> /// internal static IContainer CreateDependencyResolver(Func <IConfigurationFactory> createConfigurationFactoryDelegate = null) { var orderSubmitterAssembly = typeof(EntryPoint).Assembly; var coreAssembly = typeof(IConfigurationFactory).Assembly; var builder = new ContainerBuilder(); // Infrastructure dependencies var serializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; serializerSettings.Converters.Add(new StringEnumConverter()); var serializer = new JsonSerializer { ContractResolver = new CamelCasePropertyNamesContractResolver() }; serializer.Converters.Add(new StringEnumConverter()); builder .RegisterInstance(serializer) .AsSelf() .SingleInstance(); builder .RegisterInstance(serializerSettings) .AsSelf() .SingleInstance(); builder .RegisterInstance(SystemClock.Instance) .AsImplementedInterfaces(); // Configuration dependencies builder .RegisterInstance(createConfigurationFactoryDelegate?.Invoke() ?? new ApplicationSettingsConfigurationFactory()) .AsImplementedInterfaces() .SingleInstance(); builder .RegisterAssemblyTypes(orderSubmitterAssembly, coreAssembly) .AssignableTo <IConfiguration>() .AsSelf() .OnActivating(args => args.ReplaceInstance(args.Context.Resolve <IConfigurationFactory>().Create(args.Instance.GetType()))); builder .RegisterGeneric(typeof(ServiceBusQueueCommandPublisherConfiguration <>)) .AsSelf() .OnActivating(args => args.ReplaceInstance(args.Context.Resolve <IConfigurationFactory>().Create(ServiceBusQueueCommandPublisherConfiguration <object> .GetSpecificConfigurationType(args.Instance.GetType())))); builder .RegisterGeneric(typeof(ServiceBusTopicEventPublisherConfiguration <>)) .AsSelf() .OnActivating(args => args.ReplaceInstance(args.Context.Resolve <IConfigurationFactory>().Create(ServiceBusTopicEventPublisherConfiguration <object> .GetSpecificConfigurationType(args.Instance.GetType())))); // Logging dependencies var logBuilder = new LoggerConfiguration() .WriteTo.Trace() .WriteTo.Console() .WriteTo.ApplicationInsightsEvents(new TelemetryClient(TelemetryConfiguration.Active), logEventToTelemetryConverter: EntryPoint.ConvertLogEventToTelementry); builder .RegisterInstance(logBuilder.CreateLogger()) .AsImplementedInterfaces(); // Event and Command dependencies builder .RegisterGeneric(typeof(ServiceBusQueueCommandPublisher <>)) .As(typeof(ICommandPublisher <>)) .SingleInstance(); builder .RegisterGeneric(typeof(ServiceBusTopicEventPublisher <>)) .As(typeof(IEventPublisher <>)) .SingleInstance(); // External collaboration dependencies builder .RegisterType <EcommerceClient>() .AsImplementedInterfaces() .SingleInstance(); builder .RegisterType <OrderProductionClient>() .AsImplementedInterfaces() .SingleInstance(); builder .RegisterType <OrderSubmissionBlobStorage>() .AsImplementedInterfaces() .SingleInstance(); builder .RegisterType <SkuMetadataBlobStorage>() .AsImplementedInterfaces() .SingleInstance(); // Order Submission dependencies builder .RegisterAssemblyTypes(orderSubmitterAssembly, coreAssembly) .AssignableTo <IOrderSubmitter>() .AsImplementedInterfaces() .SingleInstance(); // Web Job Function dependencies builder .RegisterType <CommandRetryThresholds>() .AsSelf() .OnActivating(args => args.ReplaceInstance(args.Context.Resolve <OrderSubmitterJobHostConfiguration>().CreateCommandRetryThresholdsFromConfiguration())); builder .RegisterAssemblyTypes(orderSubmitterAssembly, coreAssembly) .AssignableTo <WebJobFunctionBase>() .AsSelf() .WithParameter(new ResolvedParameter((pi, ctx) => ((pi.ParameterType == typeof(IDisposable)) && (pi.Name == "lifetimeScope")), (pi, ctx) => ctx.Resolve <ILifetimeScope>())); // Create and return the container. return(builder.Build()); }
/// <summary> /// Performs the tasks needed to configure dependency injection for use with Web API /// and other consumers of the HTTP configuration. /// </summary> /// /// <param name="config">The HTTP configuration to be used for DI configuration.</param> /// internal static void ConfigureDependencyResolver(HttpConfiguration config, Func <IConfigurationFactory> createConfigurationFactoryDelegate = null) { if (config == null) { throw new ArgumentNullException(nameof(config)); } var apiAssembly = typeof(Startup).Assembly; var coreAssembly = typeof(IConfigurationFactory).Assembly; var builder = new ContainerBuilder(); // Infrastructure dependencies builder.Register <IClock>(context => SystemClock.Instance); // Configuration dependencies builder .RegisterInstance(createConfigurationFactoryDelegate?.Invoke() ?? new ApplicationSettingsConfigurationFactory()) .AsImplementedInterfaces() .SingleInstance(); builder .RegisterAssemblyTypes(apiAssembly, coreAssembly) .AssignableTo <IConfiguration>() .AsSelf() .OnActivating(args => args.ReplaceInstance(args.Context.Resolve <IConfigurationFactory>().Create(args.Instance.GetType()))); builder .RegisterGeneric(typeof(ServiceBusQueueCommandPublisherConfiguration <>)) .AsSelf() .OnActivating(args => args.ReplaceInstance(args.Context.Resolve <IConfigurationFactory>().Create(ServiceBusQueueCommandPublisherConfiguration <object> .GetSpecificConfigurationType(args.Instance.GetType())))); builder .RegisterGeneric(typeof(ServiceBusTopicEventPublisherConfiguration <>)) .AsSelf() .OnActivating(args => args.ReplaceInstance(args.Context.Resolve <IConfigurationFactory>().Create(ServiceBusTopicEventPublisherConfiguration <object> .GetSpecificConfigurationType(args.Instance.GetType())))); // Logging dependencies var logBuilder = new LoggerConfiguration() .WriteTo.Trace() .WriteTo.Console() .WriteTo.ApplicationInsightsEvents(new TelemetryClient(TelemetryConfiguration.Active), logEventToTelemetryConverter: Startup.ConvertLogEventToTelementry); builder .RegisterInstance(logBuilder.CreateLogger()) .AsImplementedInterfaces(); // Validation dependencies builder .RegisterAssemblyTypes(apiAssembly, coreAssembly) .AssignableTo <IPropertyValidator>() .AsSelf() .SingleInstance(); builder .RegisterAssemblyTypes(apiAssembly, coreAssembly) .AsClosedTypesOf(typeof(IMessageValidator <>)) .SingleInstance(); // Security dependencies builder .RegisterAssemblyTypes(apiAssembly, coreAssembly) .AssignableTo <IAuthenticationHandler>() .As <IAuthenticationHandler>() .PreserveExistingDefaults(); builder .RegisterAssemblyTypes(apiAssembly, coreAssembly) .AssignableTo <IAuthorizationPolicy>() .As <IAuthorizationPolicy>() .PreserveExistingDefaults(); // Event and Command dependencies builder .RegisterGeneric(typeof(ServiceBusQueueCommandPublisher <>)) .As(typeof(ICommandPublisher <>)) .SingleInstance(); builder .RegisterGeneric(typeof(ServiceBusTopicEventPublisher <>)) .As(typeof(IEventPublisher <>)) .SingleInstance(); // API dependencies builder.RegisterType <HttpHeaderParser>() .AsImplementedInterfaces() .SingleInstance(); builder.RegisterType <GlobalExceptionFilter>(); builder.RegisterApiControllers(apiAssembly); builder.RegisterWebApiFilterProvider(config); // Finalize the resolver, using the configured dependencies. config.DependencyResolver = new AutofacWebApiDependencyResolver(builder.Build()); }
public TestPublisher(ILogger logger, ServiceBusQueueCommandPublisherConfiguration <T> configuration, Func <BrokeredMessage, Instant?, Task> sendMessageAsyncDelegate) : base(logger, configuration) { this.sendMessageAsyncDelegate = sendMessageAsyncDelegate ?? ((message, time) => Task.CompletedTask); }
public async Task PublishAsyncSendsAMessageThatMatchesTheCommand() { using (var messageBody = new MemoryStream()) { var message = default(BrokeredMessage); var configuration = new ServiceBusQueueCommandPublisherConfiguration <ProcessOrder>(); Func <BrokeredMessage, Instant?, Task> sendMessage = (msg, time) => { msg.GetBody <Stream>().CopyTo(messageBody); messageBody.Seek(0, SeekOrigin.Begin); message = msg.Clone(); return(Task.CompletedTask); }; var command = new ProcessOrder { OrderId = "ABC123", PartnerCode = "SQUIRE", Assets = new Dictionary <string, string> { { "one", "val1" }, { "two", "val2" } }, Emulation = null, Id = Guid.NewGuid(), CorrelationId = Guid.NewGuid().ToString(), OccurredTimeUtc = new DateTime(2017, 01, 05, 5, 10, 30, DateTimeKind.Utc), CurrentUser = null, Sequence = 65 }; var testPublisher = new TestPublisher <ProcessOrder>(Mock.Of <ILogger>(), configuration, sendMessage); await testPublisher.PublishAsync(command); message.CorrelationId.Should().Be(command.CorrelationId, "because the correlation id should have been copied to the message"); message.MessageId.Should().Be(command.Id.ToString(), "because the command id should have been copied to the message"); message.ContentType.Should().Be(MimeTypes.Json, "becaue the message should have the correct type"); var serializer = new JsonSerializer { ContractResolver = new CamelCasePropertyNamesContractResolver() }; serializer.Converters.Add(new StringEnumConverter()); var messageCommand = default(ProcessOrder); using (var reader = new StreamReader(messageBody)) using (var jsonReader = new JsonTextReader(reader)) { messageCommand = serializer.Deserialize <ProcessOrder>(jsonReader); reader.Close(); jsonReader.Close(); } messageCommand.ShouldBeEquivalentTo(command, "because the commands should match"); messageBody?.Close(); message?.Dispose(); } }