using System; using System.Collections.Generic; using System.IO; using System.Linq; using Hangfire; using Hangfire.PostgreSql; using Erp.Languages; using Erp.MailQueue; using Erp.Notifications.Application; using Erp.Platform.Classrooms; using Erp.Platform.EntityFrameworkCore; using Erp.Reports; using Erp.SqlQueryManager; using Erp.Platform.Extensions; using Erp.Platform.FileManagement; using Erp.Platform.Identity; using Erp.Platform.Localization; using Erp.Settings; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Extensions.DependencyInjection; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; using OpenIddict.Server.AspNetCore; using OpenIddict.Validation.AspNetCore; using Volo.Abp; using Volo.Abp.Account.Web; using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling; using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; using Volo.Abp.BackgroundWorkers.Hangfire; using Volo.Abp.BlobStoring; using Volo.Abp.BlobStoring.FileSystem; using Volo.Abp.Caching; using Volo.Abp.Hangfire; using Volo.Abp.Identity; using Volo.Abp.Modularity; using Volo.Abp.Security.Claims; using Volo.Abp.Swashbuckle; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; using Erp.Platform.DynamicServices; using static Erp.Platform.PlatformConsts; using static Erp.Settings.SettingsConsts; using Hangfire.SqlServer; using DevExpress.AspNetCore; using DevExpress.AspNetCore.Reporting; using DevExpress.XtraReports.Web.Extensions; using Erp.Platform.ReportServices; namespace Erp.Platform; [DependsOn( typeof(PlatformHttpApiModule), typeof(AbpAutofacModule), typeof(AbpAspNetCoreMultiTenancyModule), typeof(PlatformApplicationModule), typeof(PlatformEntityFrameworkCoreModule), typeof(AbpAspNetCoreMvcUiBasicThemeModule), typeof(AbpAccountWebOpenIddictModule), typeof(AbpAspNetCoreSerilogModule), typeof(AbpSwashbuckleModule), typeof(AbpBackgroundWorkersHangfireModule), typeof(SqlQueryManagerApplicationModule), typeof(ErpReportsApplicationModule) )] public class PlatformHttpApiHostModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { PreConfigure(builder => { builder.AddServer(server => { server.SetAccessTokenLifetime(TimeSpan.FromMinutes(60)); server.SetRefreshTokenLifetime(TimeSpan.FromMinutes(90)); }); builder.AddValidation(options => { options.AddAudiences(PlatformConsts.AppName); options.UseLocalServer(); options.UseAspNetCore(); }); }); PreConfigure(builder => { builder.AddClaimsPrincipalFactory(); builder.AddSignInManager(); }); context.Services.Replace( ServiceDescriptor.Transient()); context.Services.AddTransient(); } public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); //Tenant bazında lokalizasyon ayarları için //TenantLocalization Middleware kaydı context.Services.AddTransient(); context.Services.AddTransient(); ConfigureAuthentication(context); ConfigureBundles(); ConfigureUrls(configuration); ConfigureConventionalControllers(); //Localization'ı veritabanından kullandıgımız icin bir json resource kullanmıyoruz //Dolayısıyla şimdilik ihtiyacımız yok ama ileride başka bir sebepten kullanabiliriz diye silmedik //ConfigureVirtualFileSystem(context); ConfigureCors(context, configuration); ConfigureSwaggerServices(context, configuration); ConfigureIdentity(configuration); ConfigureCache(); ConfigureHangfire(context, configuration); ConfigureBlobStoring(configuration); ConfigureAuditing(); ConfigureDynamicServices(context); ConfigureDevExpressReporting(context); context.Services.AddSignalR(); Configure(options => { options.Map(AppErrorCodes.NoAuth, System.Net.HttpStatusCode.Unauthorized); }); Configure(options => { options.DisableTransportSecurityRequirement = true; }); Configure(options => { options.Contributors.AddIfNotContains(new PlatformApplicationConfigurationContributor()); }); } private void ConfigureAuthentication(ServiceConfigurationContext context) { context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme); context.Services.Configure(options => { options.IsDynamicClaimsEnabled = true; }); } private void ConfigureBundles() { Configure(options => { options.StyleBundles.Configure( BasicThemeBundles.Styles.Global, bundle => { bundle.AddFiles("/global-styles.css"); } ); }); } private void ConfigureUrls(IConfiguration configuration) { Configure(options => { options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"]?.Split(',') ?? Array.Empty()); options.Applications[PlatformConsts.React].RootUrl = configuration["App:ClientUrl"]; options.Applications[PlatformConsts.React].Urls[PlatformConsts.Urls.EmailConfirmation] = "account/confirm"; options.Applications[PlatformConsts.React].Urls[PlatformConsts.Urls.PasswordReset] = "account/reset-password"; options.Applications[PlatformConsts.React].Urls[PlatformConsts.Urls.UserDetail] = "account/{0}"; //options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"]; //options.Applications["MVC"].Urls[PlatformConsts.Urls.EmailConfirmation] = "Account/Confirm"; //options.Applications["MVC"].Urls[PlatformConsts.Urls.TwoFactor] = "Account/TwoFactor"; //options.Applications["MVC"].Urls[PlatformConsts.Urls.Login] = "Account/Login"; //options.Applications["MVC"].Urls[PlatformConsts.Urls.UserDetail] = "Identity/Users/Detail"; }); } private void ConfigureConventionalControllers() { Configure(options => { options.ConventionalControllers.Create(typeof(PlatformApplicationModule).Assembly, opts => { opts.TypePredicate = t => t.Namespace == "Erp.Platform.ListForms.Administration"; opts.RootPath = "admin"; }); options.ConventionalControllers.Create(typeof(PlatformApplicationModule).Assembly, opts => { opts.TypePredicate = t => t.Namespace != "Erp.Platform.ListForms.Administration"; opts.RootPath = "app"; }); options.ConventionalControllers.Create(typeof(LanguagesApplicationModule).Assembly); options.ConventionalControllers.Create(typeof(SettingsApplicationModule).Assembly); options.ConventionalControllers.Create(typeof(ErpMailQueueModule).Assembly); options.ConventionalControllers.Create(typeof(NotificationApplicationModule).Assembly); options.ConventionalControllers.Create(typeof(SqlQueryManagerApplicationModule).Assembly); options.ConventionalControllers.Create(typeof(ErpReportsApplicationModule).Assembly); options.ChangeControllerModelApiExplorerGroupName = false; options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(PlatformUpdateProfileDto)); options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UploadFileDto)); }); } private void ConfigureVirtualFileSystem(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); if (hostingEnvironment.IsDevelopment()) { Configure(options => { options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Erp.Platform.Domain.Shared")); options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Erp.Platform.Domain")); options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Erp.Platform.Application.Contracts")); options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Erp.Platform.Application")); options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Erp.MailQueue")); }); } } private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddCors(options => { options.AddDefaultPolicy(builder => { builder .WithOrigins(configuration["App:CorsOrigins"]? .Split(",", StringSplitOptions.RemoveEmptyEntries) .Select(o => o.RemovePostFix("/")) .ToArray() ?? Array.Empty()) .WithAbpExposedHeaders() .WithExposedHeaders(["X-Correlation-Id"]) .SetIsOriginAllowedToAllowWildcardSubdomains() .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); } private void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddAbpSwaggerGenWithOAuth( configuration["AuthServer:Authority"], new Dictionary { {"Platform", "Erp Platform Api"} }, options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "Erp Platform Api", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); }); } private void ConfigureIdentity(IConfiguration configuration) { //Veritabanından yonetildigi icin bunlar kapatildi //Configure(options => //{ // options.SignIn.RequireConfirmedEmail = true; // options.SignIn.RequireConfirmedAccount = true; // options.SignIn.RequireConfirmedPhoneNumber = false; // options.User.RequireUniqueEmail = true; // options.Lockout.AllowedForNewUsers = true; // options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); // options.Lockout.MaxFailedAccessAttempts = 5; // options.Password.RequiredLength = 6; // options.Password.RequiredUniqueChars = 0; // options.Password.RequireNonAlphanumeric = false; // options.Password.RequireLowercase = false; // options.Password.RequireUppercase = false; // options.Password.RequireDigit = false; //}); Configure(configuration.GetSection(PlatformConsts.AbpIdentity.GroupName)); } private void ConfigureCache() { Configure(options => { options.KeyPrefix = PlatformConsts.AppName; }); Configure(options => { }); } private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration) { Configure(options => { options.ServerOptions = new BackgroundJobServerOptions { Queues = ["default", "platform"] }; }); if (DefaultDatabaseProvider == DatabaseProvider.PostgreSql) { context.Services.AddHangfire(options => { options.UsePostgreSqlStorage( configuration.GetConnectionString(DefaultDatabaseProvider), new PostgreSqlStorageOptions { PrepareSchemaIfNecessary = true }); }); } else if (DefaultDatabaseProvider == DatabaseProvider.SqlServer) { context.Services.AddHangfire(options => { options.UseSqlServerStorage( configuration.GetConnectionString(DefaultDatabaseProvider), new SqlServerStorageOptions { PrepareSchemaIfNecessary = true }); }); } } private void ConfigureBlobStoring(IConfiguration configuration) { Configure(options => { options.Containers.ConfigureDefault(container => { container.UseFileSystem(fileSystem => { fileSystem.BasePath = configuration["App:CdnPath"]; }); }); }); } private void ConfigureAuditing() { Configure(options => { options.IgnoredUrls.Add("/api/app/list-form-customization"); }); } private void ConfigureDynamicServices(ServiceConfigurationContext context) { // Dynamic AppService Background Service context.Services.AddHostedService(); // Roslyn Compiler context.Services.AddSingleton(); // Action descriptor change provider for runtime controller registration context.Services.AddSingleton(); context.Services.AddSingleton(sp => sp.GetRequiredService()); // Custom controller activator for dynamic dependency injection context.Services.AddSingleton(); } private void ConfigureDevExpressReporting(ServiceConfigurationContext context) { context.Services.AddDevExpressControls(); context.Services.ConfigureReportingServices(configurator => { configurator.ConfigureReportDesigner(designerConfigurator => { }); configurator.ConfigureWebDocumentViewer(viewerConfigurator => { viewerConfigurator.UseCachedReportSourceBuilder(); }); }); // Register report storage extension context.Services.AddScoped(); // Register custom SQL data connection provider context.Services.AddScoped(); context.Services.AddScoped(); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); var env = context.GetEnvironment(); // Setup delegate for dynamic service registration DynamicServiceCompiler.NotifyAssemblyRegistration = (tenantId, assembly, assemblyName) => { DynamicAssemblyRegistrationService.RequestAssemblyRegistration(tenantId, assembly, assemblyName); }; if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseAbpRequestLocalization(); // Auth hataları MVC tarafından /Error sayfasına yönlendirilmesin diye bu kaldırıldı // if (!env.IsDevelopment()) // { // app.UseErrorPage(); // } app.UseCorrelationId(); app.MapAbpStaticAssets(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAbpOpenIddictValidation(); app.UseMiddleware(); if (PlatformConsts.IsMultiTenant) { app.UseMultiTenancy(); app.UseMiddleware(); } app.UseUnitOfWork(); app.UseDynamicClaims(); app.UseAuthorization(); app.UseSwagger(); app.UseAbpSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Erp Platform Api"); var configuration = context.ServiceProvider.GetRequiredService(); c.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); c.OAuthScopes("Platform"); }); app.UseAuditing(); app.UseAbpSerilogEnrichers(); if (env.IsDevelopment()) { app.UseHangfireDashboard(); } else { app.UseHangfireDashboard("/hangfire", new DashboardOptions { AsyncAuthorization = [new AbpHangfireAuthorizationFilter()] }); } app.UseEndpoints(endpoints => { endpoints.MapHub("/classroomhub"); }); app.UseConfiguredEndpoints(); } }