|
|
using DS.Module.Core.Exceptions;
|
|
|
using DS.Module.Core.Helpers;
|
|
|
using DS.Module.Core.Modules;
|
|
|
using JetBrains.Annotations;
|
|
|
using Microsoft.Extensions.Configuration;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
using Microsoft.Extensions.FileProviders;
|
|
|
using System.Reflection;
|
|
|
using System.Text;
|
|
|
|
|
|
namespace DS.Module.Core.Extensions;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 服务集合扩展
|
|
|
/// </summary>
|
|
|
public static class ServiceCollectionExtension
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 得到注入服务
|
|
|
/// </summary>
|
|
|
/// <typeparam name="TType"></typeparam>
|
|
|
/// <param name="services"></param>
|
|
|
/// <returns></returns>
|
|
|
public static TType GetService<TType>(this IServiceCollection services)
|
|
|
{
|
|
|
var provider = services.BuildServiceProvider();
|
|
|
return provider.GetService<TType>();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterAssemblyTypes
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="assemblies">assemblies</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterAssemblyTypes(this IServiceCollection services,
|
|
|
params Assembly[] assemblies)
|
|
|
=> RegisterAssemblyTypes(services, null, ServiceLifetime.Singleton, assemblies);
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterAssemblyTypes
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="serviceLifetime">service lifetime</param>
|
|
|
/// <param name="assemblies">assemblies</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterAssemblyTypes(this IServiceCollection services,
|
|
|
ServiceLifetime serviceLifetime, params Assembly[] assemblies)
|
|
|
=> RegisterAssemblyTypes(services, null, serviceLifetime, assemblies);
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterAssemblyTypes
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="typesFilter">filter types to register</param>
|
|
|
/// <param name="assemblies">assemblies</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterAssemblyTypes(this IServiceCollection services,
|
|
|
Func<Type, bool> typesFilter, params Assembly[] assemblies)
|
|
|
=> RegisterAssemblyTypes(services, typesFilter, ServiceLifetime.Singleton, assemblies);
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterAssemblyTypes
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="typesFilter">filter types to register</param>
|
|
|
/// <param name="serviceLifetime">service lifetime</param>
|
|
|
/// <param name="assemblies">assemblies</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterAssemblyTypes(this IServiceCollection services,
|
|
|
Func<Type, bool> typesFilter, ServiceLifetime serviceLifetime, params Assembly[] assemblies)
|
|
|
{
|
|
|
if (assemblies == null || assemblies.Length == 0)
|
|
|
{
|
|
|
assemblies = ReflectHelper.GetAssemblies();
|
|
|
}
|
|
|
|
|
|
var types = assemblies
|
|
|
.Select(assembly => assembly.GetExportedTypes())
|
|
|
.SelectMany(t => t);
|
|
|
if (typesFilter != null)
|
|
|
{
|
|
|
types = types.Where(typesFilter);
|
|
|
}
|
|
|
|
|
|
foreach (var type in types)
|
|
|
{
|
|
|
services.Add(new ServiceDescriptor(type, type, serviceLifetime));
|
|
|
}
|
|
|
|
|
|
return services;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterTypeAsImplementedInterfaces
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="assemblies">assemblies</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterAssemblyTypesAsImplementedInterfaces(this IServiceCollection services,
|
|
|
params Assembly[] assemblies)
|
|
|
=> RegisterAssemblyTypesAsImplementedInterfaces(services, typesFilter: null, ServiceLifetime.Singleton,
|
|
|
assemblies);
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterTypeAsImplementedInterfaces
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="serviceLifetime">service lifetime</param>
|
|
|
/// <param name="assemblies">assemblies</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterAssemblyTypesAsImplementedInterfaces(this IServiceCollection services,
|
|
|
ServiceLifetime serviceLifetime, params Assembly[] assemblies)
|
|
|
=> RegisterAssemblyTypesAsImplementedInterfaces(services, typesFilter: null, serviceLifetime, assemblies);
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterTypeAsImplementedInterfaces, singleton by default
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="typesFilter">filter types to register</param>
|
|
|
/// <param name="assemblies">assemblies</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterAssemblyTypesAsImplementedInterfaces(this IServiceCollection services,
|
|
|
Func<Type, bool> typesFilter, params Assembly[] assemblies)
|
|
|
=> RegisterAssemblyTypesAsImplementedInterfaces(services, typesFilter: typesFilter, ServiceLifetime.Singleton,
|
|
|
assemblies);
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterTypeAsImplementedInterfaces
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="typesFilter">filter types to register</param>
|
|
|
/// <param name="serviceLifetime">service lifetime</param>
|
|
|
/// <param name="assemblies">assemblies</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterAssemblyTypesAsImplementedInterfaces(this IServiceCollection services,
|
|
|
Func<Type, bool> typesFilter, ServiceLifetime serviceLifetime, params Assembly[] assemblies)
|
|
|
{
|
|
|
if (assemblies == null || assemblies.Length == 0)
|
|
|
{
|
|
|
assemblies = ReflectHelper.GetAssemblies();
|
|
|
}
|
|
|
|
|
|
var types = assemblies
|
|
|
.Select(assembly => assembly.GetExportedTypes())
|
|
|
.SelectMany(t => t);
|
|
|
if (typesFilter != null)
|
|
|
{
|
|
|
types = types.Where(typesFilter);
|
|
|
}
|
|
|
|
|
|
foreach (var type in types)
|
|
|
{
|
|
|
foreach (var implementedInterface in type.GetImplementedInterfaces())
|
|
|
{
|
|
|
services.Add(new ServiceDescriptor(implementedInterface, type, serviceLifetime));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return services;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// RegisterTypeAsImplementedInterfaces
|
|
|
/// </summary>
|
|
|
/// <param name="services">services</param>
|
|
|
/// <param name="type">type</param>
|
|
|
/// <param name="serviceLifetime">service lifetime</param>
|
|
|
/// <returns>services</returns>
|
|
|
public static IServiceCollection RegisterTypeAsImplementedInterfaces(this IServiceCollection services, Type type,
|
|
|
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton)
|
|
|
{
|
|
|
if (type != null)
|
|
|
{
|
|
|
foreach (var interfaceType in type.GetImplementedInterfaces())
|
|
|
{
|
|
|
services.Add(new ServiceDescriptor(interfaceType, type, serviceLifetime));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return services;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 得到注入服务
|
|
|
/// </summary>
|
|
|
/// <typeparam name="TType"></typeparam>
|
|
|
/// <param name="services"></param>
|
|
|
/// <returns></returns>
|
|
|
public static TType GetBuildService<TType>(this IServiceCollection services)
|
|
|
{
|
|
|
var provider = services.BuildServiceProvider();
|
|
|
return provider.GetService<TType>();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 得到或添加Singleton服务
|
|
|
/// </summary>
|
|
|
/// <typeparam name="TServiceType"></typeparam>
|
|
|
/// <typeparam name="TImplementation"></typeparam>
|
|
|
/// <param name="services"></param>
|
|
|
/// <returns></returns>
|
|
|
public static TServiceType GetOrAddSingletonService<TServiceType, TImplementation>(this IServiceCollection services)
|
|
|
where TServiceType : class
|
|
|
where TImplementation : class, TServiceType
|
|
|
{
|
|
|
var type = services.GetSingletonInstanceOrNull<TServiceType>();
|
|
|
if (type is null)
|
|
|
{
|
|
|
var provider = services.BuildServiceProvider();
|
|
|
var serviceType = (TServiceType)provider.GetInstance(new ServiceDescriptor(typeof(TServiceType),
|
|
|
typeof(TImplementation), ServiceLifetime.Singleton));
|
|
|
return serviceType;
|
|
|
}
|
|
|
|
|
|
return type;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 得到或添加Singleton服务
|
|
|
/// </summary>
|
|
|
/// <typeparam name="TServiceType"></typeparam>
|
|
|
public static TServiceType GetOrAddSingletonService<TServiceType>(this IServiceCollection services,
|
|
|
Func<TServiceType> factory) where TServiceType : class
|
|
|
{
|
|
|
var servciceType = services.GetSingletonInstanceOrNull<TServiceType>();
|
|
|
if (servciceType is null)
|
|
|
{
|
|
|
servciceType = factory();
|
|
|
services.AddSingleton<TServiceType>(servciceType);
|
|
|
}
|
|
|
|
|
|
return servciceType;
|
|
|
}
|
|
|
|
|
|
public static IConfiguration GetConfiguration(this IServiceCollection services)
|
|
|
{
|
|
|
return services.GetBuildService<IConfiguration>();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取单例注册服务对象
|
|
|
/// </summary>
|
|
|
public static T GetSingletonInstanceOrNull<T>(this IServiceCollection services)
|
|
|
{
|
|
|
ServiceDescriptor descriptor =
|
|
|
services.FirstOrDefault(d => d.ServiceType == typeof(T) && d.Lifetime == ServiceLifetime.Singleton);
|
|
|
|
|
|
if (descriptor?.ImplementationInstance != null)
|
|
|
{
|
|
|
return (T)descriptor.ImplementationInstance;
|
|
|
}
|
|
|
|
|
|
if (descriptor?.ImplementationFactory != null)
|
|
|
{
|
|
|
return (T)descriptor.ImplementationFactory.Invoke(null);
|
|
|
}
|
|
|
|
|
|
return default;
|
|
|
}
|
|
|
|
|
|
// /// <summary>
|
|
|
// /// 得到操作设置
|
|
|
// /// </summary>
|
|
|
// /// <param name="services"></param>
|
|
|
// /// <returns></returns>
|
|
|
// public static AppOptionSettings GetAppSettings(this IServiceCollection services)
|
|
|
// {
|
|
|
// services.NotNull(nameof(services));
|
|
|
// return services.GetBuildService<IOptions<AppOptionSettings>>()?.Value;
|
|
|
// }
|
|
|
|
|
|
public static T GetSingletonInstance<T>(this IServiceCollection services)
|
|
|
{
|
|
|
var service = services.GetSingletonInstanceOrNull<T>();
|
|
|
if (service == null)
|
|
|
{
|
|
|
throw new InvalidOperationException("找不到singleton服务: " + typeof(T).AssemblyQualifiedName);
|
|
|
}
|
|
|
|
|
|
return service;
|
|
|
}
|
|
|
|
|
|
#region New Module
|
|
|
|
|
|
public static ObjectAccessor<T> TryAddObjectAccessor<T>(this IServiceCollection services)
|
|
|
{
|
|
|
if (services.Any(s => s.ServiceType == typeof(ObjectAccessor<T>)))
|
|
|
{
|
|
|
return services.GetSingletonInstance<ObjectAccessor<T>>();
|
|
|
}
|
|
|
|
|
|
return services.AddObjectAccessor<T>();
|
|
|
}
|
|
|
|
|
|
public static ObjectAccessor<T> AddObjectAccessor<T>(this IServiceCollection services)
|
|
|
{
|
|
|
return services.AddObjectAccessor(new ObjectAccessor<T>());
|
|
|
}
|
|
|
|
|
|
public static ObjectAccessor<T> AddObjectAccessor<T>(this IServiceCollection services, T obj)
|
|
|
{
|
|
|
return services.AddObjectAccessor(new ObjectAccessor<T>(obj));
|
|
|
}
|
|
|
|
|
|
public static ObjectAccessor<T> AddObjectAccessor<T>(this IServiceCollection services, ObjectAccessor<T> accessor)
|
|
|
{
|
|
|
if (services.Any(s => s.ServiceType == typeof(ObjectAccessor<T>)))
|
|
|
{
|
|
|
throw new Exception("在类型“{typeof(T).AssemblyQualifiedName)}”之前注册了对象: ");
|
|
|
}
|
|
|
|
|
|
//Add to the beginning for fast retrieve
|
|
|
services.Insert(0, ServiceDescriptor.Singleton(typeof(ObjectAccessor<T>), accessor));
|
|
|
services.Insert(0, ServiceDescriptor.Singleton(typeof(IObjectAccessor<T>), accessor));
|
|
|
|
|
|
return accessor;
|
|
|
}
|
|
|
|
|
|
public static T GetObjectOrNull<T>(this IServiceCollection services)
|
|
|
where T : class
|
|
|
{
|
|
|
return services.GetSingletonInstanceOrNull<IObjectAccessor<T>>()?.Value;
|
|
|
}
|
|
|
|
|
|
public static T GetObject<T>(this IServiceCollection services)
|
|
|
where T : class
|
|
|
{
|
|
|
return services.GetObjectOrNull<T>() ??
|
|
|
throw new Exception($"找不到的对象 {typeof(T).AssemblyQualifiedName} 服务。请确保您以前使用过AddObjectAccessor!");
|
|
|
}
|
|
|
|
|
|
public static IServiceProvider BuildServiceProviderFromFactory([NotNull] this IServiceCollection services)
|
|
|
{
|
|
|
foreach (var service in services)
|
|
|
{
|
|
|
var factoryInterface = service.ImplementationInstance?.GetType()
|
|
|
.GetTypeInfo()
|
|
|
.GetInterfaces()
|
|
|
.FirstOrDefault(i => i.GetTypeInfo().IsGenericType &&
|
|
|
i.GetGenericTypeDefinition() == typeof(IServiceProviderFactory<>));
|
|
|
|
|
|
if (factoryInterface == null)
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
var containerBuilderType = factoryInterface.GenericTypeArguments[0];
|
|
|
return (IServiceProvider)typeof(Extensions)
|
|
|
.GetTypeInfo()
|
|
|
.GetMethods()
|
|
|
.Single(m => m.Name == nameof(BuildServiceProviderFromFactory) && m.IsGenericMethod)
|
|
|
.MakeGenericMethod(containerBuilderType)
|
|
|
.Invoke(null, new object[] { services, null });
|
|
|
}
|
|
|
|
|
|
return services.BuildServiceProvider();
|
|
|
}
|
|
|
|
|
|
#endregion New Module
|
|
|
|
|
|
/// <summary>
|
|
|
/// 得到文件容器
|
|
|
/// </summary>
|
|
|
/// <param name="services">服务接口</param>
|
|
|
/// <param name="fileName">文件名+后缀名</param>
|
|
|
/// <param name="fileNotExistsMsg">文件不存提示信息</param>
|
|
|
/// <returns>返回文件中的文件</returns>
|
|
|
public static string GetFileText(this IServiceCollection services, string fileName, string fileNotExistsMsg)
|
|
|
{
|
|
|
fileName.NotNullOrEmpty(nameof(fileName));
|
|
|
var fileProvider = services.GetSingletonInstanceOrNull<IFileProvider>();
|
|
|
|
|
|
if (fileProvider == null)
|
|
|
{
|
|
|
throw new DSAppException("IFileProvider接口不存在");
|
|
|
}
|
|
|
|
|
|
var fileInfo = fileProvider.GetFileInfo(fileName);
|
|
|
if (!fileInfo.Exists)
|
|
|
{
|
|
|
if (!fileNotExistsMsg.IsNullOrEmpty())
|
|
|
{
|
|
|
throw new DSAppException(fileNotExistsMsg);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var text = ReadAllText(fileInfo);
|
|
|
if (text.IsNullOrEmpty())
|
|
|
{
|
|
|
throw new DSAppException("文件内容不存在");
|
|
|
}
|
|
|
|
|
|
return text;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 根据配置得到文件内容
|
|
|
/// </summary>
|
|
|
/// <param name="services">服务接口</param>
|
|
|
/// <param name="sectionKey">分区键</param>
|
|
|
/// <param name="fileNotExistsMsg">文件不存提示信息</param>
|
|
|
/// <returns>返回文件中的文件</returns>
|
|
|
public static string GetFileByConfiguration(this IServiceCollection services, string sectionKey,
|
|
|
string fileNotExistsMsg)
|
|
|
{
|
|
|
sectionKey.NotNullOrEmpty(nameof(sectionKey));
|
|
|
var configuration = services.GetService<IConfiguration>();
|
|
|
var value = configuration?.GetSection(sectionKey)?.Value;
|
|
|
return services.GetFileText(value, fileNotExistsMsg);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 读取全部文本
|
|
|
/// </summary>
|
|
|
/// <param name="fileInfo">文件信息接口</param>
|
|
|
/// <returns></returns>
|
|
|
private static string ReadAllText(IFileInfo fileInfo)
|
|
|
{
|
|
|
byte[] buffer;
|
|
|
using var stream = fileInfo.CreateReadStream();
|
|
|
buffer = new byte[stream.Length];
|
|
|
stream.Read(buffer, 0, buffer.Length);
|
|
|
return Encoding.Default.GetString(buffer).Trim();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 添加文件提供器
|
|
|
/// </summary>
|
|
|
/// <param name="services"></param>
|
|
|
/// <returns></returns>
|
|
|
public static IServiceCollection AddFileProvider(this IServiceCollection services)
|
|
|
{
|
|
|
var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath; //获取项目路径
|
|
|
return services.AddSingleton<IFileProvider>(new PhysicalFileProvider(basePath));
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取指定key的值,如没有则设置并获取默认值
|
|
|
/// </summary>
|
|
|
/// <typeparam name="TKey">key的类型</typeparam>
|
|
|
/// <typeparam name="TValue">value的类型</typeparam>
|
|
|
/// <param name="dict">字典</param>
|
|
|
/// <param name="key">key</param>
|
|
|
/// <param name="func">默认值委托</param>
|
|
|
/// <returns></returns>
|
|
|
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, Func<TKey, TValue> func)
|
|
|
{
|
|
|
if (dict.TryGetValue(key, out var obj))
|
|
|
{
|
|
|
return obj;
|
|
|
}
|
|
|
|
|
|
return dict[key] = func(key);
|
|
|
}
|
|
|
} |