更新框架,增加云库搜索模块
This commit is contained in:
1 parent
8526e5e0d2
commit
f2caec6083
192 files changed
+3626
-804
No files matched your search
@@ -0,0 +1,163 @@
|
||||
using MAX.Core.DependencyInjection;
|
||||
using MAX.Core.Interfaces;
|
||||
using MAX.Framework.Commons;
|
||||
using MAX.Framework.Dtos;
|
||||
using MAX.Framework.Interfaces;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MAX.Framework.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// IOC 注册入口(由宿主 Program.cs 调用)
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
private static readonly Type[] DependencyMarkers =
|
||||
[
|
||||
typeof(ISingletonDependency),
|
||||
typeof(IScopedDependency),
|
||||
typeof(ITransientDependency),
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// 注册应用服务:
|
||||
/// <list type="number">
|
||||
/// <item>自动注册所有实现 <see cref="ISingletonDependency"/> / <see cref="IScopedDependency"/> / <see cref="ITransientDependency"/> 的类型;</item>
|
||||
/// <item>发现所有 <see cref="IStartup"/>,按 <see cref="IStartup.Priority"/> 降序执行 Initialize + Register。</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public static IServiceCollection AddStoreHub(this IServiceCollection services)
|
||||
{
|
||||
IEnumerable<Assembly> assemblies = GetApplicationAssemblies();
|
||||
RegisterDependencyMarkers(services, assemblies);
|
||||
RunStartups(services, assemblies);
|
||||
RunModules(services, assemblies);
|
||||
|
||||
|
||||
services.AddControllers(options =>
|
||||
{
|
||||
options.Filters.Add<GlobalExceptionFilter>();
|
||||
options.Filters.Add<UnifyResultFilter>();
|
||||
}).ConfigureApiBehaviorOptions(options =>
|
||||
{
|
||||
options.InvalidModelStateResponseFactory = context =>
|
||||
{
|
||||
// 取出所有校验错误信息,拼成一个字符串(或者只取第一个)
|
||||
var errors = context.ModelState
|
||||
.Where(e => e.Value?.Errors.Count > 0)
|
||||
.SelectMany(e => e.Value!.Errors.Select(err => err.ErrorMessage))
|
||||
.ToList();
|
||||
|
||||
var msg = string.Join("; ", errors);
|
||||
|
||||
var result = ApiResult.Fail(msg, ResultCode.ValidationError);
|
||||
|
||||
return new ObjectResult(result)
|
||||
{
|
||||
StatusCode = 200 // 和其他接口保持一致,用Code表达失败,而不是HTTP 400
|
||||
};
|
||||
};
|
||||
|
||||
});
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动注册标记接口(ISingletonDependency / IScopedDependency / ITransientDependency)的实现类型
|
||||
/// </summary>
|
||||
private static void RegisterDependencyMarkers(IServiceCollection services, IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
foreach (Type type in GetConcreteTypes(assemblies))
|
||||
{
|
||||
Debug.WriteLine(type.Namespace);
|
||||
Type? marker = DependencyMarkers.FirstOrDefault(m => m.IsAssignableFrom(type));
|
||||
if (marker is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ServiceLifetime lifetime = marker == typeof(ISingletonDependency) ? ServiceLifetime.Singleton
|
||||
: marker == typeof(IScopedDependency) ? ServiceLifetime.Scoped
|
||||
: ServiceLifetime.Transient;
|
||||
|
||||
// 注册为自身
|
||||
services.Add(new ServiceDescriptor(type, type, lifetime));
|
||||
|
||||
// 注册为实现的接口(排除标记接口与系统接口)
|
||||
foreach (Type iface in type.GetInterfaces())
|
||||
{
|
||||
if (DependencyMarkers.Contains(iface) || IsSystemInterface(iface))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
services.Add(new ServiceDescriptor(iface, type, lifetime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发现所有 <see cref="IStartup"/> 实现,按 <see cref="IStartup.Priority"/> 降序执行
|
||||
/// </summary>
|
||||
private static void RunStartups(IServiceCollection services, IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
IServiceRegistrar registrar = new ServiceRegistrarProxy(services);
|
||||
|
||||
foreach (IStartup startup in GetConcreteTypes(assemblies)
|
||||
.Where(t => typeof(IStartup).IsAssignableFrom(t))
|
||||
.Select(t => (IStartup)Activator.CreateInstance(t, true)!)
|
||||
.OrderByDescending(s => s.Priority))
|
||||
{
|
||||
startup.Initialize();
|
||||
startup.Register(registrar);
|
||||
}
|
||||
}
|
||||
private static void RunModules(IServiceCollection services, IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
IServiceRegistrar registrar = new ServiceRegistrarProxy(services);
|
||||
|
||||
foreach (IModule startup in GetConcreteTypes(assemblies)
|
||||
.Where(t => typeof(IModule).IsAssignableFrom(t))
|
||||
.Select(t => (IModule)Activator.CreateInstance(t, true)!))
|
||||
{
|
||||
startup.AddModule(services);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetConcreteTypes(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return assemblies
|
||||
.SelectMany(SafeGetTypes)
|
||||
.Where(t => t.IsClass && !t.IsAbstract && !t.IsGenericTypeDefinition);
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> SafeGetTypes(Assembly assembly)
|
||||
{
|
||||
try
|
||||
{
|
||||
return assembly.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
return ex.Types.OfType<Type>();
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Assembly> GetApplicationAssemblies()
|
||||
{
|
||||
// 使用 AppTypeFinder:扫描应用输出目录 + 已加载程序集,
|
||||
return StoreHubAppTypeFinder.Current.GetAssemblies();
|
||||
}
|
||||
|
||||
private static bool IsSystemInterface(Type type)
|
||||
{
|
||||
return type.Namespace is null
|
||||
|| type.Namespace.StartsWith("System", StringComparison.Ordinal)
|
||||
|| type.Namespace.StartsWith("Microsoft", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user