// Inject background service, for receiving message
        public void ConfigureServices(IServiceCollection services)
        {
            var serviceProvider  = services.BuildServiceProvider();
            var loggerFactorySrv = serviceProvider.GetService <ILoggerFactory>();

            services.AddDbContextPool <CustomerDbContext>(options => options.UseSqlServer(
                                                              _systemLocalConfiguration.EventDbConnection,
                                                              //enable connection resilience
                                                              connectOptions =>
            {
                connectOptions.EnableRetryOnFailure();
                connectOptions.CommandTimeout(Identifiers.TimeoutInSec);
            })   //.UseLoggerFactory(loggerFactorySrv)// to log queries
                                                          );

            //add application insights information, could be used to monitor the performance, and more analytics when application moved to the cloud.
            loggerFactorySrv.AddApplicationInsights(services.BuildServiceProvider(), LogLevel.Information);

            ILogger _logger = loggerFactorySrv
                              .AddConsole()
                              .AddDebug()
                              .AddFile(Configuration.GetSection("Logging"))
                              .CreateLogger <Startup>();



            // no need to inject the following service since, currently they are injected for the mediator.

            services.AddSingleton <MiddlewareConfiguration, MiddlewareConfiguration>(srv => _systemLocalConfiguration);

            services.AddScoped <IOperationalUnit, IOperationalUnit>(srv => new OperationalUnit(
                                                                        environment: Environemnt.EnvironmentName,
                                                                        assembly: AssemblyName));

            services.AddScoped <IMessageCommand, RabbitMQPublisher>(srv => new RabbitMQPublisher(loggerFactorySrv,
                                                                                                 new RabbitMQConfiguration
            {
                hostName = _systemLocalConfiguration.MessagesMiddleware,
                exchange = _systemLocalConfiguration.MiddlewareExchange,
                userName = _systemLocalConfiguration.MessagesMiddlewareUsername,
                password = _systemLocalConfiguration.MessagesMiddlewarePassword,
                routes   = new string[] { _systemLocalConfiguration.MessagePublisherRoute }
            }));
            services.AddOptions();

            #region workers

            #region customer worker

            services.AddSingleton <IHostedService, RabbitMQSubscriberWorker>(srv =>
            {
                //get Vehicle service
                var customerSrv = new CustomerManager(loggerFactorySrv, srv.GetService <CustomerDbContext>());
                var cacheSrv    = new CacheManager(Logger, _systemLocalConfiguration.CacheServer);
                return(new RabbitMQSubscriberWorker
                           (serviceProvider, loggerFactorySrv, new RabbitMQConfiguration
                {
                    hostName = _systemLocalConfiguration.MessagesMiddleware,
                    exchange = _systemLocalConfiguration.MiddlewareExchange,
                    userName = _systemLocalConfiguration.MessagesMiddlewareUsername,
                    password = _systemLocalConfiguration.MessagesMiddlewarePassword,
                    routes = _systemLocalConfiguration.MessageSubscriberRoute?.Split('-') ?? new string[0]
                }
                           , (messageCallback) =>
                {
                    try
                    {
                        var message = messageCallback();
                        if (message != null)
                        {
                            var domainModel = Utilities.JsonBinaryDeserialize <DomainModels.Business.CustomerDomain.CustomerModel>(message);
                            var customer = new CustomerSQLDB.DbModels.Customer(domainModel.Body);
                            customerSrv.Add(customer).Wait();
                            cacheSrv.SetBinary(customer.Id.ToString(), Utilities.JsonBinarySerialize(customer)).Wait();
                        }
                        Logger.LogInformation($"[x] Customer service receiving a message from exchange: {_systemLocalConfiguration.MiddlewareExchange}, route :{_systemLocalConfiguration.MessageSubscriberRoute}");
                    }
                    catch (System.Exception ex)
                    {
                        Logger.LogCritical(ex, "Object de-serialization exception.");
                    }
                }));
            });

            #endregion

            #region tracking customer query client

            services.AddScoped <IMessageRequest <CustomerFilterModel, IEnumerable <DomainModels.Business.CustomerDomain.Customer> >,
                                RabbitMQRequestClient <CustomerFilterModel, IEnumerable <DomainModels.Business.CustomerDomain.Customer> > >(
                srv =>
            {
                return(new RabbitMQRequestClient <CustomerFilterModel, IEnumerable <DomainModels.Business.CustomerDomain.Customer> >
                           (loggerFactorySrv, new RabbitMQConfiguration
                {
                    exchange = "",
                    hostName = _systemLocalConfiguration.MessagesMiddleware,
                    userName = _systemLocalConfiguration.MessagesMiddlewareUsername,
                    password = _systemLocalConfiguration.MessagesMiddlewarePassword,
                    routes = new string[] { "rpc_queue_customer_filter" },
                }));
            });

            #endregion

            #region customer query worker
            // business logic
            services.AddSingleton <IHostedService, RabbitMQRequestWorker>(srv =>
            {
                var customerSrv = new CustomerManager(loggerFactorySrv, srv.GetService <CustomerDbContext>());

                return(new RabbitMQRequestWorker
                           (serviceProvider, loggerFactorySrv, new RabbitMQConfiguration
                {
                    exchange = "",
                    hostName = _systemLocalConfiguration.MessagesMiddleware,
                    userName = _systemLocalConfiguration.MessagesMiddlewareUsername,
                    password = _systemLocalConfiguration.MessagesMiddlewarePassword,
                    routes = new string[] { "rpc_queue_customer_filter" },
                }
                           , (customerFilterMessageRequest) =>
                {
                    try
                    {
                        //TODO: add business logic, result should be serializable
                        var customerFilter = Utilities.JsonBinaryDeserialize <CustomerFilterModel>(customerFilterMessageRequest);
                        Logger.LogInformation($"[x] callback of RabbitMQ customer worker=> a message");
                        var response = customerSrv.Query((c) =>
                        {
                            return c.CorrelationId == customerFilter.Body?.CorrelationId;
                        })?.ToList();
                        if (response == null)
                        {
                            return new byte[0];
                        }
                        return Utilities.JsonBinarySerialize(response);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogCritical(ex, "Object de-serialization exception.");
                        //to respond back to RPC client
                        return new byte[0];
                    }
                }));
            });
            #endregion

            #region tracking vehicle query client

            services.AddScoped <IMessageRequest <VehicleFilterModel, IEnumerable <Vehicle> >,
                                RabbitMQRequestClient <VehicleFilterModel, IEnumerable <Vehicle> > >(
                srv =>
            {
                return(new RabbitMQRequestClient <VehicleFilterModel, IEnumerable <Vehicle> >
                           (loggerFactorySrv, new RabbitMQConfiguration
                {
                    exchange = "",
                    hostName = _systemLocalConfiguration.MessagesMiddleware,
                    userName = _systemLocalConfiguration.MessagesMiddlewareUsername,
                    password = _systemLocalConfiguration.MessagesMiddlewarePassword,
                    routes = new string[] { "rpc_queue_vehicle_filter" },
                }));
            });

            #endregion

            #endregion

            ///
            /// Injecting message receiver background service
            ///

            services.AddDistributedRedisCache(redisOptions =>
            {
                redisOptions.Configuration = _systemLocalConfiguration.CacheServer;
                redisOptions.Configuration = _systemLocalConfiguration.VehiclesCacheDB;
            });

            services.AddApiVersioning(options =>
            {
                options.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(1, 0);
                options.AssumeDefaultVersionWhenUnspecified = true;
                options.ReportApiVersions = true;
            });

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info {
                    Title = AssemblyName, Version = "v1"
                });
            });

            services.AddMediatR();

            var _operationalUnit = new OperationalUnit(
                environment: Environemnt.EnvironmentName,
                assembly: AssemblyName);

            services.AddMvc(options =>
            {
                //TODO: add practical policy instead of empty policy for authentication / authorization .
                options.Filters.Add(new CustomAuthorizer(_logger, _operationalUnit));
                options.Filters.Add(new CustomeExceptoinHandler(_logger, _operationalUnit, Environemnt));
                options.Filters.Add(new CustomResponseResult(_logger, _operationalUnit));
            });
        }