Exemple #1
0
        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");
        }
Exemple #2
0
        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");
        }
Exemple #3
0
        /// <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);
        }
Exemple #4
0
        /// <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");
        }
Exemple #8
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());
        }
Exemple #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 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();
            }
        }