【问题标题】:Akka.NET and MVVMAkka.NET 和 MVVM
【发布时间】:2019-11-24 08:02:17
【问题描述】:

我正在尝试在我目前正在开发的新 WPF .NET Framework 应用程序中使用 Akka.NET。

大多数情况下,在应用程序中使用actors的过程看起来很容易解释,但是在应用程序视图级别实际使用actor输出时,我有点卡住了。

具体来说,关于如何在 actor 中处理接收和处理事件,似乎有两种选择。

  1. 使用公开的事件处理程序创建一个参与者。所以可能是这样的:

    public class DoActionActor : ReceiveActor
    {
        public event EventHandler<EventArgs> MessageReceived;
    
        private readonly ActorSelection _doActionRemoteActor;
    
        public DoActionActor(ActorSelection doActionRemoteActor)
        {
            this._doActionRemoteActor = doActionRemoteActor ?? throw new ArgumentNullException("doActionRemoteActor must be provided.");
    
            this.Receive<GetAllStuffRequest>(this.HandleGetAllStuffRequestReceived);
            this.Receive<GetAllStuffResponse>(this.HandleGetAllStuffResponseReceived);
        }
    
        public static Props Props(ActorSystem actorSystem, string doActionRemoteActorPath)
        {
           ActorSelection doActionRemoteActor = actorSystem.ActorSelection(doActionRemoteActorPath);
           return Akka.Actor.Props.Create(() => new DoActionActor(doActionRemoteActor));
        }
    
        private void HandleGetAllStuffResponseReceived(GetAllTablesResponse obj)
        { 
            this.MessageReceived?.Invoke(this, new EventArgs());
        }
        private void HandleGetAllStuffRequestReceived(GetAllTablesRequest obj)
        {
            this._doActionRemoteActor.Tell(obj, this.Sender);
        }
    }
    

所以基本上你可以创建你的视图并通过执行类似_doActionActor.Tell(new GetStuffRequest()); 的操作来调用任何调用,然后通过事件处理程序处理输出。这运作良好,但似乎打破了 Akka.NET 鼓励的“Actors 'everywhere' 模型”,我不确定这种方法的并发含义。

  1. 替代方法似乎是让我的 ViewModel 本身就是演员。所以基本上我有一些看起来像这样的东西。

    public abstract class BaseViewModel : ReceiveActor, IViewModel
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public abstract Props GetProps();
    
        protected void RaisePropertyChanged(PropertyChangedEventArgs eventArgs)
        {
            this.PropertyChanged?.Invoke(this, eventArgs);
        }
    }
    
    
    
    public class MainWindowViewModel : BaseViewModel
    {
        public MainWindowViewModel()
        {
            this.Receive<GetAllTablesResponse>(this.HandleGetAllTablesResponseReceived);
    
            ActorManager.Instance.Table.Tell(new GetAllTablesRequest(1), this.Self);
        }
    
        public override Props GetProps()
        {
            return Akka.Actor.Props.Create(() => new MainWindowViewModel());
        }
    
        private void HandleGetAllTablesResponseReceived(GetAllTablesResponse obj)
        {
    
        }
    }
    

这样我可以直接在actor本身(实际上是我的视图模型)中处理actor事件。

我在尝试这样做时遇到的问题是正确配置我的 Ioc (Castle Windsor) 以正确构建 Akka.NET 实例。

所以我有一些代码来创建看起来像这样的 Akka.NET 对象

        Classes.FromThisAssembly()
                .BasedOn<BaseViewModel>()
                .Configure(config => config.UsingFactoryMethod((kernel, componentModel, context) =>
                {
                    var props = Props.Create(context.RequestedType);
                    var result = ActorManager.Instance.System.ActorOf(props, context.RequestedType.Name);
                    return result;
                }))

这在实际创建IActorRef 的实例方面非常有效,但不幸的是我无法将演员引用转换回我需要的实际对象(在本例中为BaseViewModel)。

所以如果我尝试这样做return (BaseViewModel)result; 我会得到一个无效的强制转换异常。这显然是有道理的,因为我得到的是 IActorRef 对象而不是 BaseViewModel

所以最后我希望得到两个问题的答案。

  1. 在 MVVM 应用程序中处理 Akka.NET Actor 的最佳方式是什么,特别是在处理接收到的消息和处理显示输出时。

  2. 有没有办法正确配置我的 Ioc 系统以创建 IActorRef 实例并将其添加到系统但返回 BaseViewModel 的实际父actor对象具体实现的实例?

【问题讨论】:

    标签: c# akka castle-windsor akka.net akka-remote-actor


    【解决方案1】:

    以下是我正在使用的当前解决方案,希望有人可以提出更好的建议。

    基本上我已经放弃了让我的观点演员的尝试,目前决定使用一个接口在ViewModelActor之间进行通信。

    目前的解决方案是这样的:

    public class MainWindowViewModel : BaseViewModel, ITableResponseHandler
    {
        public void HandleResponse(IEnumerable<Entity> allEntities) { }
    }
    
    public interface ITableResponseHandler
    {
        void HandleResponse(IEnumerable<Entity> allEntities);
    }
    
    public class MyActor : ReceiveActor
    {
        public MyActor(ITableResponseHandler viewModel) 
        {
            this.Receive<GetAllEntitiesResponse>(this.HandleGetAllEntitiesResponseReceived);
        }
    
        private void HandleGetAllEntitiesResponseReceived(GetAllTablesResponse obj)
        {
            this._ViewModel.HandleTablesResponse(obj.Result);
        }
    
    }
    

    虽然我不觉得这很理想,但它基本上让我避免了尝试使我的视图模型本身成为演员同时充分地将演员与视图解耦的所有额外复杂性。

    我希望其他人也遇到过这个问题,并且可能能够提供一些见解,以便在 MVVM 应用程序中处理 Akka.NET 输出的更好解决方案。

    【讨论】:

    • 我没有使用Akka.NET 的经验,但是Actor 不能注入?有没有办法通过构造函数注入将所需的actor注入ViewModel?
    • 感谢您的意见。注入演员的问题在于,如果您采用这种方法,您显然是在创建一个单例,并且基本上订阅了演员现在从所有订阅者那里产生的所有事件。不是说你做不到,但我更喜欢每次观看有 1 个演员,从而限制演员需要处理的流量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    相关资源
    最近更新 更多