diff --git a/ServiceAnt.sln b/ServiceAnt.sln index 47ea89b..2a66828 100644 --- a/ServiceAnt.sln +++ b/ServiceAnt.sln @@ -26,6 +26,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4FE1FF00-52E src\Directory.Build.props = src\Directory.Build.props EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceAnt.IocInstaller.DotNetCore", "src\ServiceAnt.IocInstaller.DotNetCore\ServiceAnt.IocInstaller.DotNetCore.csproj", "{47B742B7-62A5-45EC-99F2-1700F60D138E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceAnt.IocInstaller.DotNetCore.Test", "test\ServiceAnt.IocInstaller.DotNetCore.Test\ServiceAnt.IocInstaller.DotNetCore.Test.csproj", "{2A67FC30-B4C3-4945-BFF7-E25A5C496ADE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -56,6 +60,14 @@ Global {ABC9A287-31CC-422B-84A2-6EAEF0BD448E}.Debug|Any CPU.Build.0 = Debug|Any CPU {ABC9A287-31CC-422B-84A2-6EAEF0BD448E}.Release|Any CPU.ActiveCfg = Release|Any CPU {ABC9A287-31CC-422B-84A2-6EAEF0BD448E}.Release|Any CPU.Build.0 = Release|Any CPU + {47B742B7-62A5-45EC-99F2-1700F60D138E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47B742B7-62A5-45EC-99F2-1700F60D138E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47B742B7-62A5-45EC-99F2-1700F60D138E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47B742B7-62A5-45EC-99F2-1700F60D138E}.Release|Any CPU.Build.0 = Release|Any CPU + {2A67FC30-B4C3-4945-BFF7-E25A5C496ADE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A67FC30-B4C3-4945-BFF7-E25A5C496ADE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A67FC30-B4C3-4945-BFF7-E25A5C496ADE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A67FC30-B4C3-4945-BFF7-E25A5C496ADE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -68,6 +80,8 @@ Global {1FA5221C-9A54-4132-B7CF-CF7CC7A30E59} = {0E041832-D5A5-4220-BD7D-95B03E66FF98} {ABC9A287-31CC-422B-84A2-6EAEF0BD448E} = {BDFDFA2C-DA6F-4405-B7B0-31D1B0997150} {4FE1FF00-52E7-4311-A21F-7C34831E62F1} = {5220EBDE-1FFD-4155-85A9-9A87DF0C073C} + {47B742B7-62A5-45EC-99F2-1700F60D138E} = {0E041832-D5A5-4220-BD7D-95B03E66FF98} + {2A67FC30-B4C3-4945-BFF7-E25A5C496ADE} = {BDFDFA2C-DA6F-4405-B7B0-31D1B0997150} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {52E5EADF-2B54-4C50-BF32-93550974966D} diff --git a/src/ServiceAnt.IocInstaller.Autofac/ServiceAntModule.cs b/src/ServiceAnt.IocInstaller.Autofac/ServiceAntModule.cs index 810e58a..57a9673 100644 --- a/src/ServiceAnt.IocInstaller.Autofac/ServiceAntModule.cs +++ b/src/ServiceAnt.IocInstaller.Autofac/ServiceAntModule.cs @@ -28,42 +28,44 @@ public ServiceAntModule(params System.Reflection.Assembly[] handlerAssemblies) _handlerAssemblies = handlerAssemblies; } - /// - /// Excute this method ater you builded container - /// - /// - public static void RegisterHandlers(IComponentContext container) - { - foreach (var aHandlerAssembly in _handlerAssemblies) - { - var handlerTypes = aHandlerAssembly.GetTypes().Where(p => typeof(IHandler).IsAssignableFrom(p) && !p.IsInterface); - - foreach (var aHandler in handlerTypes) - { - RegisterHandlerType(container, aHandler); - } - } - } - /// /// Intall dependenies and register handler function /// /// protected override void Load(ContainerBuilder builder) { - var serviceBus = InProcessServiceBus.Default; - builder.RegisterInstance(serviceBus).As(); - builder.RegisterType().AsSelf().As().SingleInstance(); - builder.RegisterType().AsSelf().As().SingleInstance(); + var subcriptionsManager = new InMemorySubscriptionsManager(); + var requestManager = new InMemoryRequestHandlerManager(); + + RegisterHandlers(subcriptionsManager, requestManager); + builder.RegisterInstance(subcriptionsManager).As().SingleInstance(); + builder.RegisterInstance(requestManager).As().SingleInstance(); - builder.Register(ctx => + builder.Register(ctx => { return new IocResolver(ctx.Resolve()); }); + builder.RegisterType().AsSelf().As().SingleInstance(); + builder.RegisterAssemblyTypes(_handlerAssemblies).AsSelf(); + + } + + private void RegisterHandlers(ISubscriptionManager subcriptionsManager, IRequestHandlerManager requestManager ) + { + foreach (var aHandlerAssembly in _handlerAssemblies) + { + var handlerTypes = aHandlerAssembly.GetTypes().Where(p => typeof(IHandler).IsAssignableFrom(p) && !p.IsInterface); + + foreach (var aHandler in handlerTypes) + { + RegisterHandlerType(subcriptionsManager, requestManager, aHandler); + } + } } - private static void RegisterHandlerType(IComponentContext container, Type aHandlerType) + + private void RegisterHandlerType(ISubscriptionManager subcriptionsManager, IRequestHandlerManager requestManager , Type aHandlerType) { var interfaces = aHandlerType.GetInterfaces(); foreach (var aInterface in interfaces) @@ -77,9 +79,9 @@ private static void RegisterHandlerType(IComponentContext container, Type aHandl if (genericArgs.Length == 1) { if (typeof(IRequestHandler).IsAssignableFrom(aInterface)) - container.Resolve().AddRequestHandler(genericArgs[0], new IocHandlerFactory(container.Resolve(), aHandlerType, genericArgs[0])); + requestManager.AddRequestHandler(genericArgs[0], new IocHandlerFactory( aHandlerType, genericArgs[0])); else - container.Resolve().AddSubscription(genericArgs[0], new IocHandlerFactory(container.Resolve(), aHandlerType, genericArgs[0])); + subcriptionsManager.AddSubscription(genericArgs[0], new IocHandlerFactory( aHandlerType, genericArgs[0])); } } } diff --git a/src/ServiceAnt.IocInstaller.Castle/ServiceAntInstaller.cs b/src/ServiceAnt.IocInstaller.Castle/ServiceAntInstaller.cs index 4610aa0..01ac12b 100644 --- a/src/ServiceAnt.IocInstaller.Castle/ServiceAntInstaller.cs +++ b/src/ServiceAnt.IocInstaller.Castle/ServiceAntInstaller.cs @@ -3,6 +3,7 @@ using Castle.MicroKernel.SubSystems.Configuration; using Castle.Windsor; using ServiceAnt.Handler.Request; +using ServiceAnt.Infrastructure.Dependency; using ServiceAnt.Request.Handler; using ServiceAnt.Subscription; using System; @@ -42,7 +43,8 @@ public void Install(IWindsorContainer container, IConfigurationStore store) _container = container; container.Register( - Component.For().Instance(InProcessServiceBus.Default), + Component.For().UsingFactoryMethod(ctx => new IocResolver(container)).LifestyleTransient(), + Component.For().ImplementedBy().LifestyleSingleton(), Component.For().ImplementedBy().LifestyleSingleton(), Component.For().ImplementedBy().LifestyleSingleton()); @@ -75,15 +77,13 @@ private void Kernel_ComponentRegistered(string key, IHandler handler) continue; } - var resolver = new IocResolver(_container); - var genericArgs = aInterface.GetGenericArguments(); if (genericArgs.Length == 1) { if (typeof(IRequestHandler).GetTypeInfo().IsAssignableFrom(aInterface)) - _serviceBus.AddRequestHandler(genericArgs[0], new Base.IocHandlerFactory(resolver, handler.ComponentModel.Implementation, genericArgs[0])); + _serviceBus.AddRequestHandler(genericArgs[0], new Base.IocHandlerFactory(handler.ComponentModel.Implementation, genericArgs[0])); else - _serviceBus.AddSubscription(genericArgs[0], new Base.IocHandlerFactory(resolver, handler.ComponentModel.Implementation, genericArgs[0])); + _serviceBus.AddSubscription(genericArgs[0], new Base.IocHandlerFactory(handler.ComponentModel.Implementation, genericArgs[0])); } } } diff --git a/src/ServiceAnt.IocInstaller.DotNetCore/IocResolver.cs b/src/ServiceAnt.IocInstaller.DotNetCore/IocResolver.cs new file mode 100644 index 0000000..b5c372f --- /dev/null +++ b/src/ServiceAnt.IocInstaller.DotNetCore/IocResolver.cs @@ -0,0 +1,46 @@ +using ServiceAnt.Infrastructure.Dependency; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ServiceAnt.IocInstaller.DotNetCore +{ + /// + /// IocResolver + /// + public class IocResolver : IIocResolver + { + private readonly IServiceProvider _container; + + /// + /// Constructor + /// + /// the container of castle + public IocResolver(IServiceProvider container) + { + _container = container; + } + + /// + /// Releases a pre-resolved object. See Resolve methods. + /// + /// Object to be released + public void Release(object obj) + { + } + + /// + /// Gets an object from IOC container. + /// Returning object must be Released (see ) after usage. + /// + /// Type of the object to cast + /// Type of the object to resolve + /// The object instance + public T Resolve(Type type) + { + return (T)_container.GetService(type); + } + } +} diff --git a/src/ServiceAnt.IocInstaller.DotNetCore/ServiceAnt.IocInstaller.DotNetCore.csproj b/src/ServiceAnt.IocInstaller.DotNetCore/ServiceAnt.IocInstaller.DotNetCore.csproj new file mode 100644 index 0000000..c1c80cf --- /dev/null +++ b/src/ServiceAnt.IocInstaller.DotNetCore/ServiceAnt.IocInstaller.DotNetCore.csproj @@ -0,0 +1,15 @@ + + + The IOC installer of ServiceAnt for dotnet core + $(PackageTags) + netcoreapp2.0 + + + + + + + + + + diff --git a/src/ServiceAnt.IocInstaller.DotNetCore/ServiceCollectionExtensions.cs b/src/ServiceAnt.IocInstaller.DotNetCore/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..cd47dd6 --- /dev/null +++ b/src/ServiceAnt.IocInstaller.DotNetCore/ServiceCollectionExtensions.cs @@ -0,0 +1,78 @@ +using Microsoft.Extensions.DependencyInjection; +using ServiceAnt.Handler.Request; +using ServiceAnt.Subscription; +using System; +using System.Reflection; +using System.Linq; +using ServiceAnt.Base; +using ServiceAnt.Request.Handler; +using ServiceAnt.Infrastructure.Dependency; +using ServiceAnt.IocInstaller.DotNetCore; +using ServiceAnt; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class ServiceCollectionExtensions + { + private static System.Reflection.Assembly[] _handlerAssemblies; + + public static void AddServiceAnt(this IServiceCollection @this, params Assembly[] handlerAssemblies) + { + _handlerAssemblies = handlerAssemblies; + + var subcriptionsManager = new InMemorySubscriptionsManager(); + var requestManager = new InMemoryRequestHandlerManager(); + + RegisterHandlers(subcriptionsManager, requestManager); + @this.AddSingleton(subcriptionsManager); + @this.AddSingleton(requestManager); + + @this.AddTransient(serviceProvider => + { + return new IocResolver(serviceProvider); + }); + @this.AddSingleton(); + + + var allHandlerTypes = _handlerAssemblies.SelectMany(p => p.ExportedTypes).Where(p=>typeof(IHandler).IsAssignableFrom(p)); + foreach (var aHandlerType in allHandlerTypes) + { + @this.AddTransient(aHandlerType); + } + } + + private static void RegisterHandlers(ISubscriptionManager subcriptionsManager, IRequestHandlerManager requestManager) + { + foreach (var aHandlerAssembly in _handlerAssemblies) + { + var handlerTypes = aHandlerAssembly.GetTypes().Where(p => typeof(IHandler).IsAssignableFrom(p) && !p.IsInterface); + + foreach (var aHandler in handlerTypes) + { + RegisterHandlerType(subcriptionsManager, requestManager, aHandler); + } + } + } + + private static void RegisterHandlerType(ISubscriptionManager subcriptionsManager, IRequestHandlerManager requestManager, Type aHandlerType) + { + var interfaces = aHandlerType.GetInterfaces(); + foreach (var aInterface in interfaces) + { + if (!typeof(IHandler).IsAssignableFrom(aInterface)) + { + continue; + } + + var genericArgs = aInterface.GetGenericArguments(); + if (genericArgs.Length == 1) + { + if (typeof(IRequestHandler).IsAssignableFrom(aInterface)) + requestManager.AddRequestHandler(genericArgs[0], new IocHandlerFactory(aHandlerType, genericArgs[0])); + else + subcriptionsManager.AddSubscription(genericArgs[0], new IocHandlerFactory(aHandlerType, genericArgs[0])); + } + } + } + } +} diff --git a/src/ServiceAnt/Base/IocHandlerFactory.cs b/src/ServiceAnt/Base/IocHandlerFactory.cs index 2988b62..2c6922f 100644 --- a/src/ServiceAnt/Base/IocHandlerFactory.cs +++ b/src/ServiceAnt/Base/IocHandlerFactory.cs @@ -16,16 +16,23 @@ public class IocHandlerFactory : IHandlerFactory /// /// ctor /// - /// /// /// - public IocHandlerFactory(IIocResolver iocResolver, Type handlerType, Type localEventType) + public IocHandlerFactory(Type handlerType, Type localEventType) { - _iocResolver = iocResolver; _handlerType = handlerType; _localEventType = localEventType; } + /// + /// set the IocResolver to resolve service + /// + /// + public void SetIocResolver(IIocResolver iocResolver) + { + _iocResolver = iocResolver; + } + /// /// get handler /// diff --git a/src/ServiceAnt/InProcessServiceBus.cs b/src/ServiceAnt/InProcessServiceBus.cs index ce277c8..9cde160 100644 --- a/src/ServiceAnt/InProcessServiceBus.cs +++ b/src/ServiceAnt/InProcessServiceBus.cs @@ -3,6 +3,7 @@ using ServiceAnt.Base; using ServiceAnt.Handler.Request; using ServiceAnt.Handler.Subscription.Handler; +using ServiceAnt.Infrastructure.Dependency; using ServiceAnt.Request; using ServiceAnt.Request.Handler; using ServiceAnt.Subscription; @@ -17,20 +18,37 @@ namespace ServiceAnt /// public class InProcessServiceBus : IServiceBus { - private ISubscriptionManager _subcriptionManager; - private IRequestHandlerManager _requestHandlerManager; + private readonly ISubscriptionManager _subcriptionManager; + private readonly IRequestHandlerManager _requestHandlerManager; + private readonly IIocResolver _iocResolver; /// /// Use to log message of bus /// public event LogBusMessage OnLogBusMessage; - private static Lazy _defaultInstance = new Lazy(); + private static InProcessServiceBus _defaultInstance; + private static object _lock = new object(); /// /// Default Instance /// - public static InProcessServiceBus Default => _defaultInstance.Value; + public static InProcessServiceBus Default + { + get + { + if (_defaultInstance == null) + { + lock (_lock) + { + if (_defaultInstance == null) + _defaultInstance = new InProcessServiceBus(); + } + } + + return _defaultInstance; + } + } /// /// Constructor @@ -46,10 +64,13 @@ public InProcessServiceBus() /// /// /// - public InProcessServiceBus(ISubscriptionManager subcriptionManager, IRequestHandlerManager requestHandlerManager) + /// + public InProcessServiceBus(ISubscriptionManager subcriptionManager, IRequestHandlerManager requestHandlerManager, IIocResolver iocResolver) { _subcriptionManager = subcriptionManager; _requestHandlerManager = requestHandlerManager; + _iocResolver = iocResolver; + _defaultInstance = this; } #region Pub/Sub @@ -153,6 +174,7 @@ private async Task ProcessEvent(string eventName, string message, TriggerOption { try { + SetTheIocResolverIfIocHandlerFactory(aHandlerFactory); var aHandler = aHandlerFactory.GetHandler(); if (aHandler is IDynamicEventHandler) { @@ -307,7 +329,7 @@ private async Task ProcessRequest(string eventName, string message, Trigge { if (requestContext.IsEnd) break; - + SetTheIocResolverIfIocHandlerFactory(aHandlerFactory); try { var aHandler = aHandlerFactory.GetHandler(); @@ -346,5 +368,12 @@ private void LogMessage(LogLevel type, string value, Exception ex) { OnLogBusMessage?.Invoke(type, value, ex); } + + private void SetTheIocResolverIfIocHandlerFactory(IHandlerFactory aHandlerFactory) + { + var iocHandlerFactory = aHandlerFactory as IocHandlerFactory; + if (iocHandlerFactory != null) + iocHandlerFactory.SetIocResolver(_iocResolver); + } } } diff --git a/test/ServiceAnt.IocInstaller.Autofac.Test/ServiceAntModule_Test.cs b/test/ServiceAnt.IocInstaller.Autofac.Test/ServiceAntModule_Test.cs index 1c32820..3be9bf5 100644 --- a/test/ServiceAnt.IocInstaller.Autofac.Test/ServiceAntModule_Test.cs +++ b/test/ServiceAnt.IocInstaller.Autofac.Test/ServiceAntModule_Test.cs @@ -28,7 +28,6 @@ public async Task CanHandleEventByIocHandler() var newContainer = new ContainerBuilder(); newContainer.RegisterModule(new ServiceAntModule(System.Reflection.Assembly.GetExecutingAssembly())); var autofacContainer = newContainer.Build(); - ServiceAntModule.RegisterHandlers(autofacContainer); await autofacContainer.Resolve().Publish(new TestEventTrigger() { Result = testValue }); @@ -42,7 +41,6 @@ public async Task CanHandleRequestByIocHandler() var newContainer = new ContainerBuilder(); newContainer.RegisterModule(new ServiceAntModule(System.Reflection.Assembly.GetExecutingAssembly())); var autofacContainer = newContainer.Build(); - ServiceAntModule.RegisterHandlers(autofacContainer); var result = await autofacContainer.Resolve().SendAsync(new TestRequestTrigger() { Result = testValue }); diff --git a/test/ServiceAnt.IocInstaller.DotNetCore.Test/ServiceAnt.IocInstaller.DotNetCore.Test.csproj b/test/ServiceAnt.IocInstaller.DotNetCore.Test/ServiceAnt.IocInstaller.DotNetCore.Test.csproj new file mode 100644 index 0000000..7178aa8 --- /dev/null +++ b/test/ServiceAnt.IocInstaller.DotNetCore.Test/ServiceAnt.IocInstaller.DotNetCore.Test.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp2.0 + + false + + + + + + + + + + + + + + diff --git a/test/ServiceAnt.IocInstaller.DotNetCore.Test/ServiceCollectionExtensions_Test.cs b/test/ServiceAnt.IocInstaller.DotNetCore.Test/ServiceCollectionExtensions_Test.cs new file mode 100644 index 0000000..2c6a7ba --- /dev/null +++ b/test/ServiceAnt.IocInstaller.DotNetCore.Test/ServiceCollectionExtensions_Test.cs @@ -0,0 +1,74 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using ServiceAnt.Request; +using ServiceAnt.Request.Handler; +using ServiceAnt.Subscription; +using ServiceAnt.Subscription.Handler; +using System; +using System.Threading.Tasks; + +namespace ServiceAnt.IocInstaller.DotNetCore.Test +{ + [TestClass] + public class ServiceCollectionExtensions_Test + { + private static string RESULT_CONTAINER = ""; + private readonly IServiceProvider _provider; + + public ServiceCollectionExtensions_Test() + { + IServiceCollection services = new ServiceCollection(); + services.AddServiceAnt(System.Reflection.Assembly.GetExecutingAssembly()); + _provider = services.BuildServiceProvider(); + } + + [TestMethod] + public async Task CanHandleEventByIocHandler() + { + var testValue = "HelloWorld"; + + await _provider.GetService().Publish(new TestEventTrigger() { Result = testValue }); + + Assert.AreEqual(testValue, RESULT_CONTAINER); + } + + [TestMethod] + public async Task CanHandleRequestByIocHandler() + { + var testValue = "HelloWorld2"; + + var result = await _provider.GetService().SendAsync(new TestRequestTrigger() { Result = testValue }); + + Assert.AreEqual(testValue, result); + } + + public class TestEventTrigger : IEventTrigger + { + public string Result { get; set; } + } + + public class TestRequestTrigger : IRequestTrigger + { + public string Result { get; set; } + } + + public class IocEventHandler : IEventHandler + { + public Task HandleAsync(TestEventTrigger param) + { + RESULT_CONTAINER = param.Result; + + return Task.Delay(1); + } + } + + public class IocRequestHandler : IRequestHandler + { + public Task HandleAsync(TestRequestTrigger param, IRequestHandlerContext handlerContext) + { + handlerContext.Response = param.Result; + return Task.Delay(1); + } + } + } +}