1

I'd like to wire a ReactiveCommand up to a ConnectableObservable, since the observable should be connectable by multiple subscribers.

The problem is that ReactiveCommand will only call the Subscribe method on the ConnectableObservable, rather than the Connect method as I would like.

The code below demonstrates what I'm trying to achieve. Notice the StartOrConnectService method that is called by service code.

public class Foo
{
    public IConnectableObservable<string> Connection { get; }

    public Foo(BarService barService)
    {
        Connection = Observable.Create<string>(observer =>
        {
            disp = barService.BarStream().Subscribe(
              bar => { 
                Console.WriteLine($"{bar}");
                observable.onNext("Connected");
              },
              ex => observable.onNext("Errored"),
              () => observable.onNext("Disconnected")
            );
            return disp;
        }).Publish();
    }

    // This method is called by service code.
    public IDisposable StartOrConnectService()
    {
        // bunch of other stuff going on here, but essentially calling connect
        return Connection.Connect();
    }

}

public sealed class FooViewModel : ReactiveObject
{
    public ReactiveCommand<Unit, string> ConnectCommand { get; }

    public FooViewModel(Foo foo)
    {
        ConnectCommand = ReactiveCommand
            .CreateFromObservable(() => foo.Connection);
    }
}     

Is there some way of adapting or wrapping a ConnectableObservable to a regular Observable so the ConnectableObservable.Connect method is called when the ReactiveCommand executes?

MarkNS
  • 3,811
  • 2
  • 43
  • 60
  • 2
    If you ever find yourself doing a `return Disposable.Empty` then you're probably doing something wrong. – Enigmativity Oct 25 '17 at 02:53
  • What does your source observable really look like? And why do you say "since the observable should be connectable by multiple subscribers"? – Enigmativity Oct 25 '17 at 02:54
  • The source obsservable is actually the one shown in my other question here: https://stackoverflow.com/questions/46832362/notification-when-reactivecommand-completes. I want this observable to be subscribed to when either a system condition occurs, or when a user clicks a button. The Console.WriteLine in the above code actually updates some internal state of the Foo class. – MarkNS Oct 25 '17 at 07:05
  • Indeed the disposable that's returned in the real code disposes of the inner subscription, amongst other things. (I'm tempted to edit that in the question, do you mind?) – MarkNS Oct 25 '17 at 07:06
  • It would be better to show the correct code. – Enigmativity Oct 25 '17 at 07:16
  • Why do you say "since the observable should be connectable by multiple subscribers"? – Enigmativity Oct 25 '17 at 07:32
  • Maybe my terminology is not great as I'm new to RX. The ViewModel has a ReactiveCommand that should be able to subscribe to the outer observable, and there's other system code that should also be able to subscribe to the outer observable. As soon as there's at least one subscriber to the outer observable, I want the inner observable to be subscribed to. (Hopefully that's precise!) – MarkNS Oct 25 '17 at 07:41
  • 2
    I think you might be getting it worse. Usually we refer to "inner" and "outer" observables when you have `IObservable>`. I think you just mean that you want a single subscription to the observable in the `.Create` method when you have one or more subscribing to the result of the `.Create` method. Is that right? – Enigmativity Oct 25 '17 at 08:38
  • Yep, that's absolutely right. – MarkNS Oct 25 '17 at 08:39
  • And why don't you want more than one subscription to the observable in the `.Create` method? – Enigmativity Oct 25 '17 at 09:03
  • Because the subscription to the inner observable (I'm sorry that's easier to say than 'the observable in the create method') is only interested in updating the state of the Foo object. Whereas the outer subscriptions are only interested in the state of that connection - and ensuring that it is on when they are subscribed. – MarkNS Oct 25 '17 at 09:10
  • There are other non-reactive components that access the Foo state directly, upon an external trigger. – MarkNS Oct 25 '17 at 09:15
  • It doesn't sound like you need to publish. I think you should post the actual code too. – Enigmativity Oct 25 '17 at 09:20
  • Hmm, sorry I can't do that very easily. Can you explain why you think I don't need to publish? Otherwise, thanks for the help, but I'm pretty happy with the solution I have now :) – MarkNS Oct 25 '17 at 09:23
  • If you're just updating the state of `Foo` (which is shared with all subscribers) then it doesn't matter if you have a shared subscription to the "inner" observable. – Enigmativity Oct 25 '17 at 09:51
  • The state of Foo is not observed by the subscribers - that state is used by a different part of the system. The subscribers observe the state of the connection. – MarkNS Oct 25 '17 at 09:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/157459/discussion-between-enigmativity-and-markns). – Enigmativity Oct 25 '17 at 11:19

1 Answers1

2

Aha, turns out I was looking for the RefCount extension method (introtorx), that converts an IConnectableObservable back into an IObservable, but magically implements the Connect semantics. #loveRX

MarkNS
  • 3,811
  • 2
  • 43
  • 60
  • 2
    Careful - this makes it a one time only subscription call. If the observable completes and you try to connect again you'll get no values. – Enigmativity Oct 25 '17 at 02:52
  • Indeed, the outer observable never completes or errors - the observable stream simply toggles between an enum describing the inner stream state: Connected, Disconnected, Errored. – MarkNS Oct 25 '17 at 07:09
  • I updated the question to show that the outer observable never completes. – MarkNS Oct 25 '17 at 07:27