Observable subclass with public Notify<T>(T value) method - c#

Is there a subclass of the Observable<T> class that exposes access to Notify<T>(T value) method (or access Notifier, extension method) so that we can call observable.Notify(t) at hoc resulting all subscriptions being notified (OnNext invoked on the same thread).
I am not interested in FromEventPattern.

The ISubject<T> interface inherits both IObservable<T> and IObserver<T>.
var subject = new Subject<string>();
subject.Subscribe(text => Console.WriteLine(text));
subject.OnNext("Hello");
subject.OnNext("World!");
IObserver<T>.OnNext is essentially your Notify method.
More reading:
Using Subjects (MSDN)
Subject<T> (Introduction to Rx)

You certainly can use Subject<string> to provide an object that is an observer (i.e. you can call .OnNext(string)) and is an observable that can be subscribed to.
The only downside is that any code with access to your Subject<string> can also call .OnCompleted() or .OnError(...) and break your subscribers' code.
The other alternative is to do this:
Action<string> notify = null;
var observable = Observable.FromEvent<string>(h => notify += h, h => notify -= h);
var subscription = observable.Subscribe(x => Console.WriteLine(x));
notify("Hello");
You now have a simple Action<string> delegate that you can call to push a value and just so long as you keep the subscription alive clients can't kill your program with rogue calls to .OnCompleted() or .OnError(...).

Related

Invoking an initial request before starting to observe changes with observables

I have a (classic) SignalR hub which returns the state of some value, with an additional client callback contract that sends updates to the clients. What I'm basically trying to create on the client side (C#) is an observable stream which invokes a task when the first observer connects, and then starts further listening to the changes on the callback contract.
Server contracts (pseudo):
interface IMyHub
Task<int> GetInitialInt();
interface IMyHubClient
void SendFurtherInts(int value);
Client proxy:
var client = hubConnection.CreateObservableHubProxy<IMyHub, IMyHubClient>();
I now had imagined something like this:
public IObservable<int> Value { get; }
var initialData = Observable.FromAsync(async () =>
await _client.CallAsync(client => client.GetInitialInt));
var stream = _client.Observe(client => client.SendFurtherInts)
.StartWith(initialData)
.Publish()
.RefCount(1);
stream.Connect();
Value = stream.AsObservable();
StartWith() however expects an enumeration of existing values, not a single value or a stream. .Prepend() also doesn't seem to work with streams. I could technically invoke the task first, and then create the stream, but that's neither really functional nor does it fit my needs (invoke when the first observer connects).
What would be the proper way to solve this?

Why does Buffer from my Observable not receive events?

I have tried several ways but failing to get my subscription method called:
Method 1:
var buffer = new List<Kpi>();
buffer.ToObservable().Buffer(TimeSpan.FromMinutes(1), 5).Subscribe(
async kpis =>
{
await _retry.ExecuteAsync(() => Process(kpis.ToList())).ConfigureAwait(false);
});
Then buffer.Add(new Kpi()); won't trigger my method.
Method 2: (Note: I have read the definition for the special methods Empty/Never/Throw but other than these I can't seem to find a way to create an observable that emits something other than primitive numbers etc.)
var buffer = Observable.Empty<Kpi>();
buffer.Buffer(TimeSpan.FromMinutes(1), 5).Subscribe(
async kpis =>
{
await _retry.ExecuteAsync(() => Process(kpis.ToList())).ConfigureAwait(false);
});
Then buffer.Publish(new Kpi()) . Again nothing happens
Where am I am going wrong ?
In the first case, calling ToObservable on List won't make the List magically notify of it's changes. List simply does not have that feature.
In the second case, Publish does something completely different than what you are expecting.
If you want to create an observable from events, you are looking for Subject class.
var buffer = new Subject<Kpi>();
buffer.Buffer(TimeSpan.FromMinutes(1), 5).Subscribe(
async kpis =>
{
await _retry.ExecuteAsync(() => Process(kpis.ToList())).ConfigureAwait(false);
});
// notify of new item
buffer.OnNext(new Kpi());
There are many ways to create new observable sequence. I would recommend read through it to see if one is more suited for you. For example turning event into observable.

How to set dispose action to Observable?

I know how to create an observable and assign a disposing action:
Observable.Create(o =>
{
// o.OnNext etc.
return Disposable.Create(() => { /* ... */ });
});
But now I produced an observable from query syntax:
var observable = from x in otherObservable
select x;
How to assign a disposing action to such query?
If I understand correctly, you want to "chain" or "listen" whenever the subscription is disposed. One way to do this is to use the Finally operator of IObservable<T>, as such:
var ob = from x in Observable.Interval(TimeSpan.FromSeconds(1))
select x;
// Use Finally to create an intermediate IObservable
var disposeSub = ob.Finally(() => Console.WriteLine("disposed"));
// Subscribe to the intermediate observable instead the original one
var yourSub = disposeSub.Subscribe(Console.WriteLine);
// Wait for some numbers to print
Thread.Sleep(TimeSpan.FromSeconds(4));
// "disposed" will be written on the console at this point
yourSub.Dispose();
Hope that helps!
I think you should clarify your question. It's not entirely clear what you mean by "disposing action".
Calling an action using Observable.Finally has been suggested, but this action would run when the first of the following conditions is met:
The Observable sends OnCompleted()
The Observable sends OnError()
The subscription handle is disposed.
i.e. You can't guarantee that the action will be executed precisely when you call Dispose on the subscription handle; it may have already been run - but calling Dispose ensures it will have been invoked before the call to Dispose returns.
This may be what you need - but taking you at your word, you only want the action to run in the last of these cases - on dispose of the handle, then you would need to attach the action to the subscription handle itself, ie:
var otherDisposable = /* your observable */;
Action disposingAction = () => Console.WriteLine("I am disposed!");
var subscription = otherDisposable.Subscribe(/* set your handlers here */);
var disposable = new CompositeDisposable(
subscription,
Disposable.Create(disposingAction));
/* The disposingAction is *only* run when this is called */
disposable.Dispose();
I can't think what scenario would require this though, I wonder if Observable.Finally, as suggested by Carlos, is a better fit!
You don't dispose an observable. You dispose a subscription to an observable.
Example:
var observable = from x in otherObservable
select x;
var sub = observable.Subscribe(DoStuff);
sub.Dispose();

Track the (number of) observers in an Observable?

I have an observable which represents a stream of stock prices. If there are no observers on my observable sequence I'd like to be able to disconnect from the remote server that is supplying the stream of prices, but I don't want to do that until every observer has called Dispose(). Then in a similar fashion, when the first person calls Subscribe I'd like to reconnect to the remote server.
Is there a way to figure out how many observers have called subscribe on an observable? Or perhaps a way to know when observers are calling Subscribe or Dispose?
I would simply use RefCount / Publish. I always feel like if I'm implementing IObservable I'm working way too hard.
myColdObservable.Publish().RefCount();
This will make your observable stop pulsing after everyone has disconnected. Here's a sample:
var coldObservable = Observable
.Interval(TimeSpan.FromSeconds(1))
.ObserveOn(Scheduler.TaskPool)
.Select(_ => DoSomething());
var refCountObs = coldObservable.Publish().RefCount();
CompositeDisposable d = new CompositeDisposable();
d.Add(refCountObs.Subscribe(n => Console.WriteLine("First got: " + n)));
d.Add(refCountObs.Subscribe(n => Console.WriteLine("Second got: " + n)));
d.Add(refCountObs.Subscribe(n => Console.WriteLine("Third got: " + n)));
//Wait a bit for work to happen
System.Threading.Thread.Sleep(10000);
//Everyone unsubscribes
d.Dispose();
//Observe that DoSomething is not called.
System.Threading.Thread.Sleep(3000);
This does not cover the case where you actually want to know the number of subscribers, but I think this fits with your requirements of stopping work if there are no subscribers.
Bit of an old one but I came across this post as I had a problem where I needed to know the number of subscribers. Using Bart's suggestion I came up with this extension.
public static IObservable<T> CountSubscribers<T>(this IObservable<T> source, Action<int> countChanged)
{
int count = 0;
return Observable.Defer(() =>
{
count = Interlocked.Increment(ref count);
countChanged(count);
return source.Finally(() =>
{
count = Interlocked.Decrement(ref count);
countChanged(count);
});
});
}
In general, don't implement IObservable; typically there's already soemthing in Rx that can help you out, either directly or through composition. If you ever have to implement IObservable, use Observable.Create to do so, in order to get all the guaranteed required for the observer contract etc.
As for your problem - the suggestion of using Publish and RefCount is exactly the composition you're looking for. If you want to count yourself for some reason, use Observable.Defer to intercept subscriptions, possibly with Observable.Finally to intercept sequence terminations. Or, wrap the source with an Observable.Create, forward the observer to the wrapped sequence, and wrap the returned IDisposable with counting logic (using Disposable.Create).
Cheers,
-Bart (Rx team)
IObservable<T> is an interface that you can implement. In the Subscribe method of the interface you can keep track of observers by maintaining a list internally.
Following code snippet is from MSDN.
private List<IObserver<Location>> observers;
public IDisposable Subscribe(IObserver<Location> observer)
{
if (! observers.Contains(observer))
observers.Add(observer);
// ------- If observers.Count == 1 create connection. -------
return new Unsubscriber(observers, observer);
}
private class Unsubscriber : IDisposable
{
private List<IObserver<Location>>_observers;
private IObserver<Location> _observer;
public Unsubscriber(List<IObserver<Location>> observers, IObserver<Location> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
_observers.Remove(_observer);
// ----------- if observers.Count == 0 close connection -----------
}
}

Using Rx to synchronize asynchronous events

I want to put Reactive Extensions for .NET (Rx) to good use and would like to get some input on doing some basic tasks. To illustrate what I'm trying to do I have a contrived example where I have an external component with asyncronous events:
class Component {
public void BeginStart() { ... }
public event EventHandler Started;
}
The component is started by calling BeginStart(). This method returns immediately, and later, when the component has completed startup, the Started event fires.
I want to create a synchronous start method by wrapping the component and wait until the Started event is fired. This is what I've come up with so far:
class ComponentWrapper {
readonly Component component = new Component();
void StartComponent() {
var componentStarted =
Observable.FromEvent<EventArgs>(this.component, "Started");
using (var startedEvent = new ManualResetEvent(false))
using (componentStarted.Take(1).Subscribe(e => { startedEvent.Set(); })) {
this.componenet.BeginStart();
startedEvent.WaitOne();
}
}
}
I would like to get rid of the ManualResetEvent, and I expect that Rx has a solution. But how?
PL's answer if perfectly good for your spec, but I thought you might get better results by not fighting RX with .First() but embracing it with creating an observable to your component:
public static IObservable<Unit> AsObservable(this Component component)
{
return Observable.Defer(() =>
{
component.BeginStart();
return Observable
.FromEvent<EventArgs>(component, "Started")
.Select(_ => new Unit());
});
}
Then you could use it as blocking:
new Component().AsObservable().First();
Non - blocking:
new Component().AsObservable().Subscribe(_ => Console.WriteLine("Done"));
Hot:
var pub = new Component().AsObservable().Publish();
pub.Subscribe(_ => Console.WriteLine("Sub1"));
pub.Subscribe(_ => Console.WriteLine("Sub2"));
pub.Connect(); // started just once per two subscriptions
Composable:
new Component().AsObservable().Delay(TimeSpan.FromSeconds(1));
etc...
EDIT: For the case of multiple events that you have to wait on and collect information,
the following variation could be used:
public static IObservable<EventArgs> AsObservable(this Component component)
{
return Observable.Defer(() =>
{
component.BeginStart();
return
Observable.FromEvent<EventArgs>(component, "Started1").Take(1)
.Merge(
Observable.FromEvent<EventArgs>(component, "Started2").Take(1))
.Select(evt => evt.EventArgs);
});
}
With this one, if you want to block till completion, you might use .AsObservable.Last().
Something like this should do it:
var replay = Observable
.FromEvent<EventArgs>(this.component, "Started")
.Replay();
replay.Connect();
component.BeginStart();
replay.First();

Categories