public abstract void ConfigureHangfire(TenantBuilderContext context, HangfireConfiguration configuration);
        public virtual void ConfigureServices(TenantBuilderContext context, IServiceCollection services)
        {
            var hangfireServicesAdded = context.RootServiceProvider.GetService <IGlobalConfiguration>() != null;

            //configuration
            var configuration = new HangfireConfiguration();

            context.Configuration.Bind("Hangfire", configuration);
            ConfigureHangfire(context, configuration);
            services.AddSingleton(configuration);

            //dashboard options
            var dashboardOptions = context.RootServiceProvider.GetService <DashboardOptions>()?.Clone() ?? new DashboardOptions();

            ConfigureHangfireDashboard(context, dashboardOptions);
            services.AddSingleton(dashboardOptions);

            //background processing server
            IBackgroundProcessingServer processingServer = null;

            //Storage
            if (configuration.Enabled)
            {
                var storageDetails = HangfireJobStorage.GetJobStorage(configuration.ConnectionString, options => {
                    options.PrepareSchemaIfNecessary = false;
                    options.EnableHeavyMigrations    = false;
                    options.EnableLongPolling        = configuration.EnableLongPolling;
                    options.SchemaName = configuration.SchemaName;
                });

                JobStorage storage = storageDetails.JobStorage;
                configuration.ExistingConnection = storageDetails.ExistingConnection;

                services.AddSingleton(storage);
                services.AddHangfireServerServices();

                Func <IServiceProvider, Action <IBackgroundProcessingServer> > processingServerSetter = ((sp) => (x) => { processingServer = x; });
                services.AddSingleton(processingServerSetter);
                Func <IServiceProvider, IBackgroundProcessingServer> processingServerAccessor = ((sp) => processingServer);
                services.AddSingleton(processingServerAccessor);

                var backgroundServerOptions = context.RootServiceProvider.GetService <BackgroundJobServerOptions>()?.Clone() ?? new BackgroundJobServerOptions();

                backgroundServerOptions.ServerName     = configuration.ServerName ?? backgroundServerOptions.ServerName;
                backgroundServerOptions.Activator      = new MultiTenantJobActivator(context.RootServiceProvider.GetRequiredService <MultitenantContainer>(), context.TenantId);
                backgroundServerOptions.FilterProvider = context.RootServiceProvider.GetService <IJobFilterProvider>() ?? new JobFilterCollection();

                ConfigureHangfireServer(context, backgroundServerOptions);

                services.AddSingleton(backgroundServerOptions);
            }
            else
            {
                if (hangfireServicesAdded)
                {
                    services.AddSingleton((JobStorage) new NoopJobStorage());
                    services.AddHangfireServerServices();
                }
            }

            //background processes
            ConfigureBackgroundProcesses(context, services);
        }