Current filter:
                                You should refresh the page.
                                  • The example shows how to use Actor Model framework as a Model Layer in the MVVM applications.

                                    Actor Model is a high level abstraction for writing concurrent, distributed and loose coupling code.
                                    There are 2 popular actor frameworks: Akka.NET (direct Scala to .NET porting)  and Proto.Actor.
                                    Both frameworks are production ready, in the example I used Proto.Actor (but it's documentation is not complete at the moment).
                                    Form my point of view the Akka.NET is over engineered and has some performance issues (Remote actions).

                                    An actor is a very lightweight object (~300 bytes, you can create million actors) which can sends and receives immutable (lock free) messages.
                                    Messages are passed to the actor's MailBox and processed asynchronously with minimal overhead (30-50 millions messages in a second is a typical rate).

                                    Actor API:

                                    1. Tell method is a non-blocking, fire-and-forget method for sending a message to an actor
                                    2. Request method is very similar to Tell, but it also includes the sender PID so that the receiving actor can send a reply.
                                         actor.Request(message, context.Self);
                                    3. RequestAsync<T> method is identical to Request but it returns an awaitable Task that will complete when the actor has sent a reply of type T.
                                        var reply = await actor.RequestAsync<string>(message);

                                    Message examples:

                                    public class NewOrder { public int CustomerId { get; } public NewOrder(int customerId) { CustomerId = customerId; } } public class CreatedOrder { public int OrderId { get; } public DateTime CreatedDate { get; } public int CustomerId { get; } public CreatedOrder(int orderId, DateTime createdDate, int customerId) { OrderId = orderId; CreatedDate = createdDate; CustomerId = customerId; } }

                                    Actor examples:

                                    public class OrderActor : IActor { private int orderId; // reference to other actors private readonly PID _orderListActor; private readonly PID _dataActor; public OrderActor(PID orderList, PID data) { _orderListActor = orderList; _dataActor = data; } public Task ReceiveAsync(IContext context) { switch (context.Message) { case NewOrder newOrder: var order = new CreatedOrder(orderId++, DateTime.Now, newOrder.CustomerId); _dataActor.Tell(order); _orderListActor.Tell(order); break; } return Actor.Done; } }

                                    Some evident advantages we get from the Actors Model for the MVVM approach:

                                    1. A ViewModel turns into a simple bindable properties holder and command wrapper:
                                    public class MainVM : AbstractViewModel { public virtual GridItem Row { get; set; } public virtual string Series { get; set; } public virtual double Value { get; set; } // just for testing purpose public INavigationService NavigationService; // ctor public MainVM() => ActorRef = IoC.ActorCatalog.Create("main", () => new MainActor(this)); // command wrapper public void SomeAction() => ActorRef.Tell(new ActionMessage(par1, par2)); // NavigationService registration protected override void LoadedCore() => ActorRef.Tell(NavigationService ?? this.GetService<INavigationService>()); }

                                    As a result we have an anemic (minimal code and logic) ViewModel, which can be easily tested (but it seems there is nothing to test there).

                                    2. We don't need any ViewModel reference, so just set it in XAML:
                                    DataContext="{dxmvvm:ViewModelSource Type={x:Type viewModels:MainVM}}"

                                    It's much easier to establish actors relationship than ViewModels relationship.

                                    3. A ViewModel Actor (Model) has full access to ViewModel's properties and can interact with other actors:
                                    public class MainActor : AbstractActor<MainVM>, IActor { public INavigationService NavigationService { get; private set; } public MainActor(MainVM viewModel) => ViewModel = viewModel; public Task ReceiveAsync(IContext context) { switch (context.Message) { case INavigationService navigationService: NavigationService = navigationService; IoC.ActorCatalog.Tell("ribbon", "View1"); break; case Navigate navigate: IoC.ServiceFacade.Notify("Navigating...", $"Navigate to {navigate.View}"); NavigationService.Navigate(navigate.View); break; case GridItem row: ViewModel.Row = row; IoC.ServiceFacade.Msg("Row is selected", $"Row: {row}", MessageBoxButton.OK, MessageBoxImage.Information); break; case string series: ViewModel.Series = series; IoC.ServiceFacade.Msg("Series is selected", $"Series: {series}", MessageBoxButton.OK, MessageBoxImage.Information); break; case double value: ViewModel.Value = value; IoC.ServiceFacade.Msg("Value is selected", $"Value: {value}", MessageBoxButton.OK, MessageBoxImage.Information); break; } return Actor.Done; } }
                                    4. The Integration testing is very simple:
                                    [Fact] public void MainVmAndViewModelInteraction() { _catalog.Create("database", () => new DataBaseActor(new DataService())); var main = new MainVM(); var viewModel = ViewModelSource.Create(() => new ViewModel1()); // actors are created asynchronously Thread.Sleep(50); var row = viewModel.Items.FirstOrDefault(t => t.Id == 10); // property changed handler sends the new value to the ViewModel1 actor, which forwards it to the MainVM actor viewModel.Current = row; // messages are processed asynchronously Thread.Sleep(50); Assert.Same(row, main.Row); }

                                    The actors' paradigm is very different from the usual OOP paradigm, instead of classes and methods you should think in terms of actors and messages.
                                    So it will take some time to get used to it, but it's worth it.

                                0 Solutions

                                Creation Date Importance Sort by