Synchronizing RX .NET Subscribe by CorrelationId - c#

I'm trying to write something similar to Sagas using RX.NET. I've came across a simple issue and I don't know what the best way is to sychronize states by correlation id. I have simple EventAggregator which listens for some events and it can be notified from multiple threads so I cannot assume that subscribe is always called on the same thread so there is a possibility that the first notification will update the state and in the meantime another notification will receive old state and work with it so I have to synchronize it. I have simplified my scenario to something like below. I could lock the whole subscribe by some object id dependent but it doesn't seem right. What is RX way of doing it?
public interface IEventAggregator
{
IObservable<T> GetEvent<T>() where T : Event;
}
public class EventAggregator : IEventAggregator
{
Subject<Event> _sub = new Subject<Event>();
public IObservable<T> GetEvent<T>() where T : Event
{
return _sub.OfType<T>();
}
public void Notify<T>(T ev) where T : Event
{
_sub.OnNext(ev);
}
}
public class Event
{
public string CorrelationId { get; set; }
}
public class State
{
public int SomeValue { get; set; }
}
public interface IStateRepository
{
State Get(string id);
}
public class ProcessManager
{
private readonly IStateRepository _stateRepository;
private readonly IEventAggregator _eventAggregator;
public ProcessManager(IStateRepository stateRepository, IEventAggregator eventAggregator)
{
_stateRepository = stateRepository;
_eventAggregator = eventAggregator;
eventAggregator.GetEvent<Event>()
.Select(x => _stateRepository.Get(x.CorrelationId))
.Subscribe(state =>
{
// -do something with state like write or read;
// - state should be unique per correlation id.
// - this block should be synchronized.
});
}
}

Related

Activation/Deactivation with ObservableAsPropertyHelper

What is the proper usage of Activation/Deactivation in conjunction with ObservableAsPropertyHelper? Given a view and viewmodel that reflects long lived (hot) observables, the subscription would need to be disposed when the view and viewmodel is unloaded. However ObservableAsPropertyHelper, which is recommended to be readonly is assigned in the constructor of the viewmodel, and cannot be part of the activation/deactivation lifecycle. What is the right way to handle these kind of situations?
public interface ILongLivedObject
{
IObservable<bool> Status { get; }
}
public class TestViewModel : ReactiveObject
{
private readonly ObservableAsPropertyHelper<bool> _status;
public bool Status => _status.Value;
public TestViewModel(ILongLivedObject obj)
{
_status = obj.Status.ToProperty(this, vm => vm.Status); //how is the subscription disposed?
}
}
This also gets me into a corner when trying to add commands that depends on this status. In my application, a common use case is to have some hardware that is on some specific status (e.g. IsOpen) and allow commands when it is true.
Without knowing better, this is what I am trying to do:
public class TestViewModel : ReactiveObject
{
private readonly ObservableAsPropertyHelper<bool> _status;
public bool Status => _status.Value;
public ReactiveCommand<Unit, Unit> DoStuff {get;}
public TestViewModel(ILongLivedObject obj)
{
_status = obj.Status.ToProperty(this, vm => vm.Status); //how is the subscription disposed?
DoStuff = ReactiveCommand.CreateFromTask(....., this.WhenAnyValue(this, x => x.Status);
}
}
If I try to move the _status creation into this.WhenActivated, the app will crash as the command is trying to get the value of status before it is created. Am I supposed to (re)create the comand during activation? This seems wrong and pretty costly?
So far, it seems better to have a regular Status property with a protected setter and make a regular subscription in this.WhenActivated - but this is what the handbook tells to avoid for "readonly" properties.
So one thing to be aware of in Reactive programming, disposing often means "unsubscribe".
You often don't need to unsubscribe since the garbage collector will take care of it for you, providing you create ObservableAsPropertyHelper (abbreviated as OAPH) only with observables generated from the current ViewModel.
In your case however, your observable/object, is related to a object outside the current ViewModel. The OAPH itself is a Disposable object.
So you can use ISupportsActivation (shortly going to have a replacement of IActivableViewModel) and pass your OAPH into it's Disposable property.
public class TestViewModel : ReactiveObject, ISupportsActivation
{
private readonly ObservableAsPropertyHelper<bool> _status;
public bool Status => _status.Value;
public ViewModelActivator Activator { get; } = new ViewModelActivator();
public TestViewModel(ILongLivedObject obj)
{
_status = obj.Status.ToProperty(this, vm => vm.Status);
this.WhenActivated(disposables =>
{
disposables(_status);
}
}
}
The disposables parameter passed into the WhenActivated lambda is a Func that takes a IDisposable
In the view, make sure you derive off IActivatable (soon to be renamed IActivatableView) and use WhenActivated in the constructor of the view as well.

Property Change Event for C# ..Parent child interaction

I have a class Step that stores a list of Tasks :
public class Step
{
public string StepName { get; set; }
private string _stepStatus
public List<Task> Tasks { get; set; }
public string StepStatus
{
get
{
return _stepStatus;
}
set
{
_stepStatus = value;
}
}
public Step(String name)
{
StepName = name;
Tasks = new List<Task>();
}
I have a class of Task :
public class Task
{
public string TaskName { get; set; }
private string _taskStatus
public string TaskStatus
{
get
{
return _taskStatus;
}
set
{
// raise an event here
_taskStatus = value;
}
}
public Task(String name)
{
TaskName = name;
}
Whenever an individual updates a Task , I want to raise an event . this event should be caught by the parent i.e Step .. Step should check the status of all the tasks .
If all tasks' status are New , then Step status should be automatically set to New .
If all tasks' status are Finished , then Step status should be automatically set to Finished.
If even on of the task's status is In Progress , the Step Status should be set to In Progress.
I shall call this method TripleLogic , say.
I can do the logic for the above three since this is logical. I am not sure how to raise an event from Task Status setter and ensure that Step class object picks it up since I am new to C#. If someone could help me with this event raising part with a small sample code , and also show me how I cna get my parent Step object to capture this event and call TripleLogic at that instance.
I looked at INotifyPropertyChanged but am not sure how to implement.
Any other code design related pointers will be helpful.
First suggestion is not not expose your Tasks property on the Step class so that consumers are not able to modify the collection whenever/however they want. Instead add a method called AddTask(Task t) to Step and in there you can set up your event handling.
The Task class should expose an event, perhaps called StatusChanged. When the setter on the TaskStatus property is called, fire that event (after checking to ensure there are listeners). This event's arguments should include the updated status and the task's name. If you have a finite set of statuses, I'd suggest defining an enum for them, instead of relying on strings.
Example:
public class Task
{
public event EventHandler<TaskStatusEventArgs> StatusChanged;
//...
}
public enum TaskStatus
{
New,
InProgress,
Done
}
public class TaskStatusEventArgs: EventArgs
{
public string TaskName { get; private set; }
public TaskStatus Status { get; private set; }
public TaskStatusEventArgs(string taskName, TaskStatus status)
{
TaskName = taskName;
Status = status;
}
}
Back in Step and the AddTask() method, subscribe to the Task's StatusChanged event and keep track of the number of tasks in the Step. In the handler for the StatusChanged event, you can then grab the task's new status and do whatever logic you need in your TripleLogic() method.
Example:
public class Step
{
List<Task> tasks;
public void AddTask(Task t)
{
t.StatusChanged += HandleStatusChanged;
}
private void HandleStatusChanged(object sender, TaskStatusEventArgs args)
{
string taskName = args.TaskName;
TaskStatus status = args.Status;
TripleLogic(taskName, status);
}
}
Given that you've mentioned you are new to C#, perhaps go through the MSDN guide for events, specifically the sections on subscribing and publishing. The publishing section mentions the generic EventHandler<TEventArgs> delegate, I highly suggest using that method.
Your question is vague and large-enough that, when coupled with your lack of experience in the language, this may take you a while to get through.

WPF share string between 2 viewmodels

I'm a newbie in this WPF world, I have the following situation:
I am developing a multimedia-related application using VLC and the Caliburn.Micro, I have encountered a problem where I need the variable TotalTime from the MainViewModel to be shared with the TextBox on the SettingsViewModel.
This variable happens to change every second, so it has to be notified every second.
MainViewModel -> string TotalTime
SettingsViewModel -> TextBox Time
I have tried to do it with events, but I haven't succeeded.
If you nest the SettingsViewModel in the MainViewModel as a property (say Settings), you can bind an UI element to it like this:
Text = "{Binding Path=Settings.TotalTime}"
if the View's DataContext is set to an instance of the MainViewModel
In general, the solution to this problem is a singleton messenger that both view-models have injected into them on creation (usually from an IoC container). In your scenario, SettingsViewModel would subscribe to messages of a particular type, say TotalTimeChangedMessage, and MainViewModel would send messages of that type whenever TotalTime changed. The message simply contains the current value of TotalTime, e.g.:
public sealed class TotalTimeChangedMessage
{
public string totalTime;
public TotalTimeChangedMessage(string totalTime)
{
this.totalTime = totalTime;
}
public string TotalTime
{
get { return this.totalTime; }
}
}
Caliburn.Micro contains an event aggregator that you can use to pass messages in this fashion between view-models. Your MainViewModel would send the message like this:
public class MainViewModel
{
private readonly IEventAggregator _eventAggregator;
public MainViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
public string TotalTime
{
set
{
this.totalTime = value;
_eventAggregator.Publish(new TotalTimeChangedMessage(this.totalTime));
}
}
}
..and your SettingsViewModel would handle it like this:
public class SettingsViewModel: IHandle<TotalTimeChangedMessage>
{
private readonly IEventAggregator eventAggregator;
public SettingsViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
this.eventAggregator.Subscribe(this);
}
public void Handle(TotalTimeChangedMessage message)
{
// Use message.TotalTime as necessary
}
}

Using IObservable<T> to keep track of current state

Suppose I have an object that observes an IObservable so that it's always aware of the current state of some external source. Internally my object has a method that uses that external value as part of the operation:
public class MyObject
{
public MyObject(IObservable<T> externalSource) { ... }
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
What's the idomatic 'reactive' way of using IObservable for 'tracking current state' instead of 'responding to stream of events'.
Idea #1 is to just monitor the observable and write down values as they come in.
public class MyObject
{
private T CurrentT;
public MyObject(IObservable<T> externalSource)
{
externalSource.Subscribe((t) => { CurrentT = t; });
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
And that's fine, but keeping track of the state in a class member seems very un-reactive-y.
Idea #2 is to use a BehaviorSubject
public class MyObject
{
private readonly BehaviorSubject<T> bs;
public MyObject(BehvaiorSubject<T> externalSource)
{
this.bs = externalSource
}
public void DoSomething()
{
DoSomethingWith(bs.Value);
}
}
But using subjects directly seems to be frowned upon. But at least in this case I have the ability to use a readonly field to store the behaviorsubject.
The BehaviorSubject (or ReplaySubject) does seem like it was made for this purpose, but is there some other better way here? And if I should use the subject, would it make more sense to take the subject as an injected parameter, or take the original observable and build the subject locally in the constructor?
(by the way I'm aware about the need to deal with the 1st value if the source observable hasn't fired yet. Don't get hung up on that, that's not what I'm asking about)
I'd go with a generic solution utilizing the ReactiveUI library. RUI has a standard way of mapping IObservable<T> to an INotifyPropertyChanged stateful property.
public class ObservableToINPCObject<T> : ReactiveObject, IDisposable
{
ObservableAsPropertyHelper<T> _ValueHelper;
public T Value {
get { return _ValueHelper.Value; }
}
public ObservableToINPCObject(IObservable<T> source, T initial = default(T))
{
_ValueHelper = source.ToProperty(this, p=>p.Value, initial);
}
public Dispose(){
_ValueHelper.Dispose();
}
}
ValueHelper is contains both the current state of the observable and automatically triggers the correct INPC notification when the state changes. That's quite a bit of boiler plate handled for you.
and an extension method
public static class ObservableToINPCObject {
public static ObservableToINPCObject<T> ToINPC<T>
( this IObservable<T> source, T init = default(T) )
{
return new ObservableToINPCObject(source, init);
}
}
now given an
IObservable<int> observable;
you can do
var obj = observable.ToINPC(10);
and to get the latest value
Console.WriteLine(obj.Value);
also given that Value is an INPC supporting property you can use it in databinding. I use ToProperty all the time for exposing my observables as properties for WPF databinding.
To be Rx-ish I'd suggest avoiding the second option and go with your first, but modified in one of two ways.
Either (1) make your class disposable so that you can cleanly close off the subscription to the observables or (2) make a method that lets you clean up individual observables.
(1)
public class MyObject : IDisposable
{
private T CurrentT;
private IDisposable Subscription;
public MyObject(IObservable<T> externalSource)
{
Subscription = externalSource
.Subscribe((t) => { CurrentT = t; });
}
public void Dispose()
{
Subscription.Dispose();
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
(2)
public class MyObject
{
private T CurrentT;
public IDisposable Observe(IObservable<T> externalSource)
{
return externalSource
.Subscribe((t) => { CurrentT = t; });
}
public void DoSomething()
{
DoSomethingWith(CurrentT);
}
}
Both allow proper clean-up and both don't use a subject.

Command object pattern wannabe or the real thing?

The command object pattern is one that I still haven't been able to truly grasp and I found an implementation in the code I'm currently working on so I studied it long and hard to see if I could finally get it with a real world example. The problem is that I am sure this is not properly implemented and it is just an attempt by someone who just read about it and thought it made sense here.
Allow me to show it to you (for confidentiality reasons it will be greatly simplified but I'll do my best to show the main concepts):
public class CommandOne
{
public CommandOne(Manager manager, MyForm form)
{
m_manager = manager;
m_form = form;
}
public void Execute()
{
m_manager.CommandOne(m_form);
}
}
public class CommandTwo
{
public CommandTwo(Manager manager, MyForm form)
{
m_manager = manager;
m_form = form;
}
public void Execute()
{
m_manager.CommandTwo(m_form);
}
}
The first thing that strikes me as odd is that these two classes are not inheriting from any abstract class nor implementing a common interface.
The code that uses these commands is as follows:
public class MyForm : System.Windows.Forms.Form
{
public MyForm(Manager manager)
{
m_manager = manager;
}
private void SomeMethod()
{
....
var cmd = new CommandOne(manager, this);
cmd.Execute();
...
}
private void OtherMethod()
{
....
var cmd = new CommandTwo(manager, this);
cmd.Execute();
...
}
}
So the way I see it, this form is absolutely coupled to all the classes involved except the manager which is being injected to it through its constructors. So with this code I really don't see any benefit of creating the "command" classes which basically are just delegating the call to the manager's methods since the form is instantiating them when it needs them and calling the execute method right afterwards.
So could someone please explain what pieces, if any, is this implementation missing to truly be a command object pattern and, although it might be too subjective, what would be the benefit to implement it in this case?
Thank you.
Based on what you're showing here it looks like the benefit of the command pattern is lost. There are a few reasons you might want to use the command pattern in the context of a WinForms app.
You want to execute a command later
public interface ICommand
{
void Execute();
}
Keep a history of executed commands so they can be undone by the user
public interface ICommand
{
void Execute();
void Undo();
}
Check permissions to see if the current user has rights to execute the command. For example, maybe you have a RefundCustomerCommand and not all customer service agents have the right to issue a refund so you want to disable a button on the form.
public interface ICommand
{
void Execute();
bool CanExecute { get; }
}
You can also roll multiple commands together in a composite like this:
public class CompositeCommand : ICommand
{
private readonly List<ICommand> commands;
public CompositeCommand()
{
commands = new List<ICommand>();
}
public void Add(ICommand command)
{
commands.Add(command);
}
public void Execute()
{
foreach (var command in commands) command.Execute();
}
}
The command pattern also works nicely with the decorator. You can easily add additional cross-cutting behavior to your commands like retry logic:
public class RetryOnTimeout : ICommand
{
private readonly ICommand command;
private int numberOfRetries;
public RetryOnTimeout(ICommand command, int numberOfRetries)
{
this.command = command;
this.numberOfRetries = numberOfRetries;
}
public void Execute()
{
try
{
command.Execute();
}
catch (TimeoutException)
{
if (++numberOfRetries > 3)
throw;
Execute();
}
}
}

Categories