Files
BusinessMgr-2019/SaBusMgrCoreWeb/Web/App/SbmStartup_Web.cs
T

221 lines
7.8 KiB
C#

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Net.Http.Headers;
using Sarand.BusinessMgr.Net.Core.Web.Middleware;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
namespace Sarand.BusinessMgr.Net.Core.Web.App
{
//=======================================================================
public class SbmStartup_Web : SacsDisposable
{
//-------------------------------------------------------------------
// Data members.
// Localisation.
private static RequestCulture defaultRequestCulture = new RequestCulture("en-GB", "en-GB");
private static List<CultureInfo> supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-GB"),
new CultureInfo("en-US"),
new CultureInfo("en"),
new CultureInfo("fr-FR"),
new CultureInfo("fr"),
};
//-------------------------------------------------------------------
// Protected construction.
protected SbmStartup_Web(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
}
}
//-------------------------------------------------------------------
// Properties.
public IConfiguration Configuration { get; }
public static RequestCulture DefaultRequestCulture { get { return defaultRequestCulture; } }
public static List<CultureInfo> SupportedCultures { get { return new List<CultureInfo>(supportedCultures); } }
//-------------------------------------------------------------------
// This method gets called by the runtime. Use this method to add services to the container.
protected class ConfigureServicesConfig
{
public IServiceCollection services;
public String sessionCookieName;
public bool sessionCookieHttpOnly;
public TimeSpan sessionIdleTimeout;
}
protected void ConfigureServices(ConfigureServicesConfig config)
{
// Authentication service.
// Required to handle 'Forbidden' responses etc.
config.services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "forbidScheme";
options.DefaultForbidScheme = "forbidScheme";
options.AddScheme<SbmAuthenticationHandler>("forbidScheme", "Handle Forbidden");
});
// Periodic housekeeping.
config.services.AddHostedService<SbmHousekeepingService>();
// Added to support memory caching of sessions.
config.services.AddMemoryCache();
//config.services.AddDistributedMemoryCache(); - for multiple web servers.
// Online web application cookie definition.
config.services.AddSession
(options =>
{
options.Cookie.Name = config.sessionCookieName;
options.Cookie.HttpOnly = config.sessionCookieHttpOnly;
options.IdleTimeout = config.sessionIdleTimeout;
// Override cookie policy for session cookie. Ref. config.app.UseCookiePolicy()
options.Cookie.IsEssential = true;
}
);
// Localisation properties folder.
String resourcesPath = "Localisation";
config.services.AddLocalization(opts => { opts.ResourcesPath = resourcesPath; });
// Modify pages during debug.
#if DEBUG
if (SbmSystem.DebugMode)
// If the following line throws an error such as:
// 'imvcbuilder' does not contain a definition for 'addrazorruntimecompilation'
// Revert the NuGet Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package
// to a previous version and then reinstal the latest version.
config.services.AddRazorPages().AddRazorRuntimeCompilation();
#endif
config.services.AddMvc
(options =>
{
// Model binding - intercepting form values being bound to models.
options.ModelBinderProviders.Insert(0, new SbmModelBinderProvider());
// Blank form values to be populated to model as empty strings rather than null values.
options.ModelMetadataDetailsProviders.Add(new SbmMetadataProvider());
}
)
// View and data annotation localisations.
.AddViewLocalization(
LanguageViewLocationExpanderFormat.Suffix,
opts => { opts.ResourcesPath = resourcesPath; })
.AddDataAnnotationsLocalization()
// Ignore null values during object serialiation.
.AddJsonOptions(options => { options.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull; });
// Jun24 Was: .AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = true; });
// Configure localisation middleware.
config.services.Configure<RequestLocalizationOptions>
(opts =>
{
// Default culture to use for requests.
opts.DefaultRequestCulture = DefaultRequestCulture;
// Cultures supported by the application. Formatting numbers, dates, etc.
opts.SupportedCultures = SupportedCultures;
// UI cultures supported by the application. UI strings that have been localized.
opts.SupportedUICultures = SupportedCultures;
}
);
// Allows access to the HttpContext inside a service.
config.services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
//-------------------------------------------------------------------
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
protected class ConfigureConfig
{
public IApplicationBuilder app;
public IHostApplicationLifetime hostApplicationLifetime;
public IWebHostEnvironment env;
}
protected void Configure(ConfigureConfig config)
{
if (config.env.IsDevelopment())
{
config.app.UseDeveloperExceptionPage();
}
else
{
config.app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
config.app.UseHsts();
}
config.app.UseHttpsRedirection();
config.app.UseStaticFiles();
config.app.UseCookiePolicy();
config.app.UseSession();
config.app.UseRouting();
//config.app.UseAuthorization();
config.app.UseAntiforgeryTokens();
config.app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
// Application events.
// NB The shutdown events only fire if he application stops 'gracefully'.
config.hostApplicationLifetime.ApplicationStarted.Register(OnApplicationStarted);
config.hostApplicationLifetime.ApplicationStopping.Register(OnApplicationStopping);
config.hostApplicationLifetime.ApplicationStopped.Register(OnApplicationStopped);
config.app.Use(async (context, next) =>
{
if (context.Request.Method.Equals(HttpMethod.Get.Method))
{
context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
//context.Response.Headers[HeaderNames.Vary] = new string[] { "Accept-Encoding" };
}
await next();
});
}
//-------------------------------------------------------------------
// Application events.
private readonly static String ApplicationEventLogPrefix = "### ";
private void OnApplicationStarted()
{
SaLogger.Info(ApplicationEventLogPrefix + "Application started");
}
private void OnApplicationStopping()
{
SaLogger.Info(ApplicationEventLogPrefix + "Application stopping");
}
private void OnApplicationStopped()
{
SaLogger.Info(ApplicationEventLogPrefix + "Application stopped");
}
//-------------------------------------------------------------------
}
//=======================================================================
}