public void GetSpecificConfigurationTypeWithIncorrectTypeProducesNothing() { var genericType = typeof(NonSerializedAttribute); var actual = ServiceBusTopicEventPublisherConfiguration <object> .GetSpecificConfigurationType(genericType); actual.Should().BeNull("because the generic type did not correspond to a specific type"); }
public void GetSpecificConfigurationTypeProducesWithASpecificTypeProducesTheCorrectType() { var expectedType = typeof(EventBaseServiceBusTopicEventPublisherConfiguration); var actual = ServiceBusTopicEventPublisherConfiguration <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"); }
public async Task PublishAsyncSendsAMessageThatMatchesTheEvents() { using (var messageBody = new MemoryStream()) { var message = default(BrokeredMessage); var configuration = new ServiceBusTopicEventPublisherConfiguration <EventBase>(); Func <BrokeredMessage, Task> sendMessage = msg => { msg.GetBody <Stream>().CopyTo(messageBody); messageBody.Seek(0, SeekOrigin.Begin); message = msg.Clone(); return(Task.CompletedTask); }; var @event = new OrderReceived { OrderId = "ABC123", PartnerCode = "SQUIRE", 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 <EventBase>(Mock.Of <ILogger>(), configuration, sendMessage); await testPublisher.PublishAsync(@event); message.CorrelationId.Should().Be(@event.CorrelationId, "because the correlation id should have been copied to the message"); message.MessageId.Should().Be(@event.Id.ToString(), "because the event 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 messageEvent = default(EventBase); using (var reader = new StreamReader(messageBody)) using (var jsonReader = new JsonTextReader(reader)) { messageEvent = serializer.Deserialize <EventBase>(jsonReader); reader.Close(); jsonReader.Close(); } messageEvent.ShouldBeEquivalentTo(@event, "because the events should match"); messageBody?.Close(); message?.Dispose(); } }
/// <summary> /// Creates a client that can be used for publishing to the topic. /// </summary> /// /// <param name="configuration">The configuration to use for topic client creation.</param> /// /// <returns>The topic client to use for publishing events.</returns> /// protected virtual TopicClient CreateTopicClient(ServiceBusTopicEventPublisherConfiguration <T> configuration) { var client = TopicClient.CreateFromConnectionString(configuration.ServiceBusConnectionString, configuration.TopicName); 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="ServiceBusTopicEventdPublisher{T}" /> class. /// </summary> /// /// <param name="logger">The logger to use for any telemetry.</param> /// <param name="configuration">The configuration to use for event publication.</param> /// public ServiceBusTopicEventPublisher(ILogger logger, ServiceBusTopicEventPublisherConfiguration <T> configuration) { this.Log = logger ?? throw new ArgumentNullException(nameof(logger)); this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); this.topicClient = new Lazy <TopicClient>(() => this.CreateTopicClient(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 ServiceBusTopicEventPublisherConfiguration <EventBase>(); Func <BrokeredMessage, Task> sendMessage = message => { called = true; return(Task.CompletedTask); }; var testPublisher = new TestPublisher <EventBase>(Mock.Of <ILogger>(), configuration, sendMessage); await testPublisher.PublishAsync(new OrderReceived()); called.Should().BeTrue("because a message should have been sent to the topic"); }
public void ClientCreationSetsTheRetryPolicy() { var configuration = new ServiceBusTopicEventPublisherConfiguration <EventBase> { ServiceBusConnectionString = "Endpoint=sb://someorderfulfillment.servicebus.windows.net/;SharedAccessKeyName=Fulfillment-App;SharedAccessKey=3L/M5xPb7Lh4KSXJAj6h/8egK9EEZdKyYdt0at21mLI=", TopicName = "fake-topic", RetryMaximumAttempts = 7, RetryMinimalBackoffTimeSeconds = 6, RetryMaximumlBackoffTimeSeconds = 8 }; var publisher = new ServiceBusTopicEventPublisher <EventBase>(Mock.Of <ILogger>(), configuration); var client = (TopicClient)typeof(ServiceBusTopicEventPublisher <EventBase>).GetMethod("CreateTopicClient", 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"); }
public TestPublisher(ILogger logger, ServiceBusTopicEventPublisherConfiguration <T> configuration, Func <BrokeredMessage, Task> sendMessageAsyncDelegate) : base(logger, configuration) { this.sendMessageAsyncDelegate = sendMessageAsyncDelegate ?? (_ => Task.CompletedTask); }
/// <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()); }