From c663bc230946644b9d91999d9dbbccf8ebc699f5 Mon Sep 17 00:00:00 2001 From: Sam Ember Date: Wed, 26 May 2021 22:48:06 +0100 Subject: [PATCH] Abstraction of ServiceProvider, Improving Akka.DependencyInjection (#4814) * Abstraction of ServiceProvider * introduced non-breaking Akka.DependencyInjection API changes * fixed unit tests / Props bug * fixed up DelegateInjectionSpecs * Added type checking for `Props(Type type, params object[] args)` * fixed non-generic `Props()` method Co-authored-by: Aaron Stannard --- ...ctorServiceProviderPropsWithScopesSpecs.cs | 24 +++- .../DelegateInjectionSpecs.cs | 12 +- .../ServiceProviderSetupSpecs.cs | 22 +-- .../DependencyResolver.cs | 125 ++++++++++++++++++ .../DependencyResolverSetup.cs | 84 ++++++++++++ .../IDependencyResolver.cs | 61 +++++++++ .../ServiceProvider.cs | 27 +++- .../ServiceProviderDependencyResolver.cs | 62 +++++++++ .../ServiceProviderScope.cs | 33 +++++ .../ServiceProviderSetup.cs | 40 ------ .../Actors/AkkaService.cs | 5 +- 11 files changed, 428 insertions(+), 67 deletions(-) create mode 100644 src/contrib/dependencyinjection/Akka.DependencyInjection/DependencyResolver.cs create mode 100644 src/contrib/dependencyinjection/Akka.DependencyInjection/DependencyResolverSetup.cs create mode 100644 src/contrib/dependencyinjection/Akka.DependencyInjection/IDependencyResolver.cs create mode 100644 src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderDependencyResolver.cs create mode 100644 src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderScope.cs delete mode 100644 src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderSetup.cs diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ActorServiceProviderPropsWithScopesSpecs.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ActorServiceProviderPropsWithScopesSpecs.cs index ef5d2fe0c39..4c2c84c5f54 100644 --- a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ActorServiceProviderPropsWithScopesSpecs.cs +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ActorServiceProviderPropsWithScopesSpecs.cs @@ -21,7 +21,7 @@ namespace Akka.DependencyInjection.Tests public class ActorServiceProviderPropsWithScopesSpecs : AkkaSpec, IClassFixture { - public ActorServiceProviderPropsWithScopesSpecs(AkkaDiFixture fixture, ITestOutputHelper output) : base(ServiceProviderSetup.Create(fixture.Provider) + public ActorServiceProviderPropsWithScopesSpecs(AkkaDiFixture fixture, ITestOutputHelper output) : base(DependencyResolverSetup.Create(fixture.Provider) .And(BootstrapSetup.Create().WithConfig(TestKitBase.DefaultConfig)), output) { @@ -30,7 +30,7 @@ public ActorServiceProviderPropsWithScopesSpecs(AkkaDiFixture fixture, ITestOutp [Fact(DisplayName = "DI: actors who receive an IServiceScope through Props should dispose of their dependencies upon termination")] public void ActorsWithScopedDependenciesShouldDisposeUponStop() { - var spExtension = ServiceProvider.For(Sys); + var spExtension = DependencyResolver.For(Sys); var props = spExtension.Props(); // create a scoped actor using the props from Akka.DependencyInjection @@ -60,11 +60,23 @@ public void ActorsWithScopedDependenciesShouldDisposeUponStop() deps2.Dependencies.All(x => x.Disposed).Should().BeFalse(); } + [Fact(DisplayName = "DI: should be able to start actors with untyped Props")] + public void ShouldStartActorWithUntypedProps() + { + var spExtension = DependencyResolver.For(Sys); + var props = spExtension.Props(typeof(ScopedActor)); + + // create a scoped actor using the props from Akka.DependencyInjection + var scoped1 = Sys.ActorOf(props, "scoped1"); + scoped1.Tell(new FetchDependencies()); + var deps1 = ExpectMsg(); + } + [Fact(DisplayName = "DI: actors who receive an IServiceScope through Props should dispose of their dependencies and recreate upon restart")] public void ActorsWithScopedDependenciesShouldDisposeAndRecreateUponRestart() { - var spExtension = ServiceProvider.For(Sys); + var spExtension = DependencyResolver.For(Sys); var props = spExtension.Props(); // create a scoped actor using the props from Akka.DependencyInjection @@ -95,7 +107,7 @@ public void ActorsWithScopedDependenciesShouldDisposeAndRecreateUponRestart() "DI: actors who receive a mix of dependencies via IServiceScope should dispose ONLY of their scoped dependencies and recreate upon restart")] public void ActorsWithMixedDependenciesShouldDisposeAndRecreateScopedUponRestart() { - var spExtension = ServiceProvider.For(Sys); + var spExtension = DependencyResolver.For(Sys); var props = spExtension.Props(); // create a scoped actor using the props from Akka.DependencyInjection @@ -134,7 +146,7 @@ public void ActorsWithMixedDependenciesShouldDisposeAndRecreateScopedUponRestart public void ActorsWithNonDiDependenciesShouldStart() { // - var spExtension = ServiceProvider.For(Sys); + var spExtension = DependencyResolver.For(Sys); var arg1 = "foo"; var arg2 = "bar"; var props = spExtension.Props(arg1, arg2); @@ -182,7 +194,7 @@ public void ActorsWithNonDiDependenciesShouldStart() public void ServiceProvider_Props_should_support_copying() { // - var spExtension = ServiceProvider.For(Sys); + var spExtension = DependencyResolver.For(Sys); var arg1 = "foo"; var arg2 = "bar"; var props = spExtension.Props(arg1, arg2).WithRouter(new RoundRobinPool(10).WithSupervisorStrategy(new OneForOneStrategy( diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/DelegateInjectionSpecs.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/DelegateInjectionSpecs.cs index bc0a64388ad..1e2342644d6 100644 --- a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/DelegateInjectionSpecs.cs +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/DelegateInjectionSpecs.cs @@ -1,4 +1,10 @@ -using System; +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2021 Lightbend Inc. +// Copyright (C) 2013-2021 .NET Foundation +// +//----------------------------------------------------------------------- +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -73,7 +79,7 @@ public async Task DI_should_be_able_to_retrieve_singleton_using_delegate_from_in internal class ParentActor : UntypedActor { public static Props Props(ActorSystem system) => - ServiceProvider.For(system).Props(); + DependencyResolver.For(system).Props(); private readonly IActorRef _echoActor; @@ -114,7 +120,7 @@ public AkkaService(IServiceProvider serviceProvider) public Task StartAsync(CancellationToken cancellationToken) { - var setup = ServiceProviderSetup.Create(_serviceProvider) + var setup = DependencyResolverSetup.Create(_serviceProvider) .And(BootstrapSetup.Create().WithConfig(TestKitBase.DefaultConfig)); ActorSystem = ActorSystem.Create("TestSystem", setup); diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ServiceProviderSetupSpecs.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ServiceProviderSetupSpecs.cs index e14e8e8ee4b..d44085f69f6 100644 --- a/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ServiceProviderSetupSpecs.cs +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection.Tests/ServiceProviderSetupSpecs.cs @@ -18,7 +18,7 @@ namespace Akka.DependencyInjection.Tests { public class ServiceProviderSetupSpecs : AkkaSpec, IClassFixture { - public ServiceProviderSetupSpecs(AkkaDiFixture fixture, ITestOutputHelper output) : base(ServiceProviderSetup.Create(fixture.Provider) + public ServiceProviderSetupSpecs(AkkaDiFixture fixture, ITestOutputHelper output) : base(DependencyResolverSetup.Create(fixture.Provider) .And(BootstrapSetup.Create().WithConfig(TestKitBase.DefaultConfig)), output) { @@ -27,29 +27,29 @@ public ServiceProviderSetupSpecs(AkkaDiFixture fixture, ITestOutputHelper output [Fact(DisplayName = "DI: Should access Microsoft.Extensions.DependencyInjection.IServiceProvider from ServiceProvider ActorSystem extension")] public void ShouldAccessServiceProviderFromActorSystemExtension() { - var sp = ServiceProvider.For(Sys); - var dep = sp.Provider.GetService(); + var sp = DependencyResolver.For(Sys); + var dep = sp.Resolver.GetService(); dep.Should().BeOfType(); - var dep2 = sp.Provider.GetService(); + var dep2 = sp.Resolver.GetService(); dep2.Should().NotBe(dep); // the two transient instances should be different // scoped services should be the same - var scoped1 = sp.Provider.GetService(); - var scoped2 = sp.Provider.GetService(); + var scoped1 = sp.Resolver.GetService(); + var scoped2 = sp.Resolver.GetService(); scoped1.Should().Be(scoped2); // create a new scope - using (var newScope = sp.Provider.CreateScope()) + using (var newScope = sp.Resolver.CreateScope()) { - var scoped3 = newScope.ServiceProvider.GetService(); + var scoped3 = newScope.Resolver.GetService(); scoped1.Should().NotBe(scoped3); } // singleton services should be the same - var singleton1 = sp.Provider.GetService(); - var singleton2 = sp.Provider.GetService(); + var singleton1 = sp.Resolver.GetService(); + var singleton2 = sp.Resolver.GetService(); singleton1.Should().Be(singleton2); } @@ -67,7 +67,7 @@ public void ShouldAccessServiceProviderFromActorSystemExtension() { Action getSp = () => { - var sp = ServiceProvider.For(Sys); + var sp = DependencyResolver.For(Sys); }; getSp.Should().Throw(); diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection/DependencyResolver.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection/DependencyResolver.cs new file mode 100644 index 00000000000..4917a1b8ed5 --- /dev/null +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection/DependencyResolver.cs @@ -0,0 +1,125 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2021 Lightbend Inc. +// Copyright (C) 2013-2021 .NET Foundation +// +//----------------------------------------------------------------------- + +using System; +using Akka.Actor; +using Akka.Configuration; +using Akka.Event; +using Microsoft.Extensions.DependencyInjection; + +namespace Akka.DependencyInjection +{ + /// + /// Provides users with immediate access to the bound to + /// this , if any. + /// + public sealed class DependencyResolver : IExtension + { + public DependencyResolver(IDependencyResolver resolver) + { + Resolver = resolver; + } + + /// + /// The globally scoped . + /// + /// + /// Per https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines - please use + /// the appropriate for your actors and the dependencies they consume. DI is typically + /// not used for long-lived, stateful objects such as actors. + /// + /// Therefore, injecting transient dependencies via constructors is a bad idea in most cases. You'd be far better off + /// creating a local "request scope" each time your actor processes a message that depends on a transient dependency, + /// such as a database connection, and disposing that scope once the operation is complete. + /// + /// Actors are not MVC Controllers. Actors can live forever, have the ability to restart, and are often stateful. + /// Be mindful of this as you use this feature or bad things will happen. Akka.NET does not magically manage scopes + /// for you. + /// + public IDependencyResolver Resolver { get; } + + public static DependencyResolver For(ActorSystem actorSystem) + { + return actorSystem.WithExtension(); + } + + /// + /// Uses a delegate to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection + /// and others are not. + /// + /// + /// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU. + /// + /// The type of actor to instantiate. + /// Optional. Any constructor arguments that will be passed into the actor's constructor directly without being resolved by DI first. + /// A new instance which uses DI internally. + public Props Props(params object[] args) where T : ActorBase + { + return Resolver.Props(args); + } + + /// + /// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection + /// and others are not. + /// + /// + /// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU. + /// + /// The type of actor to instantiate. + /// A new instance which uses DI internally. + public Props Props() where T : ActorBase + { + return Resolver.Props(); + } + + /// + /// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection + /// and others are not. + /// + /// + /// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU. + /// + /// The type of actor to instantiate. + /// A new instance which uses DI internally. + public Props Props(Type type) + { + return Resolver.Props(type); + } + + /// + /// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection + /// and others are not. + /// + /// + /// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU. + /// + /// The type of actor to instantiate. + /// Optional. Any constructor arguments that will be passed into the actor's constructor directly without being resolved by DI first. + /// A new instance which uses DI internally. + public Props Props(Type type, params object[] args) + { + return Resolver.Props(type, args); + } + } + + /// + /// INTERNAL API + /// + public sealed class DependencyResolverExtension : ExtensionIdProvider + { + public override DependencyResolver CreateExtension(ExtendedActorSystem system) + { + var setup = system.Settings.Setup.Get(); + if (setup.HasValue) return new DependencyResolver(setup.Value.DependencyResolver); + + var exception = new ConfigurationException("Unable to find [DependencyResolverSetup] included in ActorSystem settings." + + " Please specify one before attempting to use dependency injection inside Akka.NET."); + system.EventStream.Publish(new Error(exception, "Akka.DependencyInjection", typeof(DependencyResolverExtension), exception.Message)); + throw exception; + } + } +} diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection/DependencyResolverSetup.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection/DependencyResolverSetup.cs new file mode 100644 index 00000000000..3df580095a3 --- /dev/null +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection/DependencyResolverSetup.cs @@ -0,0 +1,84 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2021 Lightbend Inc. +// Copyright (C) 2013-2021 .NET Foundation +// +//----------------------------------------------------------------------- + +using System; +using Akka.Actor; +using Akka.Actor.Setup; + +namespace Akka.DependencyInjection +{ + /// + /// Used to help bootstrap an with dependency injection (DI) + /// support via a reference. + /// + /// The will be used to access previously registered services + /// in the creation of actors and other pieces of infrastructure inside Akka.NET. + /// + /// The constructor is internal. Please use to create a new instance. + /// + [Obsolete("Used DependencyResolverSetup instead.")] + public class ServiceProviderSetup : Setup + { + internal ServiceProviderSetup(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public IServiceProvider ServiceProvider { get; } + + public static ServiceProviderSetup Create(IServiceProvider provider) + { + if (provider == null) + throw new ArgumentNullException(nameof(provider)); + + return new ServiceProviderSetup(provider); + } + } + + /// + /// Used to help bootstrap an with dependency injection (DI) + /// support via a reference. + /// + /// The will be used to access previously registered services + /// in the creation of actors and other pieces of infrastructure inside Akka.NET. + /// + /// The constructor is internal. Please use to create a new instance. + /// + public class DependencyResolverSetup : Setup + { + public IDependencyResolver DependencyResolver { get; } + + internal DependencyResolverSetup(IDependencyResolver dependencyResolver) + { + DependencyResolver = dependencyResolver; + } + + /// + /// Creates a new instance of DependencyResolverSetup, passing in + /// here creates an that resolves dependencies from the specified + /// + public static DependencyResolverSetup Create(IServiceProvider provider) + { + if (provider == null) + throw new ArgumentNullException(nameof(provider)); + + return new DependencyResolverSetup(new ServiceProviderDependencyResolver(provider)); + } + + /// + /// Creates a new instance of DependencyResolverSetup, an implementation of + /// can be passed in here to resolve services from test or alternative DI frameworks. + /// + public static DependencyResolverSetup Create(IDependencyResolver provider) + { + if (provider == null) + throw new ArgumentNullException(nameof(provider)); + + return new DependencyResolverSetup(provider); + } + } +} diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection/IDependencyResolver.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection/IDependencyResolver.cs new file mode 100644 index 00000000000..d221f6480db --- /dev/null +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection/IDependencyResolver.cs @@ -0,0 +1,61 @@ +// //----------------------------------------------------------------------- +// // +// // Copyright (C) 2009-2021 Lightbend Inc. +// // Copyright (C) 2013-2021 .NET Foundation +// // +// //----------------------------------------------------------------------- + +using System; +using Akka.Actor; + +namespace Akka.DependencyInjection +{ + /// + /// Interface abstraction for working with DI providers + /// in Akka.NET without being bound to any specific implementation. + /// + /// + /// See for a reference implementation. + /// + public interface IDependencyResolver + { + IResolverScope CreateScope(); + object GetService(); + object GetService(Type type); + + /// + /// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection + /// and others are not. + /// + /// + /// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU. + /// + /// The type of actor to instantiate. + /// Optional. Any constructor arguments that will be passed into the actor's constructor directly without being resolved by DI first. + /// A new instance which uses DI internally. + Props Props(Type type, params object[] args); + + /// + /// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection + /// and others are not. + /// + /// + /// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU. + /// + /// The type of actor to instantiate. + /// A new instance which uses DI internally. + Props Props(Type type); + + /// + /// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection + /// and others are not. + /// + /// + /// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU. + /// + /// The type of actor to instantiate. + /// Optional. Any constructor arguments that will be passed into the actor's constructor directly without being resolved by DI first. + /// A new instance which uses DI internally. + Props Props(params object[] args) where T : ActorBase; + } +} \ No newline at end of file diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProvider.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProvider.cs index 883730d0b27..aa652707737 100644 --- a/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProvider.cs +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProvider.cs @@ -17,6 +17,10 @@ namespace Akka.DependencyInjection /// Provides users with immediate access to the bound to /// this , if any. /// + /// + /// [OBSOLETE] Switch to the instead. + /// + [Obsolete("Replaced by the Akka.DependencyInjection.DependencyResolver in Akka.NET v1.4.20. Please switch to that.")] public sealed class ServiceProvider : IExtension { public ServiceProvider(IServiceProvider provider) @@ -66,6 +70,7 @@ public static ServiceProvider For(ActorSystem actorSystem) /// /// INTERNAL API /// + [Obsolete("Use the DependencyResolverExtensions instead.")] public sealed class ServiceProviderExtension : ExtensionIdProvider { public override ServiceProvider CreateExtension(ExtendedActorSystem system) @@ -88,17 +93,16 @@ public override ServiceProvider CreateExtension(ExtendedActorSystem system) /// /// Used to create actors via the . /// - /// the actor type - internal sealed class ServiceProviderActorProducer : IIndirectActorProducer where TActor:ActorBase + internal class ServiceProviderActorProducer : IIndirectActorProducer { private readonly IServiceProvider _provider; private readonly object[] _args; - public ServiceProviderActorProducer(IServiceProvider provider, object[] args) + public ServiceProviderActorProducer(IServiceProvider provider, Type actorType, object[] args) { _provider = provider; _args = args; - ActorType = typeof(TActor); + ActorType = actorType; } public ActorBase Produce() @@ -113,4 +117,19 @@ public void Release(ActorBase actor) // no-op } } + + /// + /// INTERNAL API + /// + /// Used to create actors via the . + /// + /// the actor type + internal class ServiceProviderActorProducer : ServiceProviderActorProducer where TActor:ActorBase + { + + public ServiceProviderActorProducer(IServiceProvider provider, object[] args) + : base(provider, typeof(TActor), args) + { + } + } } diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderDependencyResolver.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderDependencyResolver.cs new file mode 100644 index 00000000000..8fdab7c3ada --- /dev/null +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderDependencyResolver.cs @@ -0,0 +1,62 @@ +// //----------------------------------------------------------------------- +// // +// // Copyright (C) 2009-2021 Lightbend Inc. +// // Copyright (C) 2013-2021 .NET Foundation +// // +// //----------------------------------------------------------------------- + +using System; +using Akka.Actor; +using Microsoft.Extensions.DependencyInjection; + +namespace Akka.DependencyInjection +{ + /// + /// INTERNAL API. + /// + /// implementation backed by + /// + public class ServiceProviderDependencyResolver : IDependencyResolver + { + public IServiceProvider ServiceProvider { get; } + + public ServiceProviderDependencyResolver(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public IResolverScope CreateScope() + { + return new ServiceProviderScope(ServiceProvider.CreateScope()); + } + + public object GetService() + { + return ServiceProvider.GetService(); + } + + public object GetService(Type type) + { + return ServiceProvider.GetService(type); + } + + public Props Props(Type type, params object[] args) + { + if(typeof(ActorBase).IsAssignableFrom(type)) + return Akka.Actor.Props.CreateBy(new ServiceProviderActorProducer(ServiceProvider, type, args)); + throw new ArgumentException(nameof(type), $"[{type}] does not implement Akka.Actor.ActorBase."); + } + + public Props Props(Type type) + { + return Props(type, Array.Empty()); + } + + public Props Props(params object[] args) where T : ActorBase + { + return Akka.Actor.Props.CreateBy(new ServiceProviderActorProducer(ServiceProvider, args)); + } + } + + +} diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderScope.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderScope.cs new file mode 100644 index 00000000000..ce3f1911dcc --- /dev/null +++ b/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderScope.cs @@ -0,0 +1,33 @@ +// //----------------------------------------------------------------------- +// // +// // Copyright (C) 2009-2021 Lightbend Inc. +// // Copyright (C) 2013-2021 .NET Foundation +// // +// //----------------------------------------------------------------------- + +using System; +using Microsoft.Extensions.DependencyInjection; + +namespace Akka.DependencyInjection +{ + public interface IResolverScope : IDisposable + { + IDependencyResolver Resolver { get; } + } + + public class ServiceProviderScope : IResolverScope + { + private readonly IServiceScope _scope; + public IDependencyResolver Resolver { get; } + public ServiceProviderScope(IServiceScope scope) + { + _scope = scope; + Resolver = new ServiceProviderDependencyResolver(scope.ServiceProvider); + } + + public void Dispose() + { + _scope?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderSetup.cs b/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderSetup.cs deleted file mode 100644 index 835d1ad98f3..00000000000 --- a/src/contrib/dependencyinjection/Akka.DependencyInjection/ServiceProviderSetup.cs +++ /dev/null @@ -1,40 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (C) 2009-2021 Lightbend Inc. -// Copyright (C) 2013-2021 .NET Foundation -// -//----------------------------------------------------------------------- - -using System; -using Akka.Actor; -using Akka.Actor.Setup; - -namespace Akka.DependencyInjection -{ - /// - /// Used to help bootstrap an with dependency injection (DI) - /// support via a reference. - /// - /// The will be used to access previously registered services - /// in the creation of actors and other pieces of infrastructure inside Akka.NET. - /// - /// The constructor is internal. Please use to create a new instance. - /// - public class ServiceProviderSetup : Setup - { - internal ServiceProviderSetup(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - } - - public IServiceProvider ServiceProvider { get; } - - public static ServiceProviderSetup Create(IServiceProvider provider) - { - if (provider == null) - throw new ArgumentNullException(nameof(provider)); - - return new ServiceProviderSetup(provider); - } - } -} diff --git a/src/examples/AspNetCore/Samples.Akka.AspNetCore/Actors/AkkaService.cs b/src/examples/AspNetCore/Samples.Akka.AspNetCore/Actors/AkkaService.cs index 98bb914016e..efb40de587d 100644 --- a/src/examples/AspNetCore/Samples.Akka.AspNetCore/Actors/AkkaService.cs +++ b/src/examples/AspNetCore/Samples.Akka.AspNetCore/Actors/AkkaService.cs @@ -18,7 +18,6 @@ using Microsoft.Extensions.Hosting; using Samples.Akka.AspNetCore.Messages; using Samples.Akka.AspNetCore.Services; -using ServiceProvider = Akka.DependencyInjection.ServiceProvider; namespace Samples.Akka.AspNetCore.Actors { @@ -41,14 +40,14 @@ public async Task StartAsync(CancellationToken cancellationToken) { var hocon = ConfigurationFactory.ParseString(await File.ReadAllTextAsync("app.conf", cancellationToken)); var bootstrap = BootstrapSetup.Create().WithConfig(hocon); - var di = ServiceProviderSetup.Create(_sp); + var di = DependencyResolverSetup.Create(_sp); var actorSystemSetup = bootstrap.And(di); _actorSystem = ActorSystem.Create("AspNetDemo", actorSystemSetup); // // // props created via IServiceProvider dependency injection - var hasherProps = ServiceProvider.For(_actorSystem).Props(); + var hasherProps = DependencyResolver.For(_actorSystem).Props(); RouterActor = _actorSystem.ActorOf(hasherProps.WithRouter(FromConfig.Instance), "hasher"); //