Skip to content

Instantly share code, notes, and snippets.

@seesharper
Created October 6, 2015 15:03
Show Gist options
  • Select an option

  • Save seesharper/ee6c8d3aca9d9723bda3 to your computer and use it in GitHub Desktop.

Select an option

Save seesharper/ee6c8d3aca9d9723bda3 to your computer and use it in GitHub Desktop.
An AKKA dependency resolver
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Runtime.CompilerServices;
using Akka.Actor;
using Akka.DI.Core;
using LightInject;
namespace LightInject.Akka
{
/// <summary>
/// Provides services to the <see cref="Akka.Actor.ActorSystem "/> extension system
/// used to create actors using the LightInject IoC container.
/// </summary>
public class LightInjectDependencyResolver : IDependencyResolver
{
private readonly IServiceContainer m_container;
private readonly ConcurrentDictionary<string, Type> m_typeCache;
private readonly ActorSystem m_system;
private readonly ConditionalWeakTable<ActorBase, LightInject.Scope> m_references;
/// <summary>
/// Initializes a new instance of the <see cref="LightInjectDependencyResolver"/> class.
/// </summary>
/// <param name="container">The container used to resolve references</param>
/// <param name="system">The actor system to plug into</param>
/// <exception cref="ArgumentNullException">
/// Either the <paramref name="container"/> or the <paramref name="system"/> was null.
/// </exception>
public LightInjectDependencyResolver(IServiceContainer container, ActorSystem system)
{
if (system == null) throw new ArgumentNullException("system");
if (container == null) throw new ArgumentNullException("container");
this.m_container = container;
m_typeCache = new ConcurrentDictionary<string, Type>(StringComparer.InvariantCultureIgnoreCase);
this.m_system = system;
this.m_system.AddDependencyResolver(this);
this.m_references = new ConditionalWeakTable<ActorBase, LightInject.Scope>();
}
/// <summary>
/// Retrieves an actor's type with the specified name
/// </summary>
/// <param name="actorName">The name of the actor to retrieve</param>
/// <returns>The type with the specified actor name</returns>
public Type GetType(string actorName)
{
m_typeCache.TryAdd(actorName,
actorName.GetTypeValue() ??
m_container.
AvailableServices.
Where(registration => registration.ServiceName.Equals(actorName, StringComparison.InvariantCultureIgnoreCase)).
Select(registration => registration.ImplementingType).
FirstOrDefault());
return m_typeCache[actorName];
}
/// <summary>
/// Creates a delegate factory used to create actors based on their type
/// </summary>
/// <param name="actorType">The type of actor that the factory builds</param>
/// <returns>A delegate factory used to create actors</returns>
public Func<ActorBase> CreateActorFactory(Type actorType)
{
return () =>
{
var scope = m_container.BeginScope();
var actor = (ActorBase)m_container.GetInstance(actorType);
m_references.Add(actor, scope);
return actor;
};
}
/// <summary>
/// Used to register the configuration for an actor of the specified type <typeparam name="TActor"/>
/// </summary>
/// <typeparam name="TActor">The type of actor the configuration is based</typeparam>
/// <returns>The configuration object for the given actor type</returns>
public Props Create<TActor>() where TActor : ActorBase
{
return m_system.GetExtension<DIExt>().Props(typeof(TActor));
}
/// <summary>
/// Signals the DI container to release it's reference to the actor.
/// <see href="http://www.amazon.com/Dependency-Injection-NET-Mark-Seemann/dp/1935182501/ref=sr_1_1?ie=UTF8&qid=1425861096&sr=8-1&keywords=mark+seemann">HERE</see>
/// </summary>
/// <param name="actor">The actor to remove from the container</param>
public void Release(ActorBase actor)
{
LightInject.Scope scope;
if (m_references.TryGetValue(actor, out scope))
{
scope.Dispose();
m_references.Remove(actor);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment