using NCC.ConfigurableOptions; using NCC.Dependency; using NCC.Reflection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyModel; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using StackExchange.Profiling; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Security.Claims; using System.Threading; namespace NCC { /// /// 全局应用类 /// [SuppressSniffer] public static class App { /// /// 私有设置,避免重复解析 /// internal static AppSettingsOptions _settings; /// /// 应用全局配置 /// public static AppSettingsOptions Settings => _settings ??= GetConfig("AppSettings", true); /// /// 全局配置选项 /// public static IConfiguration Configuration => InternalApp.Configuration; /// /// 获取Web主机环境,如,是否是开发环境,生产环境等 /// public static IWebHostEnvironment WebHostEnvironment => InternalApp.WebHostEnvironment; /// /// 获取泛型主机环境,如,是否是开发环境,生产环境等 /// public static IHostEnvironment HostEnvironment => InternalApp.HostEnvironment; /// /// 存储根服务,可能为空 /// public static IServiceProvider RootServices => InternalApp.RootServices; /// /// 应用有效程序集 /// public static readonly IEnumerable Assemblies; /// /// 有效程序集类型 /// public static readonly IEnumerable EffectiveTypes; /// /// 获取请求上下文 /// public static HttpContext HttpContext => RootServices?.GetService()?.HttpContext; /// /// 获取请求上下文用户 /// /// 只有授权访问的页面或接口才存在值,否则为 null public static ClaimsPrincipal User => HttpContext?.User; /// /// 未托管的对象集合 /// public static readonly ConcurrentBag UnmanagedObjects; /// /// 解析服务提供器 /// /// /// public static IServiceProvider GetServiceProvider(Type serviceType) { // 处理控制台应用程序 if (HostEnvironment == default) return RootServices; // 第一选择,判断是否是单例注册且单例服务不为空,如果是直接返回根服务提供器 if (RootServices != null && InternalApp.InternalServices.Where(u => u.ServiceType == (serviceType.IsGenericType ? serviceType.GetGenericTypeDefinition() : serviceType)) .Any(u => u.Lifetime == ServiceLifetime.Singleton)) return RootServices; // 第二选择是获取 HttpContext 对象的 RequestServices var httpContext = HttpContext; if (httpContext?.RequestServices != null) return httpContext.RequestServices; // 第三选择,创建新的作用域并返回服务提供器 else if (RootServices != null) { var scoped = RootServices.CreateScope(); UnmanagedObjects.Add(scoped); return scoped.ServiceProvider; } // 第四选择,构建新的服务对象(性能最差) else { var serviceProvider = InternalApp.InternalServices.BuildServiceProvider(); UnmanagedObjects.Add(serviceProvider); return serviceProvider; } } /// /// 获取请求生存周期的服务 /// /// /// /// public static TService GetService(IServiceProvider serviceProvider = default) where TService : class { return GetService(typeof(TService), serviceProvider) as TService; } /// /// 获取请求生存周期的服务 /// /// /// /// public static object GetService(Type type, IServiceProvider serviceProvider = default) { return (serviceProvider ?? GetServiceProvider(type)).GetService(type); } /// /// 获取请求生存周期的服务 /// /// /// /// public static TService GetRequiredService(IServiceProvider serviceProvider = default) where TService : class { return GetRequiredService(typeof(TService), serviceProvider) as TService; } /// /// 获取请求生存周期的服务 /// /// /// /// public static object GetRequiredService(Type type, IServiceProvider serviceProvider = default) { return (serviceProvider ?? GetServiceProvider(type)).GetRequiredService(type); } /// /// 获取配置 /// /// 强类型选项类 /// 配置中对应的Key /// /// TOptions public static TOptions GetConfig(string path, bool loadPostConfigure = false) { var options = Configuration.GetSection(path).Get(); // 加载默认选项配置 if (loadPostConfigure && typeof(IConfigurableOptions).IsAssignableFrom(typeof(TOptions))) { var postConfigure = typeof(TOptions).GetMethod("PostConfigure"); if (postConfigure != null) { options ??= Activator.CreateInstance(); postConfigure.Invoke(options, new object[] { options, Configuration }); } } return options; } /// /// 获取选项 /// /// 强类型选项类 /// /// TOptions public static TOptions GetOptions(IServiceProvider serviceProvider = default) where TOptions : class, new() { return GetService>(serviceProvider ?? RootServices)?.Value; } /// /// 获取选项 /// /// 强类型选项类 /// /// TOptions public static TOptions GetOptionsMonitor(IServiceProvider serviceProvider = default) where TOptions : class, new() { return GetService>(serviceProvider ?? RootServices)?.CurrentValue; } /// /// 获取选项 /// /// 强类型选项类 /// /// TOptions public static TOptions GetOptionsSnapshot(IServiceProvider serviceProvider = default) where TOptions : class, new() { // 这里不能从根服务解析,因为是 Scoped 作用域 return GetService>(serviceProvider)?.Value; } /// /// 打印验证信息到 MiniProfiler /// /// 分类 /// 状态 /// 消息 /// 是否为警告消息 public static void PrintToMiniProfiler(string category, string state, string message = null, bool isError = false) { if (!CanBeMiniProfiler()) return; // 打印消息 var titleCaseCategory = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(category); var customTiming = MiniProfiler.Current?.CustomTiming(category, string.IsNullOrWhiteSpace(message) ? $"{titleCaseCategory} {state}" : message, state); if (customTiming == null) return; // 判断是否是警告消息 if (isError) customTiming.Errored = true; } /// /// 构造函数 /// static App() { // 未托管的对象 UnmanagedObjects = new ConcurrentBag(); // 加载程序集 var assObject = GetAssemblies(); Assemblies = assObject.Assemblies; ExternalAssemblies = assObject.ExternalAssemblies; // 获取有效的类型集合 EffectiveTypes = Assemblies.SelectMany(u => u.GetTypes() .Where(u => u.IsPublic && !u.IsDefined(typeof(SuppressSnifferAttribute), false))); AppStartups = new ConcurrentBag(); } /// /// 应用所有启动配置对象 /// internal static ConcurrentBag AppStartups; /// /// 外部程序集 /// internal static IEnumerable ExternalAssemblies; /// /// 获取应用有效程序集 /// /// IEnumerable private static (IEnumerable Assemblies, IEnumerable ExternalAssemblies) GetAssemblies() { // 需排除的程序集后缀 var excludeAssemblyNames = new string[] { "Database.Migrations" }; // 读取应用配置 var supportPackageNamePrefixs = Settings.SupportPackageNamePrefixs ?? Array.Empty(); var dependencyContext = DependencyContext.Default; // 读取项目程序集或 NCC 官方发布的包,或手动添加引用的dll,或配置特定的包前缀 var scanAssemblies = dependencyContext.RuntimeLibraries .Where(u => (u.Type == "project" && !excludeAssemblyNames.Any(j => u.Name.EndsWith(j))) || (u.Type == "package" && (u.Name.StartsWith(nameof(NCC)) || supportPackageNamePrefixs.Any(p => u.Name.StartsWith(p)))) || (Settings.EnabledReferenceAssemblyScan == true && u.Type == "reference")) // 判断是否启用引用程序集扫描 .Select(u => Reflect.GetAssembly(u.Name)); IEnumerable externalAssemblies = Array.Empty(); // 加载 `appsetting.json` 配置的外部程序集 if (Settings.ExternalAssemblies != null && Settings.ExternalAssemblies.Any()) { foreach (var externalAssembly in Settings.ExternalAssemblies) { // 加载外部程序集 var assemblyFileFullPath = Path.Combine(AppContext.BaseDirectory , externalAssembly.EndsWith(".dll") ? externalAssembly : $"{externalAssembly}.dll"); // 根据路径加载程序集 var loadedAssembly = Reflect.LoadAssembly(assemblyFileFullPath); if (loadedAssembly == default) continue; var assembly = new[] { loadedAssembly }; // 合并程序集 scanAssemblies = scanAssemblies.Concat(assembly); externalAssemblies = externalAssemblies.Concat(assembly); } } return (scanAssemblies, externalAssemblies); } /// /// 判断是否启用 MiniProfiler /// /// internal static bool CanBeMiniProfiler() { // 减少不必要的监听 if (Settings.InjectMiniProfiler != true || HttpContext == null || !(HttpContext.Request.Headers.TryGetValue("request-from", out var value) && value == "swagger")) return false; return true; } /// /// 释放所有未托管的对象 /// public static void DisposeUnmanagedObjects() { UnmanagedObjects.Clear(); } } }