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();
}
}
}