I'm creating an observable and I'm creating the subscription separately:
class CustomQuery {
string Name;
IObservable<int> Occurrences;
}
public IEnumerable<CustomQuery> GatherCustomQueryObservables()
{
yield return new CustomQuery() {
Name = "NameXXX",
Occurrences = Observable.Create<int>(
observer =>
{
int occurrences = this.webservice.GetOccurrences()
observer.OnNext(occurrences);
return System.Reactive.Disposables.Disposable.Empty;
}
);
}
By other hand, there's another method deals with these CustomQueries:
public void CommitCustomQueryObservables(IEnumerable<CustomQuery> queries)
{
foreach (CustomQuery query in queries)
{
query.Occurrences
.Select(o => o)
.SubscribeOn(System.Reactive.Concurrency.TaskPoolScheduler.Default)
.ObserveOn(System.Reactive.Concurrency.DispatcherScheduler.Current)
.Subscribe(
occurrences =>
{
string strOccurrences = occurrences > 0 ? occurrences.ToString() : "";
this.Label.Text = strOccurrences;
}
);
}
}
Nevertheless, I'm getting a System.InvalidOperationException exception:
The current thread has no Dispatcher associated with it.
The last line of the stacktrace is at
System.Reactive.Concurrency.DispatcherScheduler.get_Current().
I don't quite figure out how to handle it.
Any ideas?
For Windows Forms you need to use the ControlScheduler for synchronization, not the DispatcherScheduler.
Now you've added the System.Reactive.Windows.Forms package this can be achieved by simply using [observable].ObserveOn([control]); in your example this could be:
public void CommitCustomQueryObservables(IEnumerable<CustomQuery> queries)
{
foreach (CustomQuery query in queries)
{
query.Occurrences
.Select(o => o)
.SubscribeOn(System.Reactive.Concurrency.TaskPoolScheduler.Default)
.ObserveOn(this.Label)
.Subscribe(
occurrences =>
{
string strOccurrences = occurrences > 0 ? occurrences.ToString() : "";
this.Label.Text = strOccurrences;
}
);
}
}
Related
RX is synchronous by default so we can confirm it
int j = 0;
Observable.Range(1, 2)
.SelectMany(i => {
return new[]{1}.ToObservable()
.Select(i1 => {
new[]{1}.ToObservable().Subscribe(i2 => j = 1);
return 0;
})
;
})
.Subscribe();
j.ShouldBe(1);
however in my code base I have a similar query that does not fire unless i use the Immediate scheduler.
public static IObservable<GitHubIssue> Save(this IObservable<IReadOnlyList<Issue>> source, IGitHubRepository repository){
var objectSpace = repository.ObjectSpace;
return source.SelectMany(list => list.ToObservable().Select(issue => {
var gitHubIssue = objectSpace.CreateObject<GitHubIssue>();
gitHubIssue.Id = issue.Id;
issue.Labels.ToObservable(Scheduler.Immediate).Select(label => {
var gitHubLabel =objectSpace.GetObjectsQuery<GitHubLabel>(true).FirstOrDefault(_ => label.Name == _.Name) ??
objectSpace.NewGitHubLabel(label);
gitHubIssue.Labels.Add(gitHubLabel);
return gitHubLabel;
}).Subscribe();
//previous selector is not executed
i fail to see the relation and why this happens
"RX is synchronous by default" - No, it is not. Each operator has its own default.
Take Observable.Range for example. Here's the implementation for when you don't provide a Scheduler:
public virtual IObservable<int> Range(int start, int count)
{
return Range_(start, count, SchedulerDefaults.Iteration);
}
Which in turn uses:
internal static IScheduler Iteration
{
get
{
return CurrentThreadScheduler.Instance;
}
}
If I take Observable.Timer as an counterpoint, I have this code:
public virtual IObservable<long> Timer(TimeSpan dueTime)
{
return Timer_(dueTime, SchedulerDefaults.TimeBasedOperations);
}
Which uses:
internal static IScheduler TimeBasedOperations
{
get
{
return DefaultScheduler.Instance;
}
}
The fact that you have to put in .ToObservable(Scheduler.Immediate) says you have an operator that doesn't use Scheduler.Immediate by default.
Now, ignoring all of this, what you should never ever do inside an observable pipeline is subscribe to another observable. Never ever. When you do this you are relying on side-effects and that's what's going wrong in your code.
You should always assume that any call to Subscribe runs sometime in the future, so even your assertion that j.ShouldBe(1) shouldn't ever be used after a Subscribe.
Your sample code should be more like this:
int j = 0;
Observable
.Range(1, 2)
.SelectMany(i =>
{
return
new[] { 1 }
.ToObservable()
.Select(i1 =>
{
return 1;
})
;
})
.Subscribe(x =>
{
j = x;
/* j only valid here */
});
/* j NOT valid here */
Rational concrete example of a side-effect:
int j = 0;
Observable
.Delay(Observable.Return(42), TimeSpan.FromSeconds(2.0))
.Do(x => j = x)
.Subscribe();
Console.WriteLine(j);
Ultimately j will be equal to 42, but not when Console.WriteLine(j) is called. Never rely on state outside of the observable that's updated within the observable.
I have the following method to update a document in MongoDB:
public async Task UpdateAsync(T entity)
{
await _collection.ReplaceOneAsync(filter => filter.Id == entity.Id, entity);
}
Which works fine - I was just wondering if anybody has an example of how the UpdateManyAsync function works:
public async Task UpdateManyAsync(IEnumerable<T> entities)
{
await _collection.UpdateManyAsync(); // What are the parameters here
}
Any advice is appreciated!
UpdateManyAsync works the same way as update with multi: true in Mongo shell. So you can specify filtering condition and update operation and it will affect multiple documents. For instance to increment all a fields where a is greater than 10 you can use this method:
var builder = Builders<SampleClass>.Update;
await myCollection.UpdateManyAsync(x => x.a > 10, builder.Inc(x => x.a, 1));
I guess you'd like to replace multiple documents. That can be achieved using bulkWrite method. If you need generic method in C# then you can introduce some kind of marker interface to build filter part of replace operation:
public interface IMongoIdentity
{
ObjectId Id { get; set; }
}
Then you can add generic constaint to your class and use BuikWrite in .NET like below:
class YourRepository<T> where T : IMongoIdentity
{
IMongoCollection<T> collection;
public async Task UpdateManyAsync(IEnumerable<T> entities)
{
var updates = new List<WriteModel<T>>();
var filterBuilder = Builders<T>.Filter;
foreach (var doc in entities)
{
var filter = filterBuilder.Where(x => x.Id == doc.Id);
updates.Add(new ReplaceOneModel<T>(filter, doc));
}
await collection.BulkWriteAsync(updates);
}
}
As #mickl answer, you can not use x=> x.Id because it is a Generic
Use as below:
public async Task<string> UpdateManyAsync(IEnumerable<T> entities)
{
var updates = new List<WriteModel<T>>();
var filterBuilder = Builders<T>.Filter;
foreach (var doc in entities)
{
foreach (PropertyInfo prop in typeof(T).GetProperties())
{
if (prop.Name == "Id")
{
var filter = filterBuilder.Eq(prop.Name, prop.GetValue(doc));
updates.Add(new ReplaceOneModel<T>(filter, doc));
break;
}
}
}
BulkWriteResult result = await _collection.BulkWriteAsync(updates);
return result.ModifiedCount.ToString();
}
Or you go by Bson attribute:
public async Task UpdateManyAsync(IEnumerable<TEntity> objs, CancellationToken cancellationToken = default)
{
var updates = new List<WriteModel<TEntity>>();
var filterBuilder = Builders<TEntity>.Filter;
foreach (var obj in objs)
{
foreach (var prop in typeof(TEntity).GetProperties())
{
object[] attrs = prop.GetCustomAttributes(true);
foreach (object attr in attrs)
{
var bsonId = attr as BsonIdAttribute;
if (bsonId != null)
{
var filter = filterBuilder.Eq(prop.Name, prop.GetValue(obj));
updates.Add(new ReplaceOneModel<TEntity>(filter, obj));
break;
}
}
}
}
await _dbCollection.BulkWriteAsync(updates, null, cancellationToken);
}
I have following snippet in ViewModel.
public ReactiveCommand<object, System.Reactive.Unit> LoadCustomerDetails;
ReactiveCommand<OrderViewPager<SalesOrderOrderOptionsEnum>, CommandSubmitResultDto<List<SalesOrderDto>>> _loadSalesOrderList;
public ReactiveCommand<OrderViewPager<SalesOrderOrderOptionsEnum>, CommandSubmitResultDto<List<SalesOrderDto>>> LoadSalesOrderList
{
get { return _loadSalesOrderList; }
private set { this.RaiseAndSetIfChanged(ref _loadSalesOrderList, value); }
}
this.LoadSalesOrderList = ReactiveCommand.CreateFromTask<Pager<OrderOptionsEnum>, CommandSubmitResultDto<List<SalesOrderDto>>>(
async filter =>
{
Debug.WriteLine("Load SalesOrderList...");
Debug.WriteLine("Customer Id : " + SelectedCustomerId);
await LoadCustomerDetails.Execute();
var result = await SalesOrderMobApi.GetByCustomerTraderEntityIdPaged(SelectedCustomerId, filter, null, SalesOrderTypeEnum.SalesOrder, SalesOrderPOOptions.NotOriginatingFromPurchaseOrder);
return result;
})
.DisposeWith(ViewModelBindings.Value);
this.LoadSalesOrderList.ThrownExceptions
.Subscribe(ex =>
{
Debug.WriteLine("Load SalesOrderList Failed!");
});
this.LoadSalesOrderList
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(result =>
{
if (result.PagingInfo.CurrentPage > 1)
{
foreach (var item in result.Data)
{
SalesOrdersList.Add(SalesOrderVMM.From(item));
}
}
else
{
SalesOrdersList.Clear();
foreach (var item in result.Data)
{
SalesOrdersList.Add(SalesOrderVMM.From(item));
}
}
});
LoadCustomerDetails = ReactiveCommand.CreateFromTask<object, System.Reactive.Unit>(
async _ =>
{
Debug.WriteLine(SelectedCustomerId);
var customers = await TraderEntityMobApi.GetById(SelectedCustomerId);
var customer = customers.Data;
SelectedCustomer = customer;
return System.Reactive.Unit.Default;
}
).DisposeWith(ViewModelBindings.Value);
It sometimes gives exception as follows.
System.NullReferenceException: Object reference not set to an instance of an object.
06-20 16:05:02.480 I/MonoDroid(15304): at DistributrIII.Mobile.Lib.VM.SalesOrder.CreateSOListVM.<RegisterObservables>b__43_2 (System.Collections.Generic.List`1[T] result) [0x0000e] in C:\Users\gayanbu\Source\Repos\Distributr 3.0 UI\Mobile\DistributrIII.Mobile.Lib\VM\SalesOrder\CreateSOListVM.cs:131 .at System.Reactive.AnonymousSafeObserver`1[T].OnNext (T value) [0x0000a] in <99f8205c51c44bb480747b577b8001ff>:0
06-20 16:05:02.480 I/MonoDroid(15304): at System.Reactive.ScheduledObserver`1[T].Run (System.Object state, System.Action`1[T] recurse) [0x000f5] in <99f8205c51c44bb480747b577b8001ff>:0
06-20 16:05:02.480 I/MonoDroid(15304): at System.Reactive.Concurrency.Scheduler+<>c__DisplayClass49_0`1[TState].<InvokeRec1>b__0 (TState state1) [0x0001e] in <99f8205c51c44bb480747b577b8001ff>:0
06-20 16:05:02.480 I/MonoDroid(15304): at System.Reactive.Concurrency.Scheduler.InvokeRec1[TState] (System.Reactive.Concurrency.IScheduler scheduler,
I guess it tries to execute the code inside reactive command ,LoadSalesOrderList even the result of this is null. How to handle this ? Could someone kindly explain the proper way of subscribing to Reactive Command. I am executing this command in the page load as, this.ViewModel.LoadSalesOrderList.Execute().subscribe(new Pager<OrderOptionsEnum>())
Thanks!
if you want your command when throw exception to be catched in ThrownExceptions execute command like Observable.Return(input).InvokeCommand(Command).DisposeWith(disposable) where input is the input for command and Command is the name of the Command
I have 3 methods these are same methods only some parameters will be change I want to write one method how can i write
public string method1(int id)
{
var getAllStudents = rep.Students.Where(e => e.StudentId == id).ToList();
foreach (var item in getAllStudents)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
public string method2(int id)
{
var getAllTeachers = rep.Teachers.Where(e => e.TeacherId == id).ToList();
foreach (var item in getAllTeachers)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
public string method3(int id)
{
var getAllClasses = rep.Classes.Where(e => e.ClassId == id).ToList();
foreach (var item in getAllClasses)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
I think there is very easy way to write 1 method. the think is where parameter has different id..
Thanks.
Avoid conditional logic based on arguments. This leads to fragile code because every parameter combination has to be tested to be considered reliable. This leads to complex code that is easily prone to bugs. Having simpler single-purpose methods are typically much more reliable and easier to understand and maintain.
For instance given your example and assuming that "rep" was your instance's DbContext...
public bool IsActiveStudent(int id)
{
bool result = rep.Students.Any(x => x.StudentId == id && x.IsActive);
return result;
}
public bool IsActiveTeacher(int id)
{
bool result = rep.Teachers.Any(x => x.TeacherId == id && x.IsActive);
return result;
}
public bool IsActiveClass(int id)
{
bool result = rep.Classes.Any(x => x.ClassId == id && x.IsActive);
return result;
}
These can be essentially one-liners by simply returning the .Any() result. I tend to favour selecting the result into a variable first and returning it on a separate line since it makes it easier to breakpoint and inspect.
If you need to return a string for "Ok" vs. "Error" then:
return result ? "OK" : "Error";
Methods should strive to do one thing, and do it well. Easy to understand and troubleshoot if need be. Adding parameters and conditional code inside the method merely makes the code more volatile and leaves openings for bugs. In the end it doesn't make the code much shorter when the initial method could be simplified.
You can not overload methods if they signatures are the same.
You have two methods with the same signature:
public string checkexist(int id)
What you can do is to rename your methods, like this:
public interface WriteSomethingHere {
public boolean isStudentExist(int id);
public boolean isTeacherExist(int id);
public boolean isClassExist(int id);
}
I just found answer using generic repo
public T GetEntity<T>(int Id)
where T : class
{
using (MyEntities rpContext = new MyEntities())
{
return rpContext.Set<T>().Find(e => e.Id == Id);
}
}
after calling
var entityStudent = GetEntity<Student>(1);
var entityTeacher = GetEntity<Teacher>(1);
var entityClasses = GetEntity<Classes>(1);
You have Create Enumeration
Public Enum ParameterStaus:short
{
Student=1,
Teacher=2,
Classess=3
}
public string method2(int id.ParameterStatus status)
{
if(status==ParameterStatus.Teacher)
{
var getAllTeachers = rep.Teachers.Where(e => e.TeacherId == id).ToList();
foreach (var item in getAllTeachers )
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
}
Else if(status==ParameterStatus.Student)
{
var getAllStudents = rep.Students.Where(e => e.StudentId == id).ToList();
foreach (var item in getAllStudents)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
Else
{
var getAllClasses = rep.Classes.Where(e => e.ClassId == id).ToList();
foreach (var item in getAllClasses)
{
if (item.isActive != true)
return "Error";
}
return "OK";
}
}
I am trying to hook a stream (IObservable) to be controlled through ToggleSwitch in a UWP project. The expectation is that I start the streaming when the switch is in On state and stop when it is in Off state.
So the thought is to
1. Create two commands, one to start the stream and another to stop the stream.
2. Create two Observables that monitors the switch state and InvokeCommand when the condition is right.
ViewModel
public class MainPageViewModel : ViewModelBase
{
public ReactiveCommand<Unit, (long, float)> StreamCommand { get; }
public ReactiveCommand<Unit, Unit> StopCommand { get; }
public IObservable<(long, float)> FlowStream { get; set; }
private bool _isStreamOn;
public bool IsStreamOn
{
get => _isStreamOn;
set => this.RaiseAndSetIfChanged(ref _isStreamOn, value);
}
public MainPageViewModel()
{
var stream = GetStream();
var canSwitchOn = this.WhenAnyValue(x => x.IsStreamOn);
var canSwitchOff = this.WhenAnyValue(x => x.IsStreamOn, isOn => isOn != true);
FlowStream = StreamCommand = ReactiveCommand.CreateFromObservable(
() =>
{
stream.Start();
return Observable.FromEventPattern<StreamDataEventArgs<(long, INumeric, INumeric, INumeric)>>(
h => stream.DataAvailable += h,
h => stream.DataAvailable -= h)
.SelectMany(e => e.EventArgs.Data)
.Select(item => item));
}, canSwitchOn);
StopCommand = ReactiveCommand.Create(
() =>
{
stream.Stop();
IsStreamOn = false;
}, canSwitchOff);
canSwitchOff.InvokeCommand(StopCommand);
canSwitchOn.InvokeCommand(StreamCommand);
}
}
View
public sealed partial class MainPage : Page, IViewFor<MainPageViewModel>
{
public MainPage()
{
InitializeComponent();
NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
ViewModel = new MainPageViewModel();
this.WhenActivated(subscription =>
{
subscription(this.OneWayBind(this.ViewModel,
vm => vm.StreamCommand,
v => v.chart.SeriesCollection[0].Stream)); // Chart take care of displaying data
subscription(this.Bind(this.ViewModel,
vm => vm.IsStreamOn,
v => v.streamToggle.IsOn));
});
}
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (MainPageViewModel)value; }
}
public MainPageViewModel ViewModel
{
get { return (MainPageViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(MainPageViewModel), typeof(MainPage), null);
}
However, the InvokeCommand fails, as it requires the ReactiveCommands to take the bool, instead of Unit.
Any idea how I can invoke a command when certain conditions are met?
If you want to turn a stream (IObservable<(long, float)> FlowStream) on and off based on a IObservable<bool> IsStreamOn observable then you can do this:
IObservable<(long, float)> outputStream =
IsStreamOn
.Select(flag => flag ? FlowStream : Observable.Never<(long, float)>())
.Switch();
So each time IsStreamOn produces a true you start getting values from FlowStream, otherwise the values stop.
This assumes that FlowStream is hot. If not, do this:
IObservable<(long, float)> outputStream =
FlowStream
.Publish(fs =>
IsStreamOn
.Select(flag => flag ? fs : Observable.Never<(long, float)>())
.Switch());
Here's a simple test:
void Main()
{
IObservable<long> outputStream =
FlowStream
.Publish(fs =>
IsStreamOn
.Select(flag => flag ? fs : Observable.Never<long>())
.Switch());
using (outputStream.Subscribe(Console.WriteLine))
{
IsStreamOn.OnNext(true);
Thread.Sleep(TimeSpan.FromSeconds(2.5));
IsStreamOn.OnNext(false);
Thread.Sleep(TimeSpan.FromSeconds(3.0));
IsStreamOn.OnNext(true);
Thread.Sleep(TimeSpan.FromSeconds(3.0));
}
}
IObservable<long> FlowStream = Observable.Interval(TimeSpan.FromSeconds(1.0));
Subject<bool> IsStreamOn = new Subject<bool>();
This produces:
0
1
5
6
7
Given the comments re actually calling .Start() and .Stop() then try something like this:
IObservable<(long, float)> outputStream =
Observable
.Create<(long, float)>(o =>
{
var stream = GetStream();
return
FlowStream
.Publish(fs =>
IsStreamOn
.Do(flag => { if (flag) stream.Start(); else stream.Stop(); })
.Select(flag => flag ? fs : Observable.Never<(long, float)>())
.Switch())
.Subscribe(o);
});
In these scenarios with your observables I tend to do
var canSwitchOn = this.WhenAnyValue(x => x.IsStreamOn).Select(_ => Unit.Default);
That will allow you not to have the bool passed along to the command.
oh also you may want a where() clause in this cause if you want to trigger a command in the right condition.
eg.
var switchOn = this.WhenAnyValue(x => x.IsStreamOn).Where(x => x).Select(_ => Unit.Default);
var switchOff = this.WhenAnyValue(x => x.IsStreamOn).Where(x => !x).Select(_ => Unit.Default);