Files
WCS/Cowain.TestProject/Services/ServiceCollectionExtensions.cs

425 lines
15 KiB
C#
Raw Permalink Normal View History

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Cowain.Base.Abstractions.Navigation;
using Cowain.Base.Abstractions.Plugin;
using Cowain.Base.Attributes;
using Cowain.Base.DBContext;
using Cowain.Base.Helpers;
using Cowain.Base.IServices;
using Cowain.Base.Models;
using Cowain.Base.Models.Menu;
using Ke.Bee.Localization.Extensions;
using Ke.Bee.Localization.Options;
using Ke.Bee.Localization.Providers;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Threading;
namespace Cowain.TestProject.Services;
public static class ConfigureServices
{
private static List<Assembly>? _assemblies;
private static IOptions<AppSettings>? appSettings;
private static MenuConfigurationContext? menuConfigurationContext;
private static readonly List<IPlugin> _plugins = new();
private static ILogger<App>? _logger;
/// <summary>
/// 注册服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddServices(this IServiceCollection services, IConfiguration configuration, ILogger<App>? logger)
{
_logger = logger;
// 注册全局配置
services.AddSettings();
_assemblies = GetAssemblies();
GlobalData.Instance.AddOrUpdate("Assemblies", _assemblies);
services.AddMemoryCache();
//注入configuration
services.AddSingleton(configuration);
services.AddSingleton<IMessenger, WeakReferenceMessenger>();
// 注册数据库
services.AddDbContextService(configuration);
// 注册视图模型
services.AddViewModels();
// 注册应用菜单
services.AddMenus();
// 注册视图导航器
services.AddSingleton<IViewNavigator, DefaultViewNavigator>();
// 注册TransientAttribute
services.AddTransientAttributes();
// 注册SingletonAttribute
services.AddSingletonAttributes();
// 注册所有数据库服务
services.AddDbServices();
// 注册所有实现IHostedService的类
services.AddHostedServices();
//注册插件服务
services.AddPlugins();
// 注册本地化
services.AddLocalization();
return services;
}
private static List<Assembly> GetAssemblies()
{
string? pluginPath = appSettings?.Value.PluginPath;
// 获取当前已加载的程序集使用FullName作为唯一标识
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.ToDictionary(a => a.GetName().FullName);
// 创建结果列表,初始化为已加载的程序集
var assemblies = new List<Assembly>(loadedAssemblies.Values);
// 加载插件程序集
if (Directory.Exists(pluginPath))
{
var pluginFiles = Directory.GetFiles(pluginPath, "Plugin.*.dll", SearchOption.AllDirectories);
foreach (var file in pluginFiles)
{
try
{
// 获取程序集名称而不加载它
var assemblyName = AssemblyName.GetAssemblyName(file);
// 检查是否已加载同名程序集
if (!loadedAssemblies.ContainsKey(assemblyName.FullName))
{
// 加载程序集并添加到结果列表
var assembly = Assembly.LoadFrom(file);
assemblies.Add(assembly);
loadedAssemblies[assemblyName.FullName] = assembly;
}
}
catch (Exception ex)
{
// 处理加载错误(例如,非程序集文件、版本冲突等)
_logger?.LogError(ex, $"Error loading assembly from {file}: {ex.Message}");
}
}
}
return assemblies;
}
/// <summary>
/// 注册所有viewmodel
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddViewModels(this IServiceCollection services)
{
if (_assemblies == null)
{
return services;
}
var viewModelTypes = _assemblies.SelectMany(a => a.GetTypes())
.Where(t => t.Name.EndsWith("ViewModel") && t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(ObservableObject)));
foreach (var viewModelType in viewModelTypes)
{
try
{
services.AddTransient(viewModelType);
}
catch (Exception ex)
{
_logger?.LogError(ex, "ViewModel注入错误");
}
}
return services;
}
/// <summary>
/// 注册全局配置
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddSettings(this IServiceCollection services)
{
appSettings = Options.Create(new AppSettings
{
OutputPath = Path.Combine(AppContext.BaseDirectory, "Output"),
PluginPath = Path.Combine(AppContext.BaseDirectory, "Plugins")
});
services.AddSingleton(appSettings);
GlobalData.Instance.AddOrUpdate("AppSettings", appSettings.Value);
return services;
}
/// <summary>
/// 注册数据库
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddDbContextService(this IServiceCollection services, IConfiguration configuration)
{
var database_config = configuration.GetSection("Database")["db"];
if (string.IsNullOrEmpty(database_config))
{
_logger?.LogError("未配置数据库");
return services;
}
if (!Enum.TryParse<DataBaseType>(database_config.ToUpper(), out var cmdType))
{
return services;
}
// 配置EF Core日志过滤针对9.0.0版本)
services.AddLogging(loggingBuilder =>
{
// 过滤EF Core的Info级别日志只记录Warning及以上
loggingBuilder.AddFilter(
"Microsoft.EntityFrameworkCore",
LogLevel.Warning // 最低日志级别设为Warning
);
// 专门过滤数据库命令日志SQL执行语句等
loggingBuilder.AddFilter(
"Microsoft.EntityFrameworkCore.Database.Command",
LogLevel.Warning
);
});
services.AddPooledDbContextFactory<SqlDbContext>(options =>
{
switch (cmdType)
{
case DataBaseType.SQLITE:
var SqlLite_connection = configuration.GetConnectionString("SqlLiteConn");
options.UseSqlite(SqlLite_connection);
break;
case DataBaseType.SQLSERVER:
var SqlServer_connection = configuration.GetConnectionString("SqlServerConn");
options.UseSqlServer(SqlServer_connection);
break;
case DataBaseType.MYSQL:
var MySql_connection = configuration.GetConnectionString("MySqlConn");
options.UseMySql(MySql_connection, new MySqlServerVersion(new Version(8, 0, 26)));
break;
case DataBaseType.POSTGRES:
var Postgres_connection = configuration.GetConnectionString("PostGresConn");
options.UseNpgsql(Postgres_connection);
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
break;
}
#if DEBUG
options.EnableSensitiveDataLogging();
#endif
}, 100);
return services;
}
/// <summary>
/// 注册应用菜单
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddMenus(this IServiceCollection services)
{
// 从配置文件读取菜单注入到 DI 容器
var menuItems = JsonSerializer.Deserialize<List<MenuItem>>(
File.ReadAllBytes(Path.Combine(AppContext.BaseDirectory, "Configs", "menus.json"))
);
menuConfigurationContext = new MenuConfigurationContext(menuItems);
services.AddSingleton(menuConfigurationContext);
return services;
}
/// <summary>
/// 注册插件服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddPlugins(this IServiceCollection services)
{
if (_assemblies == null)
{
return services;
}
var pluginTypes = _assemblies.SelectMany(a => a.GetTypes())
.Where(t => typeof(PluginBase).IsAssignableFrom(t) && !t.IsAbstract);
foreach (var type in pluginTypes)
{
if (Activator.CreateInstance(type) is IPlugin plugin)
{
plugin.RegisterServices(services, _assemblies);
//只是注入插件,不需要配置菜单
//plugin.ConfigureMenu(menuConfigurationContext);
_plugins.Add(plugin);
}
}
return services;
}
public static void InitializePlugins(this IServiceProvider serviceProvider)
{
foreach (var plugin in _plugins)
{
plugin.Initialize(serviceProvider);
}
}
public static void ShutDownPlugins(this IServiceProvider serviceProvider)
{
foreach (var plugin in _plugins)
{
plugin.Shutdown();
}
}
/// <summary>
/// 注册所有数据库服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddDbServices(this IServiceCollection services)
{
if (_assemblies == null)
{
return services;
}
var types = _assemblies.SelectMany(a => a.GetTypes())
.Where(t => typeof(IBaseService).IsAssignableFrom(t) && t != typeof(IBaseService));
var implementTypes = types.Where(x => x.IsClass).ToArray();
var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
foreach (var implementType in implementTypes)
{
var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
if (interfaceType != null)
services.AddScoped(interfaceType, implementType);
}
return services;
}
/// <summary>
/// 注册所有TransientAttribute
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddTransientAttributes(this IServiceCollection services)
{
if (_assemblies == null)
{
return services;
}
var transientTypes = _assemblies.SelectMany(a => a.GetTypes())
.Where(t => t.GetCustomAttributes(typeof(TransientAttribute), true).Any() && t.IsClass && !t.IsAbstract);
foreach (var transientType in transientTypes)
{
services.AddTransient(transientType);
}
return services;
}
/// <summary>
/// 注册所有SingletonAttribute
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddSingletonAttributes(this IServiceCollection services)
{
if (_assemblies == null)
{
return services;
}
var transientTypes = _assemblies.SelectMany(a => a.GetTypes())
.Where(t => t.GetCustomAttributes(typeof(SingletonAttribute), true).Any() && t.IsClass && !t.IsAbstract);
foreach (var transientType in transientTypes)
{
services.AddSingleton(transientType);
}
return services;
}
/// <summary>
/// 注册所有实现IHostedService的类
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddHostedServices(this IServiceCollection services)
{
if (_assemblies == null)
{
return services;
}
var hostedServiceTypes = _assemblies.SelectMany(a => a.GetTypes())
.Where(t => typeof(IHostedService).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract);
// 获取 AddHostedService 方法的泛型定义
var addHostedServiceMethod = typeof(ServiceCollectionHostedServiceExtensions)
.GetMethods()
.First(m => m.Name == "AddHostedService" && m.IsGenericMethod && m.GetParameters().Length == 1);
foreach (var hostedServiceType in hostedServiceTypes)
{
try
{
// 构造泛型方法并调用
var genericMethod = addHostedServiceMethod.MakeGenericMethod(hostedServiceType);
genericMethod.Invoke(null, new object[] { services });
}
catch (Exception ex)
{
_logger?.LogError(ex, $"注册后台服务 {hostedServiceType.FullName} 失败");
}
}
return services;
}
/// <summary>
/// 注册本地化
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
private static IServiceCollection AddLocalization(this IServiceCollection services)
{
services.AddLocalization<AvaloniaJsonLocalizationProvider>(() =>
{
var options = new AvaloniaLocalizationOptions(
// 支持的本地化语言文化
[
new("en-US"),
new("zh-CN")
],
// defaultCulture, 用于设置当前文化currentCulture不在 cultures 列表中时的情况以及作为缺失的本地化条目的备用文化fallback culture
new CultureInfo("en-US"),
// currentCulture 在基础设施加载时设置,可以从应用程序设置或其他地方获取
Thread.CurrentThread.CurrentCulture,
// 包含本地化 JSON 文件的资源路径
$"{typeof(App).Namespace}/Assets/i18n");
return options;
});
return services;
}
}