Simple observable variable works as expected an triggers callback immediately on the same thread.
Why a class variable of any observable type (Subject, ISubject, Observable, IObservable) doesn't trigger callback?
Example with simple variable - [Works]
var x1 = new Subject<string>();
var x2 = x1.DistinctUntilChanged();
x2.Subscribe(o =>
{
// Triggered as expected
});
x1.OnNext("Hello");
Example with a class - [Does NOT work]
public class InstrumentModel
{
public Subject<string> Demo => new Subject<string>();
}
var class1 = new InstrumentModel();
class1.Demo
//.DistinctUntilChanged()
//.SubscribeOn(Scheduler.CurrentThread)
//.ObserveOn(Scheduler.CurrentThread)
.Subscribe(o =>
{
// Never triggered
});
class1.Demo.OnNext("Hello");
Problem is that you made Demo to return new instance of Subject<string> every time it is used.
Demo instance that you subscribed too, is not the same instance you called OnNext() on.
class1.Demo.Subscribe(...); // makes new instance `Subject<string>`
class1.Demo.OnNext("Hello"); // makes another new instance of `Subject<string>`
Keep it the same instance and it will work. For example:
public class InstrumentModel
{
public Subject<string> Demo = new Subject<string>();
}
or:
public class InstrumentModel
{
public InstrumentModel()
{
this.Demo = new Subject<string>();
}
public Subject<string> Demo { get; }
}
Related
I heard that passing an action, function or delegate to a public method is a security issue.
I want to understand why or how this can be exploited because I cannot find a way to do it.
At least.. is it a best practice to not pass delegates to classes?
Examples of so called vulnerable code:
Public constructor action:
public class MyClass { public MyClass(Action doSomething) { doSomething?.Invoke(); } }
with the calling code in another project using my code as a reference:
var securityIssueActionOutsideOfMyControl = new Action(() => { ... });
var instance = new MyClass(securityIssueActionOutsideOfMyControl);
Public constructor action with parameter:
public class MyClass
{
public MyClass(Action<string> doSomething)
{
doSomething?.Invoke("something");
}
}
with the calling code in another project using my code as a reference:
var securityIssueActionOutsideOfMyControl = new Action<string>((someParameter) => { ... });
var instance = new MyClass(securityIssueActionOutsideOfMyControl);
Same so called issue can happen with functions or delegates passed to public constructor.
Public method with action:
public class MyClass { public void MyAction(Action doSomething) { doSomething?.Invoke(); } }
with the calling code in another project using my code as a reference:
var securityIssueActionOutsideOfMyControl = new Action(() => { ... });
var instance = new MyClass();
instance.MyAction(securityIssueActionOutsideOfMyControl);
public class MyClass { public void MyAction(Action<string> doSomething) { doSomething?.Invoke("some string"); } }
with the calling code in another project using my code as a reference:
var securityIssueActionOutsideOfMyControl = new Action<string>((someParameter) => { ... });
var instance = new MyClass();
instance.MyAction(securityIssueActionOutsideOfMyControl);
Same so called issue can happen with functions or delegates passed to public methods.
How is it different than the following code using events?
var securityIssueActionOutsideOfMyControl = new Action(() => { ... });
var instance = new MyClass();
instance.MyEvent += (s, e) => securityIssueActionOutsideOfMyControl;
Or how it is different from calling the method directly in a different project?
var securityIssueActionOutsideOfMyControl = new Action(() => { ... });
securityIssueActionOutsideOfMyControl?.Invoke();
I have a class called ValuePusher with a property named Value and receives a dependency of type ValueReceiver, also with a property named Value. The former class arranges to 'push' values to an instance of the latter class via a System.Reactive.Subjects.Subject<int> object. Initially it pushes values one for one, but later it will restrict the amount of values pushed using the Sample method - note the commented-out call to this method in the code below:
public sealed class ValuePusher : IDisposable
{
private readonly ValueReceiver _receiver;
private readonly IScheduler _scheduler;
private readonly Subject<int> _subject;
private int _value;
public ValuePusher(ValueReceiver receiver, IScheduler scheduler)
{
_receiver = receiver;
_scheduler = scheduler;
// Arrange to push values to `receiver` dependency
_subject = new Subject<int>();
_subject.ObserveOn(_scheduler)
//.Sample(TimeSpan.FromMilliseconds(50), _scheduler)
.SubscribeOn(_scheduler)
.Subscribe(i => PushCurrentValueToReceiver());
}
public int Value
{
get => _value;
set
{
_value = value;
_subject.OnNext(0);
}
}
private void PushCurrentValueToReceiver()
{
_receiver.Value = Value;
}
public void Dispose()
{
_subject?.OnCompleted();
_subject?.Dispose();
}
}
public class ValueReceiver
{
public int Value { get; set; }
}
I write a unit test for the code above, involving a Microsoft.Reactive.Testing.TestScheduler, which passes:
[TestMethod]
[Timeout(1000)]
public void ReceiverReceivesValueFromPusherViaScheduler()
{
var scheduler = new TestScheduler();
var receiver = new ValueReceiver();
using (var pusher = new ValuePusher(receiver, scheduler))
{
scheduler.Start();
pusher.Value = 1;
scheduler.AdvanceBy(1);
Assert.AreEqual(1, receiver.Value);
}
}
However, if uncomment the call to Sample method the test fails to complete and times-out. How can I change the test code or the production code to verify that values are pushed to the receiving object when Sample is in use?
Source code: https://github.com/DanStevens/StackOverflow71409012
The reason why it times out, seems to be the combination of .Sample(...) and scheduler.Start().
scheduler.Start() tries execute everything that has been scheduled, but I think Sample() keeps scheduling a sample, and thus scheduler.Start() never finishes.
So if you remove scheduler.Start(), and do this instead:
...
// Following line instead of scheduler.Start(), needed because of the .SubscribeOn(...) call
scheduler.AdvanceBy(1);
pusher.Value = 1;
scheduler.AdvanceBy(TimeSpan.FromMilliseconds(50).Ticks);
Assert.AreEqual(1, receiver.Value);
...
it should work with or without the call to .Sample(...).
[Edit] as per Dan Stevens' comment.
How can I change a Observable source while keeping the subscription intact? Yea, this is easy to accomplish with a Subject but best practises says not to use a subject.
Here an example:
Worker.cs
public class Worker
{
public IObservable<Worker> IsWorking {get;}
public string Name {get;}
public Worker(string name)
{
Name = name;
IsWorking = Observable.Interval(TimeSpan.FromSeconds(1))
.Select(_ => this);
}
}
This class exposes an Observable which fires every second.
WorkerState.cs
public class WorkerState
{
public Worker CurrentWorker
{
set => WorkerIsBusy = value.IsWorking;
}
public IObservable<Worker> WorkerIsBusy { get; private set; }
}
This class is supposed to hold a worker unit, which can be changed on the fly but the Subscription should be automatically attached to the current worker. (This is would be the place for a Subject)
And here the test:
Program.cs
public class Program
{
public async Task Run()
{
var state = new WorkerState();
state.CurrentWorker = new Worker("A");
state.WorkerIsBusy.Subscribe(worker =>
Console.WriteLine($"Worker {worker.Name}"));
await Task.Delay(3000);
Console.WriteLine("Should change now to B...");
state.CurrentWorker = new Worker("B");
Console.Read();
}
}
But my ouput is the following:
Worker A
Worker A
Should change now to B...
Worker A
Worker A
Worker A
...
instead of switching to worker B.
The approach you should almost always use for re-subscribing is to get the query to resubscribe for you by using the .Switch() operator.
Something like this:
var switcher = new Subject<IObservable<int>>();
var subscription = switcher.Switch().Subscribe(x => Console.WriteLine(x));
switcher.OnNext(Observable.Return(42));
switcher.OnNext(Observable.Range(0, 3));
That produces:
42
0
1
2
No re-subscription required.
For your code you need to change WorkerState to this:
public class WorkerState
{
private Worker currentWorker = null;
private Subject<Worker> currentWorkerSubject = new Subject<Worker>();
public Worker CurrentWorker
{
set
{
currentWorker = value;
currentWorkerSubject.OnNext(value);
}
}
public IObservable<Worker> WorkerIsBusy
{
get =>
currentWorkerSubject
.StartWith(currentWorker)
.Where(w => w != null)
.Select(w => w.IsWorking)
.Switch();
}
}
Then your code works (with the minor caveat that the await Task.Delay(3000); has a small race condition with the Observable.Interval(TimeSpan.FromSeconds(1)) inside Worker. Change the await to 3500 to avoid it.
The issue that you have is that you've subscribed to the previous value of WorkerIsBusy, and although you've changed the reference, you haven't changed the subscription, which still points at the previous value.
You would need to intercept (actually subscribe to) the worker.IsWorking in your WorkerState class, and unsubscribe / resubscribe when the property value changes.
Or you could use a Subject - I don't understand why you wouldn't?
Coming from a Java background, I have to implement something in C#. The class is a domain object which is composed of multiple other domain objects. I don't like to have a constructor with 10 fields, so I thought of using the builder design pattern! Here is what I came up with:
public class MyDomainObject
{
public DomainObject1 Obj1 { get; private set; }
public DomainObject2 Obj2 { get; private set; }
public DomainObject3 Obj3 { get; private set; }
...
public class DomainObjectBuilder
{
private MyDomainObject _domainObj = new MyDomainObject();
public DomainObjectBuilder(DomainObject1 obj1)
{
_domainObj.Obj1 = obj1;
}
public DomainObjectBuilder withDomainObject2(DomainObject2 obj2)
{
_domainObj.Obj2 = obj2;
return this;
}
.....
public MyDomainObject Build()
{
// Construct and Return the MyDomainObject
}
}
}
Now is this implementation thread safe? When I instantiate my domain object the following way:
var myDomainObject = new DomainObjectBuilder(obj1)
.withDomainObject2(obj2)
.withDomainObject3(obj3).build();
What happens if the calls between withDomainObject2 and withDomainObject3 is handled by different threads?
I haven't come across any code that splits a builder on multiple threads. The simple answer given your requirements is simply (no it is not thread safe).
Consider this example using your MyDomainObject class:
private MyDomainObject _myObj;
void Main(string[] args)
{
DomainObject1 obj1 = new DomainObject1();
_myObj = new MyDomainObject(obj1);
Thread oThread1 = new Thread(ThreadProc1);
oThread1.Start();
Thread oThread2 = new Thread(ThreadProc2);
oThread2.Start();
MyDomainObject myObjFinal = _myObj.Build();
DomainObject2 obj2 = myObjFinal.Obj2; //No guarantee that Obj2 is set or initialized
DomainObject3 obj3 = myObjFinal.Obj3; //No guarantee that Obj3 is set or initialized
}
void ThreadProc1()
{
DomainObject2 obj2 = new DomainObject2();
MyDomainObject myObjModified = _myObj.withDomainObject2(obj2);
DomainObject3 objNew = _myObj.Obj3; //No guarantee that Obj3 is set or initialized
}
void ThreadProc2()
{
DomainObject3 obj3 = new DomainObject3();
MyDomainObject myObjModified = _myObj.withDomainObject3(obj3);
DomainObject2 objNew = _myObj.Obj2; //No guarantee that Obj2 is set or initialized
}
As you can see there is no guarantee that any of the objects is initialized or set when called after Build() in the main thread. The same applies when trying to access an object that is initialized in a different thread.
you don't need a constructor wit too many things.... the thing that you may not call some of these method, mean some of them are optional, i see that also i java, but here after some reversion of .NET framework, you can do it more simple... like this:
A a = new A(Required properties){
Name="x",
Family="Y",
OpetionalProperty3 = "z",
.......
};
and if you do not have any thing required, you can remove the parentheses at all( when you define optional properties).
A a = new A{
Name="x",
Family="Y",
OpetionalProperty3 = "z",
.......
};
And about your case and thread handeling, check out the 'volatile' syntax for variables - it ensure last value is in the field on every thread call
I would like to invoke a simple method (no arguments, returns void) from within a workflow. Suppose I have the following class:
public class TestClass
{
public void StartWorkflow()
{
var workflow = new Sequence
{
Activities =
{
new WriteLine { Text = "Before calling method." },
// Here I would like to call the method ReusableMethod().
new WriteLine { Text = "After calling method." }
}
}
new WorkflowApplication(workflow).Run();
}
public void ReusableMethod()
{
Console.WriteLine("Inside method.");
}
}
How do I call ReusableMethod from within my workflow? I was looking at InvokeAction but that doesn't seem to be what I want. I could also write a custom activity that calls this method, but I'm specifically interested in this scenario. Is this possible?
How about InvokeMethod ?
public class TestClass
{
public void StartWorkflow()
{
var workflow = new Sequence
{
Activities =
{
new WriteLine {Text = "Before calling method."},
// Here I would like to call the method ReusableMethod().
new InvokeMethod {MethodName="ReusableMethod", TargetType = typeof(TestClass)},
new WriteLine {Text = "After calling method."}
}
};
var wf = new WorkflowApplication(workflow);
wf.Run();
var are = new AutoResetEvent(false);
wf.Completed = new Action<WorkflowApplicationCompletedEventArgs>(arg => are.Set());
are.WaitOne(5000);
}
public static void ReusableMethod()
{
Console.WriteLine("Inside method.");
}
}