// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { //Set the injected loggerFactory (which is used by ASP.NET logging messages) as the singleton instance to use everywhere NewAlbumsLogging.ConfigureLogger(loggerFactory); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); var options = new RewriteOptions() .AddRedirectToHttps(301) .Add(new NonWwwRule()); app.UseRewriter(options); } //NWebSec extensions //Other headers, from: https://damienbod.com/2018/02/08/adding-http-headers-to-improve-security-in-an-asp-net-mvc-core-application/ app.UseXContentTypeOptions(); app.UseReferrerPolicy(opts => opts.OriginWhenCrossOrigin()); app.UseXXssProtection(opts => opts.EnabledWithBlockMode()); app.UseXfo(options => options.Deny()); app.UseCsp(opts => opts .BlockAllMixedContent() .StyleSources(s => s.Self()) .StyleSources(s => s.CustomSources("https://fonts.googleapis.com")) .StyleSources(s => s.UnsafeInline()) .FontSources(s => s.Self()) .FontSources(s => s.CustomSources("https://fonts.gstatic.com")) .FormActions(s => s.Self()) .FrameAncestors(s => s.Self()) .ImageSources(s => s.Self()) .ImageSources(s => s.CustomSources("https://i.scdn.co", "https://www.google-analytics.com")) //.ImageSources(s => s.CustomSources("data:")) .ScriptSources(s => s.Self()) //Needed for webpackHotDevClient in development, and when compiled for production. //TODO implement nonces instead .ScriptSources(s => s.UnsafeInline()) .ScriptSources(s => s.CustomSources("https://www.google-analytics.com", "https://storage.googleapis.com")) ); app.UseHttpsRedirection(); //10 mins in dev, 365 days in production var maxAge = env.IsDevelopment() ? TimeSpan.FromMinutes(10) : TimeSpan.FromDays(365); app.UseStaticFiles(new StaticFileOptions { OnPrepareResponse = ctx => { var headers = ctx.Context.Response.GetTypedHeaders(); headers.CacheControl = new CacheControlHeaderValue { Public = true, MaxAge = maxAge }; } }); app.UseSpaStaticFiles(new StaticFileOptions { OnPrepareResponse = ctx => { var headers = ctx.Context.Response.GetTypedHeaders(); headers.CacheControl = new CacheControlHeaderValue { Public = true, MaxAge = maxAge }; } }); //From: https://code-maze.com/aspnetcore-webapi-best-practices/ app.UseExceptionHandler(config => { config.Run(async context => { context.Response.StatusCode = 500; context.Response.ContentType = "application/json"; var error = context.Features.Get <IExceptionHandlerFeature>(); if (error != null) { var ex = error.Error; var apiResponse = new ApiResponse(500, ex.Message); string json = JsonConvert.SerializeObject(apiResponse); await context.Response.WriteAsync(json); } }); }); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); app.UseSpa(spa => { spa.Options.SourcePath = "ClientApp"; if (env.IsDevelopment()) { spa.UseReactDevelopmentServer(npmScript: "start"); } }); //Set the App_Data directory so we can retrieve it later. https://stackoverflow.com/a/48357218 AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(env.ContentRootPath, "App_Data")); }
protected BaseController() { //Resolve from singleton so we don't need to pass ILogger into constructor of //every controller derived from BaseController Logger = NewAlbumsLogging.GetLogger(GetType()); }
/// <summary> /// See appsettings.json for where to configure various settings required by this console app /// (user-secrets in dev, Azure app service Connection Strings and Application Settings in production) /// </summary> static async Task Main(string[] args) { var builder = new HostBuilder(); IConfiguration configuration = null; builder.ConfigureHostConfiguration(configHost => { configHost.SetBasePath(Directory.GetCurrentDirectory()); configHost.AddJsonFile("hostsettings.json", optional: true); //Need to manually read ASPNETCORE_ENVIRONMENT or else it'll default to Production //See: https://github.com/aspnet/AspNetCore/issues/4150 configHost.AddInMemoryCollection(new[] { new KeyValuePair <string, string>( HostDefaults.EnvironmentKey, System.Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")) }); configHost.AddEnvironmentVariables(); }); builder.ConfigureAppConfiguration((hostContext, configApp) => { configApp.SetBasePath(Directory.GetCurrentDirectory()); configApp.AddJsonFile("appsettings.json", optional: true); configApp.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true); configApp.AddEnvironmentVariables(); if (hostContext.HostingEnvironment.EnvironmentName.ToLower() == "development") { configApp.AddUserSecrets <Program>(); } configuration = configApp.Build(); }); builder.ConfigureWebJobs(b => { b.AddAzureStorageCoreServices(); b.AddAzureStorage(); }); builder.ConfigureLogging((context, b) => { b.AddConsole(); }); builder.ConfigureServices((context, serviceCollection) => { //Need to do this or later when IConfiguration is injected, it'll be missing our user secrets configured for dev above serviceCollection.AddSingleton <IConfiguration>(configuration); serviceCollection.AddDbContext <NewAlbumsDbContext>(options => options.UseSqlServer(configuration.GetConnectionString("Default"))); serviceCollection.GenericServicesSimpleSetup <NewAlbumsDbContext>( new GenericServicesConfig { NoErrorOnReadSingleNull = true }, Assembly.GetAssembly(typeof(BaseAppService)) ); serviceCollection.AddAutoMapper(typeof(IArtistAppService)); //NewsAlbums.Application services serviceCollection.AddTransient <ISpotifyAppService, SpotifyAppService>(); serviceCollection.AddTransient <IArtistAppService, ArtistAppService>(); serviceCollection.AddTransient <IAlbumAppService, AlbumAppService>(); serviceCollection.AddTransient <ISubscriberAppService, SubscriberAppService>(); serviceCollection.AddTransient <ISubscriptionAppService, SubscriptionAppService>(); //NewAlbums.Core managers serviceCollection.AddTransient <EmailManager>(); serviceCollection.AddTransient <TemplateManager>(); serviceCollection.AddTransient <IPathProvider, PathProvider>(); var serviceProvider = serviceCollection.BuildServiceProvider(); var loggerFactory = serviceProvider.GetService <ILoggerFactory>(); string configFileName = "log4net.config"; if (context.HostingEnvironment.EnvironmentName.ToLower() != "development") { configFileName = "log4net.azure.config"; } //Set the retrieved loggerFactory (which is used by ASP.NET logging messages) as the singleton instance to use everywhere NewAlbumsLogging.ConfigureLogger(loggerFactory, configFileName); }); //Set the App_Data directory so we can retrieve it later. https://stackoverflow.com/a/48357218 //string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(Directory.GetCurrentDirectory(), "App_Data")); var host = builder.Build(); using (host) { await host.StartAsync(); var jobHost = host.Services.GetService(typeof(IJobHost)) as JobHost; await jobHost.CallAsync(typeof(Functions).GetMethod("ProcessNewSpotifyAlbums")); await host.StopAsync(); } }
protected BaseManager() { //Resolve from singleton so we don't need to pass ILogger into constructor of //every app service derived from BaseAppService Logger = NewAlbumsLogging.GetLogger(GetType()); }