Akka.net DI - 如何通过DI注入两个演员?

时间:2015-08-31 04:12:35

标签: c# akka.net akka.net-cluster

我要做的是将两个演员(木乃伊演员和爸爸演员)传给小伙子演员。因为它是使用actor引用而不是actor的最佳实践,我使用IActorRef为mummy actor和daddy actor通过DI注入命名参数。但我得到了#m; mummyActor并不是唯一的"错误。知道怎么解决吗?

using System;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.DI.AutoFac;
using Akka.DI.Core;
using Autofac;
using Autofac.Core;


namespace Akka.DI.AutoFac.ExampleConsole {

    public class DaddyActor : ReceiveActor {
        public DaddyActor() {
            Receive<DoneEatingMessage>(m => {
                Console.WriteLine("Kid finished eating. So what? ~ Dad");
            });
        }
    }


    public class MummyActor : ReceiveActor {
        public MummyActor() {
            Receive<DoneEatingMessage>(m => {
                Console.WriteLine("Kid finished eating. Time to clean up! ~Mummy");
            });
        }
    }

    public class KidActor : ReceiveActor {

        private IService _service;

        private IActorRef _mummyActor;
        private IActorRef _daddyActor;

        public KidActor(IService service, IActorRef mummyActor, IActorRef daddyActor) {
            this._service = service;
            this._mummyActor = mummyActor;
            this._daddyActor = daddyActor;

            Receive<EatMessage>(m=>{
                var food = service.GetFood();
                Console.WriteLine("Kid eat this food {0}", food);
                _mummyActor.Tell(new DoneEatingMessage());
            });
        }


    }

    public class EatMessage{    }
    public class DoneEatingMessage { }

    public interface IService {
        string GetFood();
    }
    public class FoodService : IService {

        public string GetFood() {
            return "banana";
        }
    }
    class Program {
        static ActorSystem _actorSystem;
        static void Main(string[] args) {

            var builder = new Autofac.ContainerBuilder();
            builder.RegisterType<FoodService>().As<IService>();
            builder.RegisterType<MummyActor>().InstancePerDependency();
            builder.RegisterType<DaddyActor>().InstancePerDependency();

            builder.Register(c => _actorSystem.ActorOf(_actorSystem.DI().Props<DaddyActor>(), "daddyActor"))
                .Named<IActorRef>("daddyActorRef")
                .AsSelf();

            builder.Register(c => _actorSystem.ActorOf(_actorSystem.DI().Props<MummyActor>(), "mummyActor"))
                .Named<IActorRef>("mummyActorRef")
                .AsSelf();



            builder.RegisterType<KidActor>()
                .WithParameter(
                  new ResolvedParameter(
                       (pi, ctx) => pi.ParameterType == typeof(MummyActor),
                       (pi, ctx) => ctx.ResolveNamed<IActorRef>("mummyActorRef")
                    )
                )
                .WithParameter(
                  new ResolvedParameter(
                       (pi, ctx) => pi.ParameterType == typeof(DaddyActor),
                       (pi, ctx) => ctx.ResolveNamed<IActorRef>("daddyActorRef")
                    )
                )
                .InstancePerDependency();

            var container = builder.Build();

            _actorSystem = ActorSystem.Create("ActorDISystem");
            var propsResolver = new AutoFacDependencyResolver(container, _actorSystem);


            var kidActorProps = _actorSystem.DI().Props<KidActor>();
            var kidActor = _actorSystem.ActorOf(kidActorProps, "kidActor");

            kidActor.Tell(new EatMessage());

            Console.WriteLine("Holah");
            Console.ReadLine();
        }
    }
}

3 个答案:

答案 0 :(得分:4)

问题是MummyActor和DaddyActor类型不是IActorRef的实例。所以在创建KidActor时不能使用这些类型。

我对AutoFac不太熟悉,但我能够让它像这样工作:

builder.RegisterType<KidActor>()
.WithParameter(
  new ResolvedParameter(
       (pi, ctx) => pi.Name == "mummyActor",
       (pi, ctx) => ctx.ResolveNamed<IActorRef>("mummyActorRef")
    )
)
.WithParameter(
  new ResolvedParameter(
       (pi, ctx) => pi.Name == "daddyActor",
       (pi, ctx) => ctx.ResolveNamed<IActorRef>("daddyActorRef")
    )
)
.InstancePerDependency();

我使用参数的名称进行检查。但我认为这种解决方案非常危险,特别是如果重命名参数。

您可以做的另一件事是将这些实例的创建委托给具有特定方法的服务/工厂,并通过DI注入此服务。

以下是我在进行一些重构后得到的结果:

public class DaddyActor : ReceiveActor
{
    public DaddyActor()
    {
        Receive<DoneEatingMessage>(m =>
        {
            Console.WriteLine("Kid finished eating. So what? ~ Dad");
        });
    }
}
public class MummyActor : ReceiveActor
{
    public MummyActor()
    {
        Receive<DoneEatingMessage>(m =>
        {
            Console.WriteLine("Kid finished eating. Time to clean up! ~Mummy");
        });
    }
}
public class KidActor : ReceiveActor
{
    private IService _service;
    private IActorRef _mummyActor;
    private IActorRef _daddyActor;

    public KidActor(IService service, IParentFactory parentFactory)
    {
        this._service = service;
        this._mummyActor = parentFactory.CreateMother(Context.System);
        this._daddyActor = parentFactory.CreateFather(Context.System);

        Receive<EatMessage>(m =>
        {
            var food = service.GetFood();
            Console.WriteLine("Kid eat this food {0}", food);
            _mummyActor.Tell(new DoneEatingMessage());
            _daddyActor.Tell(new DoneEatingMessage());
        });
    }
}
public class EatMessage { }
public class DoneEatingMessage { }

public interface IService
{
    string GetFood();
}
public class FoodService : IService
{
    public string GetFood()
    {
        return "banana";
    }
}

public interface IParentFactory
{
    IActorRef CreateMother(ActorSystem actorSystem);
    IActorRef CreateFather(ActorSystem actorSystem);
}
public class ParentFactory : IParentFactory
{
    public IActorRef CreateFather(ActorSystem actorSystem)
    {
        return actorSystem.ActorOf(actorSystem.DI().Props<DaddyActor>(), "daddyActor");
    }

    public IActorRef CreateMother(ActorSystem actorSystem)
    {
        return actorSystem.ActorOf(actorSystem.DI().Props<MummyActor>(), "mummyActor");
    }
}

class Program
{
    static ActorSystem _actorSystem;
    static void Main(string[] args)
    {
        var builder = new Autofac.ContainerBuilder();
        builder.RegisterType<FoodService>().As<IService>();
        builder.RegisterType<ParentFactory>().As<IParentFactory>();
        builder.RegisterType<MummyActor>().InstancePerDependency();
        builder.RegisterType<DaddyActor>().InstancePerDependency();
        builder.RegisterType<KidActor>().InstancePerDependency();

        var container = builder.Build();

        _actorSystem = ActorSystem.Create("ActorDISystem");
        var propsResolver = new AutoFacDependencyResolver(container, _actorSystem);

        var kidActorProps = _actorSystem.DI().Props<KidActor>();
        var kidActor = _actorSystem.ActorOf(kidActorProps, "kidActor");

        kidActor.Tell(new EatMessage());

        Console.WriteLine("Holah");
        Console.ReadLine();
        _actorSystem.AwaitTermination();
    }
}

我希望它会对你有所帮助。

答案 1 :(得分:1)

另一种解决方案是注入Mummy和Daddy的路径,并使用Kid内部的Context.ActorSelection在系统中查找它们。这在远程/群集情况下以及在您具有循环参考链的情况下更适合。

答案 2 :(得分:0)

每个小伙子演员正在制作木乃伊和爸爸演员。木乃伊和爸爸演员要么必须是唯一的名字,要么注册为单身人士。