using Marten; using Netina.Domain.Entities.Users; using Netina.Domain.Models.Settings; using Netina.Repository.Extensions; using Netina.Repository.Models; using Weasel.Core; namespace Netina.Api.WebFramework.Configurations; public static class ServiceExtensions { public static void AddIpRateLimit(this IServiceCollection services, IConfigurationRoot configuration) { //load general configuration from appsettings.json services.Configure(configuration.GetSection("IpRateLimiting")); //load ip rules from appsettings.json services.Configure(configuration.GetSection("IpRateLimitPolicies")); // inject counter and rules stores //services.AddInMemoryRateLimiting(); services.AddSingleton(); services.AddSingleton(); services.AddDistributedRateLimiting(); services.AddDistributedRateLimiting(); services.AddRedisRateLimiting(); // configuration (resolvers, counter key builders) services.AddSingleton(); } public static void AddCustomStackExchangeRedis(this IServiceCollection serviceCollection, SiteSettings siteSettings) { serviceCollection.AddStackExchangeRedisExtensions(options => { return new List { new() { Hosts = new[] { new RedisHost { Port = siteSettings.MasterRedisConfiguration.Port, Host = siteSettings.MasterRedisConfiguration.Host } }, Password = siteSettings.MasterRedisConfiguration.Password, Ssl = false } }; }); } public static void AddCustomDbContext(this IServiceCollection serviceCollection, IConfigurationRoot Configuration) { serviceCollection.AddDbContextFactory(options => { options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); options.UseNpgsql(Configuration.GetConnectionString("Postgres"), b => b.MigrationsAssembly("Netina.Repository")) .UseProjectAssembly(typeof(ApplicationUser).Assembly); //options.EnableServiceProviderCaching(true); }).BuildServiceProvider(); AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); } public static void AddMarten(this IServiceCollection serviceCollection, IConfigurationRoot configuration , IWebHostEnvironment environment) { serviceCollection.AddMarten(options => { // Establish the connection string to your Marten database options.Connection(configuration.GetConnectionString("MartenDB")!); // If we're running in development mode, let Marten just take care // of all necessary schema building and patching behind the scenes if (environment.IsDevelopment()) { options.AutoCreateSchemaObjects = AutoCreate.All; } }); } public static void AddCustomResponseCompression(this IServiceCollection serviceCollection) { serviceCollection.Configure(options => options.Level = CompressionLevel.Fastest); serviceCollection.AddResponseCompression(options => { options.Providers.Add(); options.EnableForHttps = true; }); } public static void AddCustomCores(this IServiceCollection serviceCollection) { serviceCollection.AddCors(options => options.AddPolicy("CorsPolicy", builder => { builder.AllowAnyMethod() .SetPreflightMaxAge(TimeSpan.FromHours(24)) .WithExposedHeaders("Access-control-allow-origins") .AllowAnyHeader() .SetIsOriginAllowed(_ => true) .AllowCredentials(); })); } public static void AddCustomController(this IServiceCollection serviceCollection) { serviceCollection.AddControllers(options => { options.Filters.Add(new AuthorizeFilter()); }) .AddControllersAsServices() .AddNewtonsoftJson(options => { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //options.SerializerSettings.ContractResolver = new DefaultContractResolver(); } ); } public static void AddCustomMvc(this IServiceCollection serviceCollection) { serviceCollection .AddMvc() .AddNewtonsoftJson(options => { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); } public static void AddCustomAuthorization(this IServiceCollection serviceCollection) { serviceCollection.AddAuthorization(); } public static void AddJwtCustomAuthentication(this IServiceCollection serviceCollection, JwtSettings jwtSettings) { serviceCollection.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { var secretKey = Encoding.UTF8.GetBytes(jwtSettings.SecretKey); var validateParammetrs = new TokenValidationParameters { ClockSkew = TimeSpan.Zero, RequireSignedTokens = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(secretKey), RequireExpirationTime = true, ValidateLifetime = true, ValidateAudience = true, ValidAudience = jwtSettings.Audience, ValidateIssuer = true, ValidIssuer = jwtSettings.Issuer }; options.RequireHttpsMetadata = true; options.SaveToken = true; options.TokenValidationParameters = validateParammetrs; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Query["access_token"]; // If the request is for our hub... var path = context.HttpContext.Request.Path; if (!string.IsNullOrEmpty(accessToken)) // Read the token out of the query string context.Token = accessToken.ToString(); return Task.CompletedTask; } }; }); } public static void AddCustomIdentity(this IServiceCollection serviceCollection) { serviceCollection.AddIdentity(options => { options.Password.RequireLowercase = false; options.Password.RequireUppercase = false; options.Password.RequireDigit = false; options.Password.RequireNonAlphanumeric = false; options.User.RequireUniqueEmail = false; }).AddEntityFrameworkStores() .AddDefaultTokenProviders() .AddErrorDescriber(); } public static void AddCustomApiVersioning(this IServiceCollection serviceCollection) { serviceCollection.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = new ApiVersion(1, 0); options.ApiVersionReader = new HeaderApiVersionReader("api-version"); options.ReportApiVersions = true; }); } }