// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddRazorPages(); services.AddSignalR(); // TODO: Change the ServiceLifetime. The usage of ServiceLifetime.Transient is because multiple threads operations are running in the same dbcontext. services.AddDbContext <DbContext, ApplicationDbContext>(ServiceLifetime.Transient); services.AddOrcEntityFrameworkCore(); services.AddDatabaseSeeder <ApplicationDbSeeder>(); var token = this.Configuration.GetSection("TelegramBot")?["Token"]; if (!string.IsNullOrWhiteSpace(token)) { if (token == "%TELEGRAM_BOT_TOKEN%") { Log.Warning( "Telegram notification is disable. Replace %TELEGRAM_BOT_TOKEN% placeholder in the configuration file with a valid bot token."); } else { Log.Information("Telegram notification is enable."); services.AddTransient <ITelegramBotClient>( sp => new TelegramBotClient(token)); services.AddSingleton <ITelegramCommander, TelegramCommander>(); } } else { Log.Warning( "Telegram notification is disable. To enable it, add a TelegramBot section with a key Token."); } HttpClientExtensions.Configure(this.Configuration); services.AddTransient(sp => new CookieContainer()); services.AddTransient(sp => BrowsingContext.New(AngleSharp.Configuration.Default)); services.AddTransient( sp => { var cookieContainer = sp.GetService <CookieContainer>(); var handler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.Brotli, AllowAutoRedirect = true }; if (cookieContainer != null) { handler.CookieContainer = cookieContainer; } var httpTimeoutInSeconds = this.Configuration.GetSection("Http")?["TimeoutInSeconds"]; var httpClient = new HttpClient(handler) { Timeout = float.TryParse( httpTimeoutInSeconds, out var timeoutInSeconds) ? TimeSpan.FromSeconds(timeoutInSeconds) : ScraperConfigurations.HttpClientTimeout }; httpClient.DefaultRequestHeaders.TryAddWithoutValidation( "user-agent", ScraperConfigurations.GetSupportedAgent()); httpClient.DefaultRequestHeaders.TryAddWithoutValidation( "accept-encoding", "gzip, deflate, br"); httpClient.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true }; return(httpClient); }); services.AddScoped <IStoreService, StoreService>(); services.AddSingleton <ICacheStorage <string, Product> >( provider => new CacheStorage <string, Product>(storeNullValues: true)); services.AddSingleton <ICacheStorage <string, Department> >( provider => new CacheStorage <string, Department>(storeNullValues: true)); services.AddSingleton <ICacheStorage <string, Store> >( provider => new CacheStorage <string, Store>(storeNullValues: true)); services.AddSingleton <ICookiesAwareHttpClientFactory, CookiesAwareHttpClientFactory>(); services.AddSingleton <IOfficialStoreInfoService, OfficialStoreInfoService>(); services.AddTransient <IEntityScraper <Product>, ProductScraper>(); services.AddTransient <IEntityScraper <Department>, DepartmentScraper>(); services.AddTransient <IEntityScraper <Store>, StoreScraper>(); services.AddTransient <IMultiEntityScraper <Product>, InspectDepartmentProductsScraper>(); services.AddTransient <IMultiEntityScraper <Department>, InspectStoreDepartmentsScraper>(); services.AddSingleton <ImportStoresHostedService>(); services.AddHostedService <AuthenticationHostedService>(); services.AddHostedService <DepartmentMonitorHostedService>(); // services.AddHostedService<ProductMonitorHostedService>(); services.AddHostedService <StoreMonitorHostedService>(); services.AddHostedService <CookieSerializationHostedService>(); // services.AddHostedService<SyncUsersFromTelegramHostedService>(); }