tnblog
首页
视频
资源
登录

.net core 3.1 制作一个简单的依赖注入容器

5724人阅读 2021/2/18 21:39 总访问:3660212 评论:0 收藏:0 手机
分类: .net后台框架

.netcore

.net core 3.1 制作一个简单的依赖注入容器

依赖注入简介

IOC(控制反转)通过将一组通用的流程的控制权从应用转移到框架之中以实现对流程的复用,并按照好莱坞法则实现应用程序的代码与框架之间的交互。关于IOC模式有很多,其中比较有价值的是:依赖注入(DI)

大致结构图

项目架构如下

生命周期

首先我们需要了解在依赖注入中它一般有三种依赖注入的方式,我们这里分别定义为Root,SelfTransient方式,他们的生命周期如下图与列表所示。

生命周期 描述
Root 表示单例模式,唯一的一个
Self 表示局部模式,在局部容器中创建
Transient 表示瞬时模式,每次都重新创建一个新的实例

代码示例

  1. public enum Lifetime
  2. {
  3. Root,
  4. Self,
  5. Transient
  6. }

实现服务注册类(ServiceRegistry)

关于服务注册类,它具有3个核心属性(ServiceType,Lifetime与Factory),它们分别代表如下表所示。

属性 描述
ServiceType 服务类型。
Lifetime 生命周期。
Factory 用来创造的服务实例的工厂。这里使用的是Func<AidasiDI,Type[],object>类型,AidasiDI类表示容器注入主体,Type[]类型表示泛型参数
Next 表示获取历史注册的服务,以单链表的形式连接起来。大家可以参考下图

  1. public class ServiceRegistry
  2. {
  3. public Type ServiceType { get; set; }
  4. public Lifetime Lifetime { get; set; }
  5. public Func<AidasiDI,Type[],object> Factory { get; set; }
  6. internal ServiceRegistry Next { get; set; }
  7. /// <summary>
  8. /// 获取该类型链表上所有的服务注册
  9. /// </summary>
  10. /// <returns></returns>
  11. internal IEnumerable<ServiceRegistry> AsEnumerable()
  12. {
  13. var list = new List<ServiceRegistry>();
  14. for (var OneServiceRegistry = this; OneServiceRegistry != null; OneServiceRegistry= OneServiceRegistry.Next)
  15. {
  16. list.Add(OneServiceRegistry);
  17. }
  18. return list;
  19. }
  20. }

实现依赖注入容器类(AidasiDI)

编写属性与构造

AidasiDI同时实现了IServiceProvider接口与IDisposable接口,通过实现IServiceProviderGetService方法来进行提供服务实例。

在这里面也有四个比较重要的属性_root_ServiceRegisters_InstancesServices_disposables。它们分别如下所示:

属性 描述
_root 表示它的父节点,当它本身为根节点的时候该字段为null
_ServiceRegisters 注册的服务键值对集合,以类型Type为Key,以服务注册类ServiceRegistry为Value
_InstancesServices 注册后当前使用的服务实例的键值对集合。以类型ServiceRegistryAndGenericity为Key,它表示服务注册与泛型参数的组合;返回的object表示注册时需要返回的类型。
_disposables 可以释放实例服务对象的集合
_disposable 表示当前的实例是否正在释放,类型为bool类型。volatile关键字可以达到共享内存的操作节省资源
  1. public class AidasiDI : IServiceProvider, IDisposable
  2. {
  3. public readonly AidasiDI _root;
  4. public readonly ConcurrentDictionary<Type,ServiceRegistry> _ServiceRegisters;
  5. public readonly ConcurrentDictionary<ServiceRegistryAndGenericity, object> _InstancesServices;
  6. public readonly ConcurrentBag<IDisposable> _disposables;
  7. public volatile bool _disposable;
  8. public AidasiDI()
  9. {
  10. _root = this;
  11. _ServiceRegisters = new ConcurrentDictionary<Type, ServiceRegistry>();
  12. _InstancesServices = new ConcurrentDictionary<ServiceRegistryAndGenericity, object>();
  13. _disposables = new ConcurrentBag<IDisposable>();
  14. }
  15. public void Dispose()
  16. {
  17. throw new NotImplementedException();
  18. }
  19. public object GetService(Type serviceType)
  20. {
  21. throw new NotImplementedException();
  22. }
  23. }

释放实例方法

  1. /// <summary>
  2. /// 释放实例
  3. /// </summary>
  4. public void Dispose()
  5. {
  6. // 设置正在释放中
  7. _disposable = true;
  8. // 释放相关服务实例
  9. foreach (var item in _disposables)
  10. {
  11. item.Dispose();
  12. }
  13. // 清除释放集合
  14. _disposables.Clear();
  15. // 清理释放服务的键值对
  16. _InstancesServices.Clear();
  17. }

在这里当释放相关服务实例时,我们可以写一个EnsureNotDisposed方法,去判断当前实例是否是处于释放阶段,以防止有新的服务实例的获取。

实现ServiceRegistryAndGenericity类

这个类主要是服务注册与泛型参数的组合,所对应的字段分别是RegistryGenericArguments。并通过实现IEquatable<ServiceRegistryAndGenericity>接口实现Equals方法。

  1. public class ServiceRegistryAndGenericity:IEquatable<ServiceRegistryAndGenericity>
  2. {
  3. public ServiceRegistry Registry { get; }
  4. public Type[] GenericArguments { get; }
  5. public ServiceRegistryAndGenericity(ServiceRegistry _Registry,Type[] _GenericArguments)
  6. {
  7. Registry = _Registry;
  8. GenericArguments = _GenericArguments;
  9. }
  10. public bool Equals(ServiceRegistryAndGenericity other)
  11. {
  12. // 判断二者是否相等
  13. if (Registry != other.Registry)
  14. {
  15. return false;
  16. }
  17. // 判断泛型参数长度是否相等
  18. if (GenericArguments.Length != other.GenericArguments.Length)
  19. {
  20. return false;
  21. }
  22. // 判断泛型参数类型是否相等
  23. for (int index = 0; index < GenericArguments.Length; index++)
  24. {
  25. if (GenericArguments[index] != other.GenericArguments[index])
  26. {
  27. return false;
  28. }
  29. }
  30. return true;
  31. }
  32. /// <summary>
  33. /// 重新hash
  34. /// </summary>
  35. /// <returns></returns>
  36. public override int GetHashCode()
  37. {
  38. var hash = Registry.GetHashCode();
  39. for (int i = 0; i < GenericArguments.Length; i++)
  40. {
  41. hash ^= GenericArguments[i].GetHashCode();
  42. }
  43. return hash;
  44. }
  45. public override bool Equals(object obj) => obj is ServiceRegistryAndGenericity srag ? Equals(obj):false;
  46. }

在AidasiDI中实现注册服务方法(Register)

主要是将服务添加到_ServiceRegisters键值对中去,如下面的代码所示:

  1. /// <summary>
  2. /// 实现注册方法
  3. /// </summary>
  4. /// <returns></returns>
  5. public AidasiDI Register(ServiceRegistry serviceRegistry)
  6. {
  7. // 判断当前实例是否正在释放
  8. EnsureNotDisposed();
  9. // 在_ServiceRegisters中判断是否注册过,如果该服务有注册我们将修改为新的注册方式,并将历史注册放到新注册的next属性上
  10. if (_ServiceRegisters.TryGetValue(serviceRegistry.ServiceType,out ServiceRegistry oldregistry))
  11. {
  12. _ServiceRegisters[serviceRegistry.ServiceType] = serviceRegistry;
  13. serviceRegistry.Next = oldregistry;
  14. }
  15. else
  16. {
  17. _ServiceRegisters[serviceRegistry.ServiceType] = serviceRegistry;
  18. }
  19. return this;
  20. }

实现获取服务核心方法(GetServiceCore)

大致逻辑是通过传入的ServiceRegister与泛型参数类型实例一个ServiceRegistryAndGenericity的类,然后通过判断生命周期的方式去获取实例。其中Transient会直接通过_ServiceRegisters的集合进行服务注册,不需要添加到已经实例的集合_InstancesServices中去,如果服务对象实现了IDisposable接口将会添加至释放_disposables集合中。

  1. private object GetServiceCore(ServiceRegistry serviceRegistry,Type[] GenericParam)
  2. {
  3. var ServiceKey = new ServiceRegistryAndGenericity(serviceRegistry, GenericParam);
  4. var ServiceLifetime = serviceRegistry.Lifetime;
  5. return ServiceLifetime switch
  6. {
  7. Lifetime.Root => GetOrCreate(_root._InstancesServices,_root._disposables),
  8. Lifetime.Self => GetOrCreate(_InstancesServices, _disposables),
  9. _ => LifetimeTransientGetOrCreate(_disposables),
  10. };
  11. object LifetimeTransientGetOrCreate( ConcurrentBag<IDisposable> disposables)
  12. {
  13. // 获取新的实例
  14. var InstanceService = serviceRegistry.Factory(this, GenericParam);
  15. // 如果可以释放,就添加到释放集合中去
  16. if (InstanceService is IDisposable disposable)
  17. {
  18. disposables.Add(disposable);
  19. }
  20. return InstanceService;
  21. }
  22. object GetOrCreate(ConcurrentDictionary<ServiceRegistryAndGenericity, object> services, ConcurrentBag<IDisposable> disposables)
  23. {
  24. // 去实例集合中判断是否存在该类型的实例
  25. if (services.TryGetValue(ServiceKey,out object InstanceService))
  26. {
  27. // 如果有就直接返回
  28. return InstanceService;
  29. }
  30. // 获取新的实例
  31. InstanceService = serviceRegistry.Factory(this, GenericParam);
  32. // 添加到当前实例集合中去
  33. services[ServiceKey] = InstanceService;
  34. // 如果可以释放,就添加到释放集合中去
  35. if (InstanceService is IDisposable disposable)
  36. {
  37. disposables.Add(disposable);
  38. }
  39. return InstanceService;
  40. }
  41. }

实现获取服务方法(GetService)

首先判断该实例是否已经释放了,如果没有释放我们需要判断它获取的是什么样的实例。最开始我们需要判断它是不是想获取当前的容器对象;接着就是它是不是想获取已经注册的服务历史集合;然后判断是泛型注入还是普通注入。

  1. public object GetService(Type serviceType)
  2. {
  3. EnsureNotDisposed();
  4. // 判断是否获取的是当前容器对象
  5. if (serviceType == typeof(AidasiDI) || serviceType == typeof(IServiceProvider))
  6. {
  7. return this;
  8. }
  9. ServiceRegistry registry;
  10. // 判断是否是获取单个服务类型集合(IEnumerable)
  11. if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
  12. {
  13. // 获取集合的第一个类型,比如List<string> 那么就是 string 类型
  14. var elementType = serviceType.GetGenericArguments()[0];
  15. // 当它集合里面的类型,在我们服务注册集合(_ServiceRegisters)里面找不到的时候
  16. if (!_ServiceRegisters.TryGetValue(elementType,out registry))
  17. {
  18. // 我们将直接返回空的集合实例
  19. return Array.CreateInstance(elementType, 0);
  20. }
  21. // 但如果找到有相关的服务注册,我们将获取该服务所有的历史注册对象
  22. var registeries = registry.AsEnumerable();
  23. var services = registeries.Select(x => GetServiceCore(x, Type.EmptyTypes)).ToArray();
  24. Array array = Array.CreateInstance(elementType, services.Length);
  25. services.CopyTo(array, 0);
  26. return array;
  27. }
  28. // 泛型获取服务实例
  29. if (serviceType.IsGenericType && !_ServiceRegisters.ContainsKey(serviceType))
  30. {
  31. // 获取泛型参数类型
  32. var definition = serviceType.GetGenericTypeDefinition();
  33. return _ServiceRegisters.TryGetValue(serviceType, out registry) ?
  34. GetServiceCore(registry, definition.GetGenericArguments()) : null;
  35. }
  36. // 普通类型获取服务实例
  37. return _ServiceRegisters.TryGetValue(serviceType, out registry) ?
  38. GetServiceCore(registry, new Type[0]) : null;
  39. }

扩展方法

这里我们需要运用一些外部扩展去调用服务的注册方法。在前面我们在获取服务具体实例时是通过factory的委托进行调用的,但这个委托我们并没有进行实现。我们这里就直接写道扩展方法AidasiDIExtensions类里面。

实现实例委托方法Create

首先我们会去判断创建的实例是不是泛型,如果是泛型我们去获取泛型的具体类型;然后通过constructors获取公共构造方法的集合;紧接着我们这里我们获取有InjectionAttribute标签的公共构造优先(代码在该代码下面);如果没有找到该标签我们就获取第一个公共构造;然后获取构造里面需要实例的参数并用GetService进行创建。

  1. public static class AidasiDIExtensions
  2. {
  3. /// <summary>
  4. /// 最重要的创建实例方法
  5. /// </summary>
  6. /// <param name="aidasiDI"></param>
  7. /// <param name="to"></param>
  8. /// <param name="arguments"></param>
  9. /// <returns></returns>
  10. private static object Create(AidasiDI aidasiDI, Type to, Type[] arguments)
  11. {
  12. if (arguments.Length > 0)
  13. {
  14. // 获取构造类型的类型对象
  15. to = to.MakeGenericType();
  16. }
  17. // 获取构造方法集合
  18. var constructors = to.GetConstructors();
  19. if (constructors.Length == 0)
  20. {
  21. throw new InvalidOperationException($"无法创建没有公共构造函数的{to}的实例。");
  22. }
  23. // GetCustomAttributes(false) 不会获取自定义属性
  24. // 有InjectionAttribute标记的公共构造优先
  25. var constructor = constructors.FirstOrDefault(it => it.GetCustomAttributes(false).OfType<InjectionAttribute>().Any());
  26. // 当没有该标记时,我们只需要选择第一个即可
  27. constructor ??= constructors.First();
  28. // 获取公共构造所需要的参数
  29. var parameters = constructor.GetParameters();
  30. // 当没有需要注入的构造参数,我们将直接实例
  31. if (parameters.Length == 0)
  32. {
  33. return Activator.CreateInstance(to);
  34. }
  35. // 创建获取服务相关实例集合
  36. var argumentinstances = new object[parameters.Length];
  37. for (int index = 0; index < argumentinstances.Length; index++)
  38. {
  39. // [ParameterType]: 获取参数类型
  40. argumentinstances[index] = aidasiDI.GetService(parameters[index].ParameterType);
  41. }
  42. return constructor.Invoke(argumentinstances);
  43. }
  44. }
  1. // AttributeUsage 声明一个Attribute的使用范围与使用原则。这里我们的范围指定为构造
  2. // 更多请参考:https://www.runoob.com/csharp/csharp-attribute.html
  3. [AttributeUsage(AttributeTargets.Constructor)]
  4. public class InjectionAttribute:Attribute
  5. {
  6. }

添加扩展方法

添加注册范围的扩展与获取服务的扩展。

  1. public static class AidasiDIExtensions
  2. {
  3. public static AidasiDI Register<TTFrom, TTTo>(this AidasiDI aidasiDI, Lifetime lifetime)
  4. where TTTo : TTFrom
  5. => Register(aidasiDI,typeof(TTFrom),typeof(TTTo),lifetime);
  6. public static AidasiDI Register(this AidasiDI aidasiDI,Type from,Type to,Lifetime lifetime)
  7. {
  8. // 生成实例的工厂方法
  9. Func<AidasiDI, Type[], object> func = (_, arguments) => Create(_, to, arguments);
  10. return aidasiDI.Register(new ServiceRegistry(from,lifetime,func));
  11. }
  12. public static AidasiDI Register(this AidasiDI aidasiDI, Type ServiceType,object instance)
  13. {
  14. Func<AidasiDI, Type[], object> func = (_, arguments) => instance;
  15. return aidasiDI.Register(new ServiceRegistry(ServiceType, Lifetime.Root, func));
  16. }
  17. public static AidasiDI Register<TSeervice>(this AidasiDI aidasiDI, TSeervice instance)
  18. {
  19. Func<AidasiDI, Type[], object> func = (_, arguments) => instance;
  20. return aidasiDI.Register(new ServiceRegistry(typeof(TSeervice), Lifetime.Root, func));
  21. }
  22. public static AidasiDI Register(this AidasiDI aidasiDI,Type serviceType,Func<AidasiDI,object> factory, Lifetime lifetime)
  23. {
  24. Func<AidasiDI, Type[], object> func = (_, arguments) => factory(_);
  25. return aidasiDI.Register(new ServiceRegistry(serviceType, lifetime, func));
  26. }
  27. public static AidasiDI Register<IService>(this AidasiDI aidasiDI, Func<AidasiDI, object> factory, Lifetime lifetime)
  28. {
  29. Func<AidasiDI, Type[], object> func = (_, arguments) => factory(_);
  30. return aidasiDI.Register(new ServiceRegistry(typeof(IService), lifetime, func));
  31. }
  32. public static IService GetService<IService>(this AidasiDI aidasiDI) => (IService)aidasiDI.GetService(typeof(IService));
  33. public static IEnumerable<IService> GetServices<IService>(this AidasiDI aidasiDI) => aidasiDI.GetService<IEnumerable<IService>>();
  34. }

运行测试

首先我们定义一个IDemo接口,然后用Demo类实现IDemoIDisposable。然后做一个小案例。

  1. static void Main(string[] args)
  2. {
  3. using (var service = new AidasiDI()
  4. .Register<IDemo,Demo>(Lifetime.Root)
  5. )
  6. {
  7. service.GetService<IDemo>();
  8. }
  9. Console.WriteLine("Exit");
  10. Console.ReadKey();
  11. }
  12. public interface IDemo{}
  13. public class Demo : IDemo, IDisposable
  14. {
  15. public void Dispose()
  16. {
  17. Console.WriteLine("Demo is Disposable");
  18. }
  19. }

我们发现还缺少局部子节点的区域运用。所以接下来我们需要添加子节点的代码。

实现子区域

从下图中我们发现子区域就有一个root父亲节点的属性,并且会的服务注册也是从父亲节点那儿学的,只是其中的实例集合不一样。所以我们实现起来也非常之简单。

创建子区域构造方法

  1. public AidasiDI(AidasiDI aidasiDI)
  2. {
  3. _root = aidasiDI;
  4. _ServiceRegisters = aidasiDI._ServiceRegisters;
  5. _InstancesServices = new ConcurrentDictionary<ServiceRegistryAndGenericity, object>();
  6. _disposables = new ConcurrentBag<IDisposable>();
  7. }

创建子区域的扩展方法

  1. public static AidasiDI CreateChild(this AidasiDI aidasiDI) => new AidasiDI(aidasiDI);

修改代码测试一下

  1. static void Main(string[] args)
  2. {
  3. using (var service = new AidasiDI()
  4. .Register<IDemo,Demo>(Lifetime.Root)
  5. )
  6. {
  7. using (var child = service.CreateChild())
  8. {
  9. child.GetService<IDemo>();
  10. }
  11. Console.WriteLine("End of subregion");
  12. service.GetService<IDemo>();
  13. }
  14. Console.WriteLine("Exit");
  15. Console.ReadKey();
  16. }

实现批量注册

由于我们考虑到多个类需要注册,所以我们这里可以写一个特性类进行类的批量注册

  1. // AttributeUsage 声明一个Attribute的使用范围与使用原则。这里我们的范围指定为构造
  2. [AttributeUsage(AttributeTargets.Class,AllowMultiple = true)]
  3. public sealed class MapToAttribute:Attribute
  4. {
  5. public Type ServiceType { get; }
  6. public Lifetime lifetime { get; }
  7. public MapToAttribute(Type ServiceType,Lifetime lifetime)
  8. {
  9. this.ServiceType = ServiceType;
  10. this.lifetime = lifetime;
  11. }
  12. }

关于它应用的扩展方法

  1. public static AidasiDI Register(this AidasiDI aidasiDI,Assembly assembly)
  2. {
  3. // GetExportedTypes 构建程序集里public的类的实例时候,可以用这个函数得到这些类。
  4. var typedAttributes = from type in assembly.GetExportedTypes()
  5. let attribute = type.GetCustomAttribute<MapToAttribute>()
  6. where attribute != null
  7. select new { ServiceType = type, Attribute = attribute };
  8. foreach (var typedAttribute in typedAttributes)
  9. {
  10. aidasiDI.Register(typedAttribute.Attribute.ServiceType, typedAttribute.Attribute.lifetime);
  11. }
  12. return aidasiDI;
  13. }

使用方法,在类的上面标注示例:[MapTo(typeof(类型),Lifetime.Root)],在注册的时候我们将直接在扩展方法中使用.Register(Assembly.GetEntryAssembly);

整合第三方依赖注入框架

安装两个包

  1. <ItemGroup>
  2. <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.11" />
  3. <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.11" />
  4. </ItemGroup>

添加相关代码

创建一个AidasiBuilder类。

  1. public class AidasiBuilder
  2. {
  3. private readonly AidasiDI _aidasiDI;
  4. public AidasiBuilder(AidasiDI aidasi)
  5. {
  6. _aidasiDI = aidasi;
  7. // 以瞬时的模式创建每一个范围服务(局部容器)
  8. _aidasiDI.Register<IServiceScopeFactory>(c => new ServiceScopeFactory(c.CreateChild()), Lifetime.Transient);
  9. }
  10. /// <summary>
  11. /// 实现服务范围(局部容器)
  12. /// </summary>
  13. private class ServiceScope : IServiceScope
  14. {
  15. public ServiceScope(IServiceProvider serviceProvider)
  16. {
  17. ServiceProvider = serviceProvider;
  18. }
  19. public IServiceProvider ServiceProvider { get; }
  20. public void Dispose()
  21. {
  22. (ServiceProvider as IDisposable)?.Dispose();
  23. }
  24. }
  25. /// <summary>
  26. /// 实现创建范围服务的工厂
  27. /// </summary>
  28. private class ServiceScopeFactory : IServiceScopeFactory
  29. {
  30. private readonly AidasiDI _aidasi;
  31. public ServiceScopeFactory(AidasiDI aidasi) => _aidasi = aidasi;
  32. public IServiceScope CreateScope() => new ServiceScope(_aidasi);
  33. }
  34. public IServiceProvider BuildServiceProvider() => _aidasiDI;
  35. /// <summary>
  36. /// 标签注册
  37. /// </summary>
  38. /// <param name="assembly"></param>
  39. /// <returns></returns>
  40. public AidasiBuilder Register(Assembly assembly)
  41. {
  42. _aidasiDI.Register(assembly);
  43. return this;
  44. }
  45. }

通过AidasiServiceProviderFactory实现IServiceProviderFactory<AidasiBuilder>类,在自定义的依赖注入框架中注册所需要的服务并提供具体的IServiceProvider相关方法。

  1. /// <summary>
  2. /// 实现 IServiceProviderFactory<AidasiBuilder> 方法
  3. /// </summary>
  4. public class AidasiServiceProviderFactory : IServiceProviderFactory<AidasiBuilder>
  5. {
  6. public AidasiBuilder CreateBuilder(IServiceCollection services)
  7. {
  8. var aidasi = new AidasiDI();
  9. foreach (var service in services)
  10. {
  11. // 通过工厂的方式进行注入
  12. if (service.ImplementationFactory != null)
  13. {
  14. aidasi.Register(service.ServiceType, provider => service.ImplementationFactory(provider), service.Lifetime.AsAidasiLifetime());
  15. }
  16. else if(service.ImplementationInstance != null)
  17. {
  18. // 通过不同的扩展注册服务
  19. aidasi.Register(service.ServiceType, service.ImplementationInstance);
  20. }
  21. else
  22. {
  23. // 通过不同的扩展进行注册服务
  24. aidasi.Register(service.ServiceType, service.ImplementationType, service.Lifetime.AsAidasiLifetime());
  25. }
  26. }
  27. // 返回对应的ContainerBuilder
  28. return new AidasiBuilder(aidasi);
  29. }
  30. /// <summary>
  31. /// 获取IServiceProvider
  32. /// </summary>
  33. /// <param name="containerBuilder"></param>
  34. /// <returns></returns>
  35. public IServiceProvider CreateServiceProvider(AidasiBuilder containerBuilder)
  36. {
  37. return containerBuilder.BuildServiceProvider();
  38. }
  39. }

添加生命周期转换的扩展方法与添加该依赖注入的方法。

  1. internal static class Extensions
  2. {
  3. public static Lifetime AsAidasiLifetime(this ServiceLifetime service) => service switch {
  4. ServiceLifetime.Scoped => Lifetime.Self,
  5. ServiceLifetime.Singleton => Lifetime.Root,
  6. ServiceLifetime.Transient => Lifetime.Transient,
  7. _ => throw new Exception($"{typeof(ServiceLifetime)} Can't Convert")
  8. };
  9. public static IServiceProvider AddAiDasiService(this IServiceCollection services)
  10. {
  11. // 实例创建范围服务的工厂
  12. var factory = new AidasiServiceProviderFactory();
  13. // 创建Builder获取IServiceProvider
  14. return factory.CreateBuilder(services)
  15. .Register(Assembly.GetEntryAssembly())
  16. .BuildServiceProvider();
  17. }
  18. }

修改Program类

  1. static void Main(string[] args)
  2. {
  3. // 这里不用root的原因是它本身就是根节点
  4. var services = new ServiceCollection()
  5. .AddSingleton<IDemo, Demo>();
  6. // 使用Aidasi依赖注入框架
  7. var _ServiceProvider = services.AddAiDasiService();
  8. // 创建区域范围
  9. using (var child = _ServiceProvider.CreateScope())
  10. {
  11. child.ServiceProvider.GetService<IDemo>();
  12. }
  13. Console.WriteLine("End of subregion");
  14. _ServiceProvider.GetService<IDemo>();
  15. Console.WriteLine("Exit");
  16. Console.ReadKey();
  17. }
  18. public interface IDemo
  19. {
  20. }
  21. public class Demo : IDemo, IDisposable
  22. {
  23. public void Dispose()
  24. {
  25. Console.WriteLine("Demo is Disposable");
  26. }
  27. }

运行测试


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

net core 使用 EF Code First

下面这些内容很老了看这篇:https://www.tnblog.net/aojiancc2/article/details/5365 项目使用多层,把数据库访问...

.net mvc分部页,.net core分部页

.net分部页的三种方式第一种:@Html.Partial(&quot;_分部页&quot;)第二种:@{ Html.RenderPartial(&quot;分部页&quot;);}...

StackExchange.Redis操作redis(net core支持)

官方git开源地址https://github.com/StackExchange/StackExchange.Redis官方文档在docs里边都是官方的文档通过nuget命令下...

.net core 使用session

tip:net core 2.2后可以直接启用session了,不用在自己添加一次session依赖,本身就添加了使用nuget添加引用Microsoft.AspN...

通俗易懂,什么是.net?什么是.net Framework?什么是.net core?

朋友圈@蓝羽 看到一篇文章写的太详细太通俗了,搬过来细细看完,保证你对.NET有个新的认识理解原文地址:https://www.cnblo...

asp.net core2.0 依赖注入 AddTransient与AddScoped的区别

asp.net core主要提供了三种依赖注入的方式其中AddTransient与AddSingleton比较好区别AddTransient瞬时模式:每次都获取一...

.net core 使用 Kestrel

Kestrel介绍 Kestrel是一个基于libuv的跨平台web服务器 在.net core项目中就可以不一定要发布在iis下面了Kestrel体验可以使...

net core中使用cookie

net core中可以使用传统的cookie也可以使用加密的cookieNET CORE中使用传统cookie设置:HttpContext.Response.Cookies.Appe...

net core项目结构简单分析

一:wwwrootwwwroot用于存放网站的静态资源,例如css,js,图片与相关的前端插件等lib主要是第三方的插件,例如微软默认引用...

net core使用EF之DB First

一.新建一个.net core的MVC项目新建好项目后,不能像以前一样直接在新建项中添加ef了,需要用命令在添加ef的依赖二.使用Nug...

.net core使用requestresponse下载文件下载excel等

使用request获取内容net core中request没有直接的索引方法,需要点里边的Query,或者formstringbase64=Request.Form[&quot;f...

iframe自适应高度与配合net core使用

去掉iframe边框frameborder=&quot;0&quot;去掉滚动条scrolling=&quot;no&quot;iframe 自适应高度如果内容是固定的,那么就...

net core启动报错Unable to configure HTTPS endpoint. No server certificate was specified

这是因为net core2.1默认使用的https,如果使用Kestrel web服务器的话没有安装证书就会报这个错其实仔细看他的错误提示,其...

net core中使用url编码与解码操作

net core中暂时还没有以前asp.net与mvc中的server对象。获取url的编码与解码操作不能使用以前的server对象来获取。使用的是...

下载net core

官方下载地址:https://dotnet.microsoft.com/download 进来之后就可以看到最新的下载版本可以直接点击下载,也可以下载其...
这一世以无限游戏为使命!
排名
2
文章
657
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术