z8018
3 天以前 d8dc91f9c1fece5711e38edd1b1274cb9e579015
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
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
    }
}