Example #1
0
        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>();
Example #2
0
        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();
        }
Example #4
0
        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>();
Example #5
0
        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();
            }
        }
Example #6
0
        // 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);
        }