using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Http;
|
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Options;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Reflection;
|
using System.Text;
|
using System.Threading.Tasks;
|
using WIDESEA_Core.Core;
|
using WIDESEA_Core.Helper;
|
using WIDESEA_Core.HttpContextUser;
|
|
namespace WIDESEA_Core
|
{
|
/// <summary>
|
/// 应用程序全局静态类,提供应用运行状态、服务获取、配置管理等核心功能
|
/// </summary>
|
/// <remarks>
|
/// 包含功能:
|
/// 1. 应用运行状态管理(IsRun/IsBuild)
|
/// 2. 程序集和类型加载(Assemblies/EffectiveTypes)
|
/// 3. 服务容器访问(RootServices/GetService)
|
/// 4. 环境配置访问(WebHostEnvironment/Configuration)
|
/// 5. 选项模式支持(GetOptions/GetConfig)
|
/// 6. HTTP上下文访问(HttpContext/User)
|
/// </remarks>
|
public class App
|
{
|
static App()
|
{
|
EffectiveTypes = Assemblies.SelectMany(GetTypes);
|
}
|
|
/// <summary>
|
/// 表示应用程序是否正在运行的标志
|
/// </summary>
|
private static bool _isRun;
|
|
/// <summary>
|
/// 获取或设置一个值,指示当前是否为构建状态
|
/// </summary>
|
public static bool IsBuild { get; set; }
|
|
/// <summary>
|
/// 获取或设置应用程序是否正在运行的标志
|
/// </summary>
|
/// <remarks>
|
/// 设置此属性时也会同时更新IsBuild属性
|
/// </remarks>
|
public static bool IsRun
|
{
|
get => _isRun;
|
set => _isRun = IsBuild = value;
|
}
|
|
/// <summary>
|
/// 有效期
|
/// </summary>
|
public static DateTime? ExpDateTime = null;
|
|
/// <summary>
|
/// 获取当前应用程序域中所有程序集的静态集合
|
/// </summary>
|
/// <remarks>
|
/// 该集合在应用程序启动时初始化,包含通过RuntimeExtension.GetAllAssemblies()方法加载的所有程序集
|
/// </remarks>
|
public static readonly IEnumerable<Assembly> Assemblies = RuntimeExtension.GetAllAssemblies();
|
|
/// <summary>
|
/// 有效的类型集合,包含所有需要处理的类型
|
/// </summary>
|
public static readonly IEnumerable<Type> EffectiveTypes;
|
|
/// <summary>
|
/// 获取根服务提供程序。当应用程序正在运行或构建时返回服务提供程序,否则返回null。
|
/// </summary>
|
public static IServiceProvider? RootServices => IsRun || IsBuild ? InternalApp.RootServices : null;
|
|
/// <summary>
|
/// 获取当前Web主机环境信息
|
/// </summary>
|
public static IWebHostEnvironment WebHostEnvironment => InternalApp.WebHostEnvironment;
|
|
/// <summary>
|
/// 获取当前应用程序的主机环境信息
|
/// </summary>
|
public static IHostEnvironment HostEnvironment => InternalApp.HostEnvironment;
|
|
/// <summary>
|
/// 获取应用程序的配置信息
|
/// </summary>
|
/// <returns>全局配置接口</returns>
|
public static IConfiguration Configuration => InternalApp.Configuration;
|
|
/// <summary>
|
/// 获取请求上下文
|
/// </summary>
|
public static HttpContext? HttpContext => RootServices?.GetService<IHttpContextAccessor>()?.HttpContext;
|
|
/// <summary>
|
/// 获取当前用户服务实例
|
/// </summary>
|
/// <returns>当前用户接口实例,可能为null</returns>
|
public static IUser? User => GetService<IUser>();
|
|
#region Service
|
|
/// <summary>
|
/// 获取指定类型的服务提供者
|
/// </summary>
|
/// <param name="serviceType">要获取的服务类型</param>
|
/// <param name="mustBuild">是否必须构建服务提供者</param>
|
/// <param name="throwException">当服务不可用时是否抛出异常</param>
|
/// <returns>服务提供者实例,若不可用则返回null</returns>
|
/// <remarks>
|
/// 该方法会按以下顺序尝试获取服务提供者:
|
/// 1. 如果是单例服务且已注册,返回根服务提供者
|
/// 2. 尝试从当前HttpContext获取请求作用域的服务提供者
|
/// 3. 创建新的作用域并返回其服务提供者
|
/// 4. 如果mustBuild为true,构建并返回新的服务提供者
|
/// </remarks>
|
public static IServiceProvider? GetServiceProvider(Type serviceType, bool mustBuild = false, bool throwException = true)
|
{
|
if (HostEnvironment == null || RootServices != null &&
|
InternalApp.InternalServices
|
.Where((u =>
|
u.ServiceType ==
|
(serviceType.IsGenericType ? serviceType.GetGenericTypeDefinition() : serviceType)))
|
.Any((u => u.Lifetime == ServiceLifetime.Singleton)))
|
return RootServices;
|
|
//获取请求生存周期的服务
|
if (HttpContext?.RequestServices != null)
|
return HttpContext.RequestServices;
|
|
if (RootServices != null)
|
{
|
IServiceScope scope = RootServices.CreateScope();
|
return scope.ServiceProvider;
|
}
|
|
if (mustBuild)
|
{
|
if (throwException)
|
{
|
throw new ApplicationException("当前不可用,必须要等到 WebApplication Build后");
|
}
|
|
return default;
|
}
|
|
ServiceProvider serviceProvider = InternalApp.InternalServices.BuildServiceProvider();
|
return serviceProvider;
|
}
|
|
/// <summary>
|
/// 获取指定类型的服务实例
|
/// </summary>
|
/// <typeparam name="TService">要获取的服务类型</typeparam>
|
/// <param name="mustBuild">是否必须构建服务实例,默认为true</param>
|
/// <returns>返回请求的服务实例,若未找到则返回null</returns>
|
public static TService? GetService<TService>(bool mustBuild = true) where TService : class
|
{
|
TService? test = GetService(typeof(TService), null, mustBuild) as TService;
|
return test;
|
}
|
|
/// <summary>
|
/// 获取指定类型的服务实例
|
/// </summary>
|
/// <typeparam name="TService">服务类型</typeparam>
|
/// <param name="serviceProvider">可选的服务提供者,如果为null则使用默认提供者</param>
|
/// <param name="mustBuild">是否必须构建服务,默认为true</param>
|
/// <returns>服务实例,如果获取失败则返回null</returns>
|
public static TService? GetService<TService>(IServiceProvider? serviceProvider, bool mustBuild = true)
|
where TService : class => (serviceProvider ?? GetServiceProvider(typeof(TService), mustBuild, false))?.GetService<TService>();
|
|
/// <summary>
|
/// 获取指定类型的服务实例
|
/// </summary>
|
/// <param name="type">要获取的服务类型</param>
|
/// <param name="serviceProvider">可选的服务提供者,若为空则使用默认提供者</param>
|
/// <param name="mustBuild">是否必须构建服务,默认为true</param>
|
/// <returns>服务实例,若未找到则返回null</returns>
|
public static object? GetService(Type type, IServiceProvider? serviceProvider = null, bool mustBuild = true)
|
{
|
object? obj = (serviceProvider ?? GetServiceProvider(type, mustBuild, false))?.GetService(type);
|
return obj;
|
}
|
|
|
#endregion
|
|
#region private
|
|
/// <summary>
|
/// 从指定程序集中获取所有公共类型
|
/// </summary>
|
/// <param name="ass">要扫描的程序集</param>
|
/// <returns>程序集中所有公共类型的枚举</returns>
|
/// <remarks>
|
/// 如果获取类型时发生错误,将静默处理并返回空集合
|
/// </remarks>
|
private static IEnumerable<Type> GetTypes(Assembly ass)
|
{
|
Type[] source = Array.Empty<Type>();
|
try
|
{
|
source = ass.GetTypes();
|
}
|
catch
|
{
|
//$@"Error load `{ass.FullName}` assembly.".WriteErrorLine();
|
}
|
|
return source.Where(u => u.IsPublic);
|
}
|
|
#endregion
|
|
#region Options
|
|
/// <summary>
|
/// 获取指定类型的配置选项实例
|
/// </summary>
|
/// <typeparam name="TOptions">配置选项类型,必须实现IConfigurableOptions接口</typeparam>
|
/// <returns>配置节中对应的选项实例</returns>
|
public static TOptions GetConfig<TOptions>()
|
where TOptions : class, IConfigurableOptions
|
{
|
TOptions instance = Configuration
|
.GetSection(ConfigurableOptions.GetConfigurationPath(typeof(TOptions)))
|
.Get<TOptions>();
|
return instance;
|
}
|
|
/// <summary>
|
/// 从服务提供器中获取指定类型的选项配置
|
/// </summary>
|
/// <typeparam name="TOptions">选项类型,必须为类且有无参构造函数</typeparam>
|
/// <param name="rootServices">根服务提供器</param>
|
/// <param name="serviceProvider">可选的服务提供器,若未指定则使用根服务提供器</param>
|
/// <returns>获取到的选项实例,若未找到则返回null</returns>
|
public static TOptions? GetOptions<TOptions>(IServiceProvider? rootServices, IServiceProvider serviceProvider = null) where TOptions : class, new()
|
{
|
IOptions<TOptions>? service = GetService<IOptions<TOptions>>(serviceProvider ?? rootServices, false);
|
return service?.Value;
|
}
|
|
/// <summary>
|
/// 从服务提供器中获取指定类型TOptions的选项监控实例的当前值
|
/// </summary>
|
/// <typeparam name="TOptions">选项类型,必须为可实例化的类</typeparam>
|
/// <param name="serviceProvider">可选的服务提供器,若未指定则使用根服务</param>
|
/// <returns>TOptions类型的当前选项值,若服务未注册则返回null</returns>
|
public static TOptions? GetOptionsMonitor<TOptions>(IServiceProvider serviceProvider = null)
|
where TOptions : class, new()
|
{
|
IOptionsMonitor<TOptions>? service =
|
GetService<IOptionsMonitor<TOptions>>(serviceProvider ?? RootServices, false);
|
return service?.CurrentValue;
|
}
|
|
/// <summary>
|
/// 获取指定选项类型的快照实例
|
/// </summary>
|
/// <typeparam name="TOptions">选项类型,必须有无参构造函数</typeparam>
|
/// <param name="serviceProvider">可选的服务提供者,默认为null</param>
|
/// <returns>选项实例的快照,如果服务未注册则返回null</returns>
|
public static TOptions? GetOptionsSnapshot<TOptions>(IServiceProvider serviceProvider = null)
|
where TOptions : class, new()
|
{
|
IOptionsSnapshot<TOptions>? service = GetService<IOptionsSnapshot<TOptions>>(serviceProvider, false);
|
return service?.Value;
|
}
|
|
#endregion
|
}
|
}
|