示例#1
0
        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");
        }
示例#2
0
        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");
        }
示例#3
0
        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());
        }
示例#6
0
        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");
        }
示例#7
0
        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");
        }
示例#8
0
 public TestPublisher(ILogger logger,
                      ServiceBusTopicEventPublisherConfiguration <T> configuration,
                      Func <BrokeredMessage, Task> sendMessageAsyncDelegate) : base(logger, configuration)
 {
     this.sendMessageAsyncDelegate = sendMessageAsyncDelegate ?? (_ => Task.CompletedTask);
 }
示例#9
0
        /// <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());
        }
示例#10
0
        /// <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());
        }