339 lines
12 KiB
C#
339 lines
12 KiB
C#
|
|
namespace Yes.Blog
|
|
{
|
|
public static class DependencyInjection
|
|
{
|
|
private readonly static Assembly[] Assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
|
|
|
|
|
public static IServiceCollection RegisterBlogModule(this IServiceCollection services, WebApplicationBuilder builder)
|
|
{
|
|
var env = builder.Environment;
|
|
var configuration = builder.BuildConfiguration();
|
|
|
|
services.AddConfiguration(configuration);
|
|
services.AddRazorPages();
|
|
services.AddEndpoints();
|
|
services.AddViewEngine(env);
|
|
services.ConfigureValidator();
|
|
services.AddAutoMapper();
|
|
services.AutoRegister();
|
|
services.AddMemoryCache();
|
|
services.AddBackgroundService();
|
|
services.AddMediatR();
|
|
services.AddHttpClient();
|
|
|
|
services.AddHttpContextAccessor();
|
|
|
|
services.AddAdminAuthentication(configuration);
|
|
|
|
services.AddAuthorization();
|
|
|
|
services.AddEndpointsApiExplorer();
|
|
|
|
services.AddHangfire(configuration);
|
|
|
|
services.AddOpenApi(options =>
|
|
{
|
|
options.AddDocumentTransformer((document, context, cancellationToken) =>
|
|
{
|
|
document.Info = new()
|
|
{
|
|
Title = "API",
|
|
Version = "V1",
|
|
Description = ""
|
|
};
|
|
|
|
|
|
return Task.CompletedTask;
|
|
});
|
|
|
|
});
|
|
|
|
return services;
|
|
}
|
|
|
|
private static IConfiguration BuildConfiguration(this WebApplicationBuilder builder)
|
|
{
|
|
var basePath = Path.Combine(builder.Environment.ContentRootPath, "files", "config");
|
|
|
|
if (!Directory.Exists(basePath))
|
|
{
|
|
Directory.CreateDirectory(basePath);
|
|
}
|
|
|
|
IConfiguration configuration = new ConfigurationBuilder()
|
|
.SetBasePath(basePath)
|
|
.AddJsonFile("appsettings.json", true, true)
|
|
.AddJsonFile("appsettings.blog.json", true, true)
|
|
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
|
|
.Build();
|
|
|
|
return configuration;
|
|
}
|
|
|
|
|
|
public static IServiceCollection AddConfiguration(this IServiceCollection services, IConfiguration configuration)
|
|
{
|
|
|
|
services.Configure<BlogSettings>(configuration);
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddBackgroundService(this IServiceCollection services)
|
|
{
|
|
var allAssemblies = Assembly.GetEntryAssembly()?.GetReferencedAssemblies().OrderBy(x => x.Name).Select(Assembly.Load).ToList() ?? new List<Assembly>();
|
|
foreach (var serviceAsm in allAssemblies)
|
|
{
|
|
var serviceList = serviceAsm.GetTypes().Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface);
|
|
foreach (Type serviceType in serviceList.Where(t => t.IsSubclassOf(typeof(BackgroundService))))
|
|
{
|
|
services.AddTransient(typeof(IHostedService), serviceType);
|
|
}
|
|
}
|
|
return services;
|
|
}
|
|
|
|
|
|
|
|
public static IServiceCollection AddRazorPages(this IServiceCollection services)
|
|
{
|
|
services.AddRazorPages(options =>
|
|
{
|
|
options.Conventions.AuthorizeAreaFolder("Admin", "/");
|
|
options.Conventions.AllowAnonymousToAreaPage("Admin", "/Login");
|
|
});
|
|
|
|
services.Configure<RouteOptions>(option =>
|
|
{
|
|
option.LowercaseUrls = true;
|
|
option.LowercaseQueryStrings = true;
|
|
});
|
|
|
|
services.AddHttpClient();
|
|
|
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
|
|
|
return services;
|
|
}
|
|
|
|
|
|
public static IServiceCollection AutoRegister(this IServiceCollection services)
|
|
{
|
|
var allAssemblies = Assembly.GetEntryAssembly()?.GetReferencedAssemblies().OrderBy(x => x.Name).Select(Assembly.Load).ToList() ?? new List<Assembly>();
|
|
foreach (var serviceAsm in allAssemblies)
|
|
{
|
|
var serviceList = serviceAsm.GetTypes().Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface);
|
|
|
|
foreach (Type serviceType in serviceList.Where(t => typeof(IScoped).IsAssignableFrom(t)))
|
|
{
|
|
var interfaceTypes = serviceType.GetInterfaces();
|
|
|
|
foreach (var interfaceType in interfaceTypes)
|
|
{
|
|
services.AddScoped(interfaceType, serviceType);
|
|
}
|
|
}
|
|
|
|
foreach (Type serviceType in serviceList.Where(t => typeof(ISingleton).IsAssignableFrom(t)))
|
|
{
|
|
var interfaceTypes = serviceType.GetInterfaces();
|
|
|
|
foreach (var interfaceType in interfaceTypes)
|
|
{
|
|
services.AddSingleton(interfaceType, serviceType);
|
|
}
|
|
}
|
|
|
|
foreach (Type serviceType in serviceList.Where(t => typeof(ITransient).IsAssignableFrom(t)))
|
|
{
|
|
var interfaceTypes = serviceType.GetInterfaces();
|
|
|
|
foreach (var interfaceType in interfaceTypes)
|
|
{
|
|
services.AddTransient(interfaceType, serviceType);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return services;
|
|
}
|
|
|
|
|
|
public static IServiceCollection AddMediatR(this IServiceCollection services)
|
|
{
|
|
|
|
var application = typeof(IAssembly);
|
|
|
|
services.AddMediatR(configure =>
|
|
{
|
|
configure.RegisterServicesFromAssembly(application.Assembly);
|
|
});
|
|
|
|
|
|
|
|
return services;
|
|
}
|
|
|
|
|
|
public static IServiceCollection AddAutoMapper(this IServiceCollection services)
|
|
{
|
|
var typeAdapterConfig = TypeAdapterConfig.GlobalSettings;
|
|
typeAdapterConfig.Scan(Assemblies);
|
|
|
|
services.AddSingleton(typeAdapterConfig);
|
|
services.AddScoped<IMapper, ServiceMapper>();
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection ConfigureValidator(this IServiceCollection services)
|
|
{
|
|
services.AddValidatorsFromAssemblies(Assemblies);
|
|
|
|
return services;
|
|
}
|
|
|
|
|
|
public static IServiceCollection AddViewEngine(this IServiceCollection services, IWebHostEnvironment env, Action<FluidViewEngineOptions> setupAction = null)
|
|
{
|
|
services.AddFluid();
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddEndpoints(this IServiceCollection services)
|
|
{
|
|
var assembly = typeof(IAssembly).Assembly;
|
|
|
|
ServiceDescriptor[] serviceDescriptors = assembly
|
|
.DefinedTypes
|
|
.Where(type => type is { IsAbstract: false, IsInterface: false } &&
|
|
type.IsAssignableTo(typeof(IEndpoint)))
|
|
.Select(type => ServiceDescriptor.Transient(typeof(IEndpoint), type))
|
|
.ToArray();
|
|
|
|
services.TryAddEnumerable(serviceDescriptors);
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IApplicationBuilder UseGlobalExceptionHandler(this WebApplication app)
|
|
{
|
|
app.UseMiddleware<GlobalExceptionHandlerMiddleware>();
|
|
|
|
return app;
|
|
}
|
|
|
|
public static IApplicationBuilder MapEndpoints(this WebApplication app)
|
|
{
|
|
var apiPolicy = new AuthorizationPolicyBuilder()
|
|
.AddAuthenticationSchemes(AuthenticationScheme.ApiScheme)
|
|
.RequireAuthenticatedUser()
|
|
.Build();
|
|
|
|
|
|
var endpoints = app.Services.GetRequiredService<IEnumerable<IEndpoint>>().OrderByDescending(x => x.Priority);
|
|
foreach (var route in endpoints)
|
|
{
|
|
var routeGroup = app.MapGroup($"/{route.Prefix}").WithTags(route.Tags).RequireAuthorization();
|
|
route.Map(routeGroup);
|
|
|
|
}
|
|
|
|
app.MapHangfireDashboard();
|
|
|
|
return app;
|
|
}
|
|
|
|
public static IApplicationBuilder UseBlogFiles(this WebApplication app, WebApplicationBuilder builder)
|
|
{
|
|
var uploadsPath = Path.Combine(builder.Environment.ContentRootPath, "files", "uploads");
|
|
if (!Directory.Exists(uploadsPath))
|
|
{
|
|
Directory.CreateDirectory(uploadsPath);
|
|
}
|
|
|
|
app.UseStaticFiles(new StaticFileOptions
|
|
{
|
|
FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRootPath, "files", "uploads")),
|
|
RequestPath = "/uploads",
|
|
});
|
|
|
|
var themesPath = Path.Combine(builder.Environment.ContentRootPath, "files", "themes");
|
|
if (!Directory.Exists(themesPath))
|
|
{
|
|
Directory.CreateDirectory(themesPath);
|
|
}
|
|
app.UseStaticFiles(new StaticFileOptions
|
|
{
|
|
FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRootPath, "files", "themes")),
|
|
RequestPath = "/themes",
|
|
});
|
|
|
|
return app;
|
|
}
|
|
|
|
|
|
public static IServiceCollection AddHangfire(this IServiceCollection services, IConfiguration configuration)
|
|
{
|
|
Enum.TryParse(configuration["DatabaseType"], out DatabaseTypeEnum databaseType);
|
|
var connectionString = configuration["ConnectionString"] ?? "";
|
|
var dbName = configuration["DatabaseName"] ?? "";
|
|
|
|
var builder = ConnectionStringBuilderFactory.CreateStringBuilder(databaseType, connectionString);
|
|
builder.SetDatabaseName(dbName);
|
|
|
|
connectionString = builder.GetConnectionString();
|
|
|
|
// Add Hangfire services
|
|
services.AddHangfire(config =>
|
|
{
|
|
switch (databaseType)
|
|
{
|
|
case DatabaseTypeEnum.SqlServer:
|
|
config.UseSqlServerStorage(connectionString);
|
|
break;
|
|
case DatabaseTypeEnum.MySql:
|
|
config.UseStorage(
|
|
new MySqlStorage(
|
|
connectionString,
|
|
new MySqlStorageOptions
|
|
{
|
|
TransactionIsolationLevel = IsolationLevel.ReadCommitted,
|
|
QueuePollInterval = TimeSpan.FromSeconds(15),
|
|
JobExpirationCheckInterval = TimeSpan.FromHours(1),
|
|
CountersAggregateInterval = TimeSpan.FromMinutes(5),
|
|
PrepareSchemaIfNecessary = true,
|
|
DashboardJobListLimit = 50000,
|
|
TransactionTimeout = TimeSpan.FromMinutes(1),
|
|
TablesPrefix = "Hangfire"
|
|
}));
|
|
break;
|
|
case DatabaseTypeEnum.PostgreSQL:
|
|
config.UsePostgreSqlStorage(c =>c.UseNpgsqlConnection(connectionString));
|
|
break;
|
|
default:
|
|
throw new InvalidOperationException($"Unsupported database type: {databaseType}");
|
|
}
|
|
|
|
config.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings();
|
|
});
|
|
|
|
|
|
// Add the processing server as IHostedService
|
|
services.AddHangfireServer();
|
|
|
|
|
|
// var minute = 60;
|
|
//int.TryParse(configuration["DatabaseName"], out minute);
|
|
// RecurringJob.AddOrUpdate<RssGenerationJob>("dynamic-job", x => x.Execute(), Cron.Minutely);
|
|
|
|
|
|
return services;
|
|
}
|
|
}
|
|
}
|