From 702891e6f1c238e37ac0936a1b59ad57ad785da8 Mon Sep 17 00:00:00 2001 From: Joel Dickson Date: Sun, 6 Mar 2022 11:26:30 +0700 Subject: [PATCH 1/2] Add autofac startupable --- .../Agoda.IoC.AutofacExt.UnitTests.csproj | 1 + .../AutoWireAssemblyExtTests.cs | 19 +++++++++++--- .../AutoWireAssemblyExt.cs | 26 ++++++++++++++++++- src/Agoda.IoC.Core/IStartupable.cs | 7 +++++ .../ValidRegistrations2.cs | 19 ++++++++++++++ 5 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 src/Agoda.IoC.Core/IStartupable.cs diff --git a/src/Agoda.IoC.AutofacExt.UnitTests/Agoda.IoC.AutofacExt.UnitTests.csproj b/src/Agoda.IoC.AutofacExt.UnitTests/Agoda.IoC.AutofacExt.UnitTests.csproj index 9c8db2c..cc9e14f 100644 --- a/src/Agoda.IoC.AutofacExt.UnitTests/Agoda.IoC.AutofacExt.UnitTests.csproj +++ b/src/Agoda.IoC.AutofacExt.UnitTests/Agoda.IoC.AutofacExt.UnitTests.csproj @@ -29,6 +29,7 @@ + diff --git a/src/Agoda.IoC.AutofacExt.UnitTests/AutoWireAssemblyExtTests.cs b/src/Agoda.IoC.AutofacExt.UnitTests/AutoWireAssemblyExtTests.cs index 7d5d2bf..a2f6015 100644 --- a/src/Agoda.IoC.AutofacExt.UnitTests/AutoWireAssemblyExtTests.cs +++ b/src/Agoda.IoC.AutofacExt.UnitTests/AutoWireAssemblyExtTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Agoda.IoC.ProjectUnderTest.Valid; +using Agoda.IoC.ProjectUnderTest.Valid2; using Autofac; using Autofac.Core; using Autofac.Core.Lifetime; @@ -27,13 +28,17 @@ public void SetUp() _containerBuilder = new ContainerBuilder(); _container = _containerBuilder.AutoWireAssembly(new[] { - typeof(NoAttribute).Assembly - }, false).Build(); + typeof(NoAttribute).Assembly, + typeof(ServiceThatStartsUp).Assembly + }, false).Build() + .UseStartupable(); _containerBuilderMocked = new ContainerBuilder(); _containerMocked = _containerBuilderMocked.AutoWireAssembly(new[] { - typeof(NoAttribute).Assembly - }, true).Build(); + typeof(NoAttribute).Assembly, + typeof(ServiceThatStartsUp).Assembly + }, true).Build() + .UseStartupable(); } [Test] @@ -235,5 +240,11 @@ public void LookforAutowire_GenericWithFactory() && x.Lifetime is CurrentScopeLifetime) .ShouldBeTrue(); } + + [Test] + public void WhenRegistarteStartupableClass_ShouldRunStartupmethods() + { + _container.Resolve().Somedata.ShouldBe(1); + } } } diff --git a/src/Agoda.IoC.AutofacExt/AutoWireAssemblyExt.cs b/src/Agoda.IoC.AutofacExt/AutoWireAssemblyExt.cs index ccdc3e6..19a27cb 100644 --- a/src/Agoda.IoC.AutofacExt/AutoWireAssemblyExt.cs +++ b/src/Agoda.IoC.AutofacExt/AutoWireAssemblyExt.cs @@ -1,9 +1,11 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using Agoda.IoC.Core; using Autofac; +using Autofac.Core; namespace Agoda.IoC.AutofacExt { @@ -87,7 +89,6 @@ public static ContainerBuilder AutoWireAssembly(this ContainerBuilder service if (toType.IsGenericTypeDefinition) { services.RegisterGeneric(toType).As(reg.FromType).SingleInstance(); - } else { @@ -106,5 +107,28 @@ public static ContainerBuilder AutoWireAssembly(this ContainerBuilder service } return services; } + + public static IContainer UseStartupable(this IContainer container) + { + var listOfStartupableServiceRegistrations = + container.ComponentRegistry.Registrations + .Where(x => typeof(IStartupable).IsAssignableFrom(x.Target.Activator.LimitType)) + .SelectMany(y => y.Services); + + foreach (var StartupableService in listOfStartupableServiceRegistrations) + { + ((IStartupable)container.ResolveService(StartupableService)).Start(); + } + + return container; + } + + + private static bool ContainsType(IEnumerable services, Type t) + { + return services.Where(y => y is TypedService) + .Any(z => ((TypedService)z).ServiceType == t); + } + } } diff --git a/src/Agoda.IoC.Core/IStartupable.cs b/src/Agoda.IoC.Core/IStartupable.cs new file mode 100644 index 0000000..e344ab0 --- /dev/null +++ b/src/Agoda.IoC.Core/IStartupable.cs @@ -0,0 +1,7 @@ +namespace Agoda.IoC.Core +{ + public interface IStartupable + { + void Start(); + } +} \ No newline at end of file diff --git a/src/ProjectsUnderTest/Agoda.IoC.ProjectUnderTest.Valid2/ValidRegistrations2.cs b/src/ProjectsUnderTest/Agoda.IoC.ProjectUnderTest.Valid2/ValidRegistrations2.cs index 234ba40..d0f9cf7 100644 --- a/src/ProjectsUnderTest/Agoda.IoC.ProjectUnderTest.Valid2/ValidRegistrations2.cs +++ b/src/ProjectsUnderTest/Agoda.IoC.ProjectUnderTest.Valid2/ValidRegistrations2.cs @@ -10,4 +10,23 @@ public class ReplaceServiceTwoWork : IReplaceService public string DoWork { get; set; } = nameof(ReplaceServiceTwoWork); } + + public interface IServiceThatStartsUp + { + int Somedata { get; set; } + } + + [RegisterSingleton(For = typeof(IServiceThatStartsUp))] + public class ServiceThatStartsUp : IServiceThatStartsUp, IStartupable + { + public ServiceThatStartsUp() + { + Somedata = 0; + } + public int Somedata { get; set; } + public void Start() + { + Somedata++; + } + } } From fd245419e932a58aa7f4545cc81126e791ee53ad Mon Sep 17 00:00:00 2001 From: Joel Dickson Date: Sun, 6 Mar 2022 14:11:34 +0700 Subject: [PATCH 2/2] add netcore implementation for startupable --- .../AutoWireAssemblyExtTests.cs | 4 +-- .../AutoWireAssemblyExt.cs | 2 +- src/Agoda.IoC.Core/RegistrationContext.cs | 4 +-- ...ensionsDependencyInjectionAutowireTests.cs | 8 +++++ .../NetCoreComponentResolver.cs | 22 ++++++++++++ src/Agoda.IoC.NetCore/StartupExtension.cs | 36 ++++++++++--------- 6 files changed, 55 insertions(+), 21 deletions(-) create mode 100644 src/Agoda.IoC.NetCore/NetCoreComponentResolver.cs diff --git a/src/Agoda.IoC.AutofacExt.UnitTests/AutoWireAssemblyExtTests.cs b/src/Agoda.IoC.AutofacExt.UnitTests/AutoWireAssemblyExtTests.cs index a2f6015..afc0225 100644 --- a/src/Agoda.IoC.AutofacExt.UnitTests/AutoWireAssemblyExtTests.cs +++ b/src/Agoda.IoC.AutofacExt.UnitTests/AutoWireAssemblyExtTests.cs @@ -31,14 +31,14 @@ public void SetUp() typeof(NoAttribute).Assembly, typeof(ServiceThatStartsUp).Assembly }, false).Build() - .UseStartupable(); + .UseAgodaIoCStartupable(); _containerBuilderMocked = new ContainerBuilder(); _containerMocked = _containerBuilderMocked.AutoWireAssembly(new[] { typeof(NoAttribute).Assembly, typeof(ServiceThatStartsUp).Assembly }, true).Build() - .UseStartupable(); + .UseAgodaIoCStartupable(); } [Test] diff --git a/src/Agoda.IoC.AutofacExt/AutoWireAssemblyExt.cs b/src/Agoda.IoC.AutofacExt/AutoWireAssemblyExt.cs index 19a27cb..7e3a0c1 100644 --- a/src/Agoda.IoC.AutofacExt/AutoWireAssemblyExt.cs +++ b/src/Agoda.IoC.AutofacExt/AutoWireAssemblyExt.cs @@ -108,7 +108,7 @@ public static ContainerBuilder AutoWireAssembly(this ContainerBuilder service return services; } - public static IContainer UseStartupable(this IContainer container) + public static IContainer UseAgodaIoCStartupable(this IContainer container) { var listOfStartupableServiceRegistrations = container.ComponentRegistry.Registrations diff --git a/src/Agoda.IoC.Core/RegistrationContext.cs b/src/Agoda.IoC.Core/RegistrationContext.cs index 3b6744f..ad562ce 100644 --- a/src/Agoda.IoC.Core/RegistrationContext.cs +++ b/src/Agoda.IoC.Core/RegistrationContext.cs @@ -19,7 +19,7 @@ public class RegistrationContext public bool ReplaceServices { get; } public (bool IsValid, string ErrorMessage) Validation { get; } - + public bool IsStartupable { get; private set; } private readonly IList _baseTypes; private readonly Type _originalToType; private readonly Type _genericArgument; @@ -42,7 +42,7 @@ public RegistrationContext( IsIntercepted = wrapper?.HasInterceptors(this) ?? false; _genericArgument = attribute.GenericArgument; _baseTypes = ContainerAttributeUtils.GetBaseTypes(attribute, toType).ToList(); - + IsStartupable = typeof(IStartupable).IsAssignableFrom(toType); // we might have to fiddle with the ToType to keep Unity happy, so we keep a copy of the original for error reporting _originalToType = ToType; diff --git a/src/Agoda.IoC.NetCore.UnitTests/MicrosoftExtensionsDependencyInjectionAutowireTests.cs b/src/Agoda.IoC.NetCore.UnitTests/MicrosoftExtensionsDependencyInjectionAutowireTests.cs index 0745d07..42eefe8 100644 --- a/src/Agoda.IoC.NetCore.UnitTests/MicrosoftExtensionsDependencyInjectionAutowireTests.cs +++ b/src/Agoda.IoC.NetCore.UnitTests/MicrosoftExtensionsDependencyInjectionAutowireTests.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using Agoda.IoC.Core; using Agoda.IoC.ProjectUnderTest.Valid; using Agoda.IoC.ProjectUnderTest.Valid2; using Microsoft.Extensions.DependencyInjection; @@ -272,5 +273,12 @@ public void LookforAutowire_ReplaceServiceChecks() svr = _notReplaceContainer.BuildServiceProvider().GetRequiredService(); svr.DoWork.ShouldBe(nameof(ReplaceServiceOneWork)); } + [Test] + public void WhenRegistarteStartupableClass_ShouldRunStartupmethods() + { + var app = _container.BuildServiceProvider(); + app.UseAgodaIoCStartupable(); + app.GetService().Somedata.ShouldBe(1); + } } } diff --git a/src/Agoda.IoC.NetCore/NetCoreComponentResolver.cs b/src/Agoda.IoC.NetCore/NetCoreComponentResolver.cs new file mode 100644 index 0000000..145976d --- /dev/null +++ b/src/Agoda.IoC.NetCore/NetCoreComponentResolver.cs @@ -0,0 +1,22 @@ +using System; +using Agoda.IoC.Core; +using Microsoft.Extensions.DependencyInjection; + +namespace Agoda.IoC.NetCore +{ + public class NetCoreComponentResolver : IComponentResolver + { + private readonly IServiceProvider _serviceProvider; + + public NetCoreComponentResolver(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public T Resolve() + { + return _serviceProvider.GetService(); + + } + } +} \ No newline at end of file diff --git a/src/Agoda.IoC.NetCore/StartupExtension.cs b/src/Agoda.IoC.NetCore/StartupExtension.cs index e4751bf..0a26fec 100644 --- a/src/Agoda.IoC.NetCore/StartupExtension.cs +++ b/src/Agoda.IoC.NetCore/StartupExtension.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; namespace Agoda.IoC.NetCore { @@ -25,6 +26,18 @@ public static IServiceCollection AutoWireAssembly( return rtn; } + public static IServiceProvider UseAgodaIoCStartupable(this IServiceProvider app) + { + foreach (var startupable in app.GetServices()) + { + if (startupable == null) + throw new Exception( + "No service found that inherit from IStartupable but UseAgodaIoCStartupable was called"); + startupable.Start(); + } + return app; + } + public static IServiceCollection AutoWireAssembly( this IServiceCollection services, Assembly[] assemblies, ServiceLifetime serviceLifetime, @@ -77,6 +90,13 @@ public static IServiceCollection AutoWireAssembly( { services.Add(serviceDescriptor); } + + if (reg.IsStartupable) + { + services.Add(new ServiceDescriptor(typeof(IStartupable), + x => x.GetService(reg.FromType), + ServiceLifetime.Singleton)); + } } return services; } @@ -167,20 +187,4 @@ private static bool Validate(List registrations, ContainerR return isValid; } } - - public class NetCoreComponentResolver : IComponentResolver - { - private readonly IServiceProvider _serviceProvider; - - public NetCoreComponentResolver(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public T Resolve() - { - return _serviceProvider.GetService(); - - } - } } \ No newline at end of file