public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; config.AddJsonFile($"appsettings.json", true, true); // First, AppSettings (general) config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true); // Then, AppSettings (specific environment) config.AddEnvironmentVariables(); // Then, Environment variables if (args != null) { config.AddCommandLine(args); // Then, CommandLine arguments } }) .UseSerilog((ctx, config) => { var shouldFormatElastic = ctx.Configuration.GetValue <bool>("LOG_ELASTICFORMAT", false); config .ReadFrom.Configuration(ctx.Configuration) // Read from appsettings and env, cmdline .Enrich.FromLogContext() .Enrich.WithExceptionDetails(); var logFormatter = new ExceptionAsObjectJsonFormatter(renderMessage: true); var logMessageTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"; if (shouldFormatElastic) { config.WriteTo.Console(logFormatter, standardErrorFromLevel: LogEventLevel.Error); } else { config.WriteTo.Console(standardErrorFromLevel: LogEventLevel.Error, outputTemplate: logMessageTemplate); } }) .UseStartup <Startup>();
public static int Main(string[] args) { var formatter = new ExceptionAsObjectJsonFormatter( renderMessage: true, inlineFields: true ); Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .Enrich.FromLogContext() .WriteTo.Console(formatter) .CreateLogger(); try { Log.Information("Starting web host"); CreateWebHostBuilder(args).Build().Run(); return(0); } catch (Exception ex) { Log.Fatal(ex, "Host terminated unexpectedly"); return(1); } finally { Log.CloseAndFlush(); } }
private static void ConfigureLogging(IConfigurationRoot configuration, string environmentName) { var isDevelopment = string.Equals( environmentName, "local", StringComparison.OrdinalIgnoreCase); var useJsonStdout = !isDevelopment; Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .Enrich.WithProperty("assemblyVersion", Version) .WriteTo.Async(config => { if (useJsonStdout) { var formatter = new ExceptionAsObjectJsonFormatter(renderMessage: true, inlineFields: true); config.Console(formatter); } else { config.ColoredConsole(); } }) .CreateLogger(); }
public void ConfigureServices(IServiceCollection services) { var formatElastic = Configuration.GetValue("FormatLogsInElasticFormat", false); // Logger configuration var logConf = new LoggerConfiguration() .ReadFrom.Configuration(Configuration); if (formatElastic) { var logFormatter = new ExceptionAsObjectJsonFormatter(renderMessage: true); logConf.WriteTo.Console(logFormatter); } else { logConf.WriteTo.Console(); } Log.Logger = logConf.CreateLogger(); services.AddMvc().AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }); var auth0Section = Configuration.GetSection("Auth0"); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.Authority = auth0Section.GetValue <string>("TenantDomain"); options.Audience = "https://api.gigdata.openplatforms.org"; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" }; options.Events = new JwtBearerEvents { OnTokenValidated = async context => { if (string.IsNullOrEmpty(context.Principal.Identity.Name)) { return; } var cache = context.HttpContext.RequestServices.GetRequiredService <IMemoryCache>(); var cacheEntry = cache.Get(context.Principal.Identity.Name); if (cacheEntry != null) { return; } var cacheEntryOptions = new MemoryCacheEntryOptions() // Keep in cache for this time, reset time if accessed. .SetAbsoluteExpiration(TimeSpan.FromSeconds(60)).SetSize(1); cache.Set(context.Principal.Identity.Name, true, cacheEntryOptions); var userManager = context.HttpContext.RequestServices.GetRequiredService <IUserManager>(); var documentStore = context.HttpContext.RequestServices.GetRequiredService <IDocumentStore>(); using var session = documentStore.OpenAsyncSession(); var auth0Client = context.HttpContext.RequestServices.GetRequiredService <Auth0ManagementApiHttpClient>(); var userInfo = await auth0Client.GetUserProfile(context.Principal.Identity.Name); var user = await userManager.GetOrCreateUserIfNotExists(context.Principal.Identity.Name, session); user.Name = userInfo.Name; var userEmailState = UserEmailState.Unverified; if (userInfo.EmailVerified) { userEmailState = UserEmailState.Verified; } var existingUserEmail = user.UserEmails.SingleOrDefault(ue => string.Equals(ue.Email, userInfo.Email, StringComparison.InvariantCultureIgnoreCase)); if (existingUserEmail == null) //email does not exist at all { user.UserEmails.Add(new UserEmail(userInfo.Email.ToLowerInvariant(), userEmailState)); } else if (existingUserEmail.UserEmailState != UserEmailState.Verified && userEmailState == UserEmailState.Verified) //email has been verified through Auth0 { existingUserEmail.SetEmailState(UserEmailState.Verified); } if (session.Advanced.HasChanges) { await session.SaveChangesAsync(); } } }; }); var rabbitMqConnectionString = Configuration.GetConnectionString("RabbitMq"); services.AddRebus(c => c .Transport(t => t.UseRabbitMqAsOneWayClient(rabbitMqConnectionString)) .Timeouts(t => t.StoreInMemory()) .Routing(r => r.TypeBased() .Map <FetchDataForPlatformConnectionMessage>("platformdatafetcher.input") .Map <PlatformConnectionUpdateNotificationMessage>("platformdatafetcher.input")) ); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
static async Task Main() { var builder = new HostBuilder(); builder.ConfigureHostConfiguration(configHost => { configHost.SetBasePath(Directory.GetCurrentDirectory()); configHost.AddInMemoryCollection(new[] { new KeyValuePair <string, string>(HostDefaults.EnvironmentKey, Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")), }) .AddEnvironmentVariables(); }).ConfigureAppConfiguration((hostContext, configApp) => { configApp.SetBasePath(Directory.GetCurrentDirectory()); configApp.AddJsonFile("appsettings.json", false, true); configApp.AddJsonFile( $"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true); configApp.AddJsonFile("/app/secrets/appsettings.secrets.json", optional: true); configApp.AddJsonFile("appsettings.local.json", optional: true, reloadOnChange: false); //load local settings configApp.AddEnvironmentVariables(); }).ConfigureLogging((hostContext, configLogging) => { var formatElastic = hostContext.Configuration.GetValue("FormatLogsInElasticFormat", false); var logConf = new LoggerConfiguration() .ReadFrom.Configuration(hostContext.Configuration); if (formatElastic) { var logFormatter = new ExceptionAsObjectJsonFormatter(renderMessage: true); logConf.WriteTo.Console(logFormatter); } else { logConf.WriteTo.Console(); } Log.Logger = logConf.CreateLogger(); configLogging.AddSerilog(dispose: true); }).ConfigureServices((hostContext, services) => { var serviceProvider = services.BuildServiceProvider(); var logger = serviceProvider.GetRequiredService <ILogger <Program> >(); services.AddGigDataApiEngine(); services.AddGigDataApiEngineDataFetching(hostContext.Configuration); services.AddGigDataApiEnginePlatformAuthentication(hostContext.Configuration); services.AutoRegisterHandlersFromAssemblyOf <DataFetchCompleteHandler>(); services.AutoRegisterHandlersFromAssemblyOf <DataFetchCompleteMessageHandler>(); //Gigplatform data update handler. var rebusSection = hostContext.Configuration.GetSection("Rebus"); var inputQueueName = rebusSection.GetValue <string>("InputQueueName"); var errorQueueName = rebusSection.GetValue <string>("ErrorQueueName"); var timeoutsFilesystemFolder = rebusSection.GetValue <string>("TimeoutsFilesystemFolder"); services.Configure <RebusConfiguration>(c => { c.InputQueueName = inputQueueName; c.ErrorQueueName = errorQueueName; }); var rabbitMqConnectionString = hostContext.Configuration.GetConnectionString("RabbitMq"); var rabbitMqConnectionEndpoint = new ConnectionEndpoint { ConnectionString = rabbitMqConnectionString }; var jsonSerializerSettings = new JsonSerializerSettings { ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor, ContractResolver = new PrivateResolver() }; services.AddRebus(c => c .Transport(t => t.UseRabbitMq(new List <ConnectionEndpoint> { rabbitMqConnectionEndpoint }, inputQueueName)) .Timeouts(t => { if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { //we can't use file system since it uses locking api on the underlying file stream which is not supported on OS X. //See: https://github.com/dotnet/coreclr/commit/0daa63e9ed40323b6f248ded8959530ea94f19aa t.StoreInMemory(); } else { t.UseFileSystem(timeoutsFilesystemFolder); } }) .Options(o => { o.SimpleRetryStrategy(errorQueueAddress: errorQueueName, secondLevelRetriesEnabled: true); o.SetNumberOfWorkers(1); o.SetMaxParallelism(1); }) .Logging(l => l.Serilog()) .Routing(r => r.TypeBased() .Map <FetchDataForPlatformConnectionMessage>(inputQueueName) .Map <PlatformConnectionUpdateNotificationMessage>(inputQueueName)) .Serialization(s => s.UseNewtonsoftJson(jsonSerializerSettings)) ); if (hostContext.HostingEnvironment.IsDevelopment()) { services.AddDistributedMemoryCache(); } else { services.AddDistributedRedisCache(a => { a.Configuration = hostContext.Configuration.GetConnectionString("Redis"); a.InstanceName = "master"; }); } var ravenDbSection = hostContext.Configuration.GetSection("RavenDb"); var urls = new List <string>(); ravenDbSection.GetSection("Urls").Bind(urls); var databaseName = ravenDbSection.GetValue <string>("DatabaseName"); var certPwd = ravenDbSection.GetValue <string>("CertPwd"); var certPath = ravenDbSection.GetValue <string>("CertPath"); var keyPath = ravenDbSection.GetValue <string>("KeyPath"); logger.LogInformation($"Will use the following database name: '{databaseName}'"); logger.LogInformation($"Will use the following database urls: {string.Join(", ", urls)}"); DocumentStoreHolder.Logger = logger; DocumentStoreHolder.Urls = urls.ToArray(); DocumentStoreHolder.DatabaseName = databaseName; DocumentStoreHolder.CertPwd = certPwd; DocumentStoreHolder.CertPath = certPath; DocumentStoreHolder.KeyPath = keyPath; DocumentStoreHolder.TypeInAssemblyContainingIndexesToCreate = typeof(Users_ByPlatformConnectionPossiblyRipeForDataFetch); services.AddSingleton(DocumentStoreHolder.Store); services.AddHostedService <TimedDataFetcherTriggerTask>(); }); var host = builder.Build(); using (host) { var logger = host.Services.GetRequiredService <ILogger <Program> >(); logger.LogInformation("Setting up handler for unhandled exceptions."); var currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledException += (sender, eventArgs) => { var exception = (Exception)eventArgs.ExceptionObject; logger.LogError(exception, "Got unhandled exception"); }; logger.LogInformation("Will start Rebus"); host.Services.UseRebus(); logger.LogInformation("Starting host."); await host.RunAsync(); } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var formatElastic = Configuration.GetValue("FormatLogsInElasticFormat", false); // Logger configuration var logConf = new LoggerConfiguration() .ReadFrom.Configuration(Configuration); if (formatElastic) { var logFormatter = new ExceptionAsObjectJsonFormatter(renderMessage: true); logConf.WriteTo.Console(logFormatter); } else { logConf.WriteTo.Console(); } Log.Logger = logConf.CreateLogger(); services.AddMvc(options => { options.Filters.Add(new ApiExceptionFilter()); }); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = ApiKeyAuthenticationOptions.DefaultScheme; options.DefaultChallengeScheme = ApiKeyAuthenticationOptions.DefaultScheme; }) .AddApiKeySupport(options => { }); // Document store for Raven services.AddRavenDb(Configuration); // Platform engine services.AddPlatformEngine(Configuration); // Connectivity services.AddPlatformEndpointConnectivity(); // Swagger services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "GigDataService Internal API", Version = "v1", Description = "API intended for triggering data fetching of platform data." }); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath, includeControllerXmlComments: true); c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme { Description = "API key Authorization header (x-api.key). \r\n\r\n " + $"Enter your api key in the text input below.\r\n\r\n" + $"Example: \"12345abcdef\"", Type = SecuritySchemeType.ApiKey, Name = "x-api-key", In = ParameterLocation.Header }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "ApiKey", Type = ReferenceType.SecurityScheme } }, new List <string>() } }); }); // Configure and register Rebus services.AutoRegisterHandlersFromAssemblyOf <PlatformUserDataMessageHandler>(); // Event dispatcher for messaging services.AddEventDispatcher(Configuration); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var formatElastic = Configuration.GetValue("FormatLogsInElasticFormat", false); // Logger configuration var logConf = new LoggerConfiguration() .ReadFrom.Configuration(Configuration); if (formatElastic) { var logFormatter = new ExceptionAsObjectJsonFormatter(renderMessage: true); logConf.WriteTo.Console(logFormatter); } else { logConf.WriteTo.Console(); } Log.Logger = logConf.CreateLogger(); // configure jwt authentication var domain = $"https://{Configuration["Auth0:Domain"]}/"; services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.Authority = domain; x.Audience = Configuration["Auth0:Audience"]; x.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" }; x.Events = new JwtBearerEvents { OnTokenValidated = async context => { var userService = context.HttpContext.RequestServices.GetRequiredService <IPlatformAdminUserManager>(); var documentStore = context.HttpContext.RequestServices.GetRequiredService <IDocumentStore>(); var uniqueIdentifier = context.Principal.Identity.Name; var auth0Client = context.HttpContext.RequestServices.GetRequiredService <Auth0Client>(); var authorizationValue = context.HttpContext.Request.Headers["Authorization"].First(); var accessToken = authorizationValue.Substring("Bearer".Length).Trim(); var userInfo = await auth0Client.GetUserInfo(accessToken); using var session = documentStore.OpenAsyncSession(); var user = await userService.GetOrCreateUserAsync(uniqueIdentifier, session); user.Name = userInfo.Name; user.Email = userInfo.Email; await session.SaveChangesAsync(); } }; }); services.AddCors(options => { options.AddPolicy(name: AllowSpecificOrigins, builder => { builder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); services.AddHttpClient <Auth0Client>(client => { client.BaseAddress = new Uri(domain); }); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); services.AddScoped <ApiExceptionFilter>(); services.AddMvc(options => { options.Filters.Add(typeof(ApiExceptionFilter)); options.Filters.Add(typeof(ValidateModelStateAttribute)); }) .AddNewtonsoftJson(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Include; //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; }); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "GigPlatform Client Api (internal)", Version = "v1", Contact = new OpenApiContact { Email = "*****@*****.**", Name = "Calle Hunefalk" } }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n " + $"Enter your token in the text input below.\r\n\r\n" + $"Example: \"12345abcdef\"", Type = SecuritySchemeType.Http, Scheme = "bearer" }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }, new List <string>() } }); c.DescribeAllParametersInCamelCase(); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); }); //Add functionality to inject IOptions<T> services.AddOptions(); // RavenDb services.AddRavenDb(Configuration); services.AddDevPortalDependencies(Configuration); services.AddEventDispatcher(Configuration); services.AddPlatformEngine(Configuration); services.AddPlatformEndpointConnectivity(); services.AddGigDataApiConnectivity(Configuration); }