/
DependencyResolver.cs
125 lines (115 loc) · 6.11 KB
/
DependencyResolver.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//-----------------------------------------------------------------------
// <copyright file="ServiceProvider.cs" company="Akka.NET Project">
// Copyright (C) 2009-2021 Lightbend Inc. <http://www.lightbend.com>
// Copyright (C) 2013-2021 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------
using System;
using Akka.Actor;
using Akka.Configuration;
using Akka.Event;
using Microsoft.Extensions.DependencyInjection;
namespace Akka.DependencyInjection
{
/// <summary>
/// Provides users with immediate access to the <see cref="IDependencyResolver"/> bound to
/// this <see cref="ActorSystem"/>, if any.
/// </summary>
public sealed class DependencyResolver : IExtension
{
public DependencyResolver(IDependencyResolver resolver)
{
Resolver = resolver;
}
/// <summary>
/// The globally scoped <see cref="IDependencyResolver"/>.
/// </summary>
/// <remarks>
/// Per https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines - please use
/// the appropriate <see cref="IServiceScope"/> 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.
/// </remarks>
public IDependencyResolver Resolver { get; }
public static DependencyResolver For(ActorSystem actorSystem)
{
return actorSystem.WithExtension<DependencyResolver, DependencyResolverExtension>();
}
/// <summary>
/// Uses a delegate to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection
/// and others are not.
/// </summary>
/// <remarks>
/// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU.
/// </remarks>
/// <typeparam name="T">The type of actor to instantiate.</typeparam>
/// <param name="args">Optional. Any constructor arguments that will be passed into the actor's constructor directly without being resolved by DI first.</param>
/// <returns>A new <see cref="Akka.Actor.Props"/> instance which uses DI internally.</returns>
public Props Props<T>(params object[] args) where T : ActorBase
{
return Resolver.Props<T>(args);
}
/// <summary>
/// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection
/// and others are not.
/// </summary>
/// <remarks>
/// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU.
/// </remarks>
/// <typeparam name="T">The type of actor to instantiate.</typeparam>
/// <returns>A new <see cref="Akka.Actor.Props"/> instance which uses DI internally.</returns>
public Props Props<T>() where T : ActorBase
{
return Resolver.Props<T>();
}
/// <summary>
/// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection
/// and others are not.
/// </summary>
/// <remarks>
/// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU.
/// </remarks>
/// <param name="type">The type of actor to instantiate.</param>
/// <returns>A new <see cref="Akka.Actor.Props"/> instance which uses DI internally.</returns>
public Props Props(Type type)
{
return Resolver.Props(type);
}
/// <summary>
/// Used to dynamically instantiate an actor where some of the constructor arguments are populated via dependency injection
/// and others are not.
/// </summary>
/// <remarks>
/// YOU ARE RESPONSIBLE FOR MANAGING THE LIFECYCLE OF YOUR OWN DEPENDENCIES. AKKA.NET WILL NOT ATTEMPT TO DO IT FOR YOU.
/// </remarks>
/// <param name="type">The type of actor to instantiate.</param>
/// <param name="args">Optional. Any constructor arguments that will be passed into the actor's constructor directly without being resolved by DI first.</param>
/// <returns>A new <see cref="Akka.Actor.Props"/> instance which uses DI internally.</returns>
public Props Props(Type type, params object[] args)
{
return Resolver.Props(type, args);
}
}
/// <summary>
/// INTERNAL API
/// </summary>
public sealed class DependencyResolverExtension : ExtensionIdProvider<DependencyResolver>
{
public override DependencyResolver CreateExtension(ExtendedActorSystem system)
{
var setup = system.Settings.Setup.Get<DependencyResolverSetup>();
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;
}
}
}