Is there someting like Dispatcher.CheckAccess() when using Scheduler - system.reactive

I want to do the equivalent of:
if (dispatcher.CheckAccess())
{
// invoke synchronously if we are on the dispatcher thread
collectionChangedEventHandler(this, args);
}
else
{
dispatcher.BeginInvoke(new Action(() => collectionChangedEventHandler(this, args)));
}
I have not found a way to do this using an IScheduler.
Pseudo code for what I want:
if (scheduler.CheckAccess())
{
collectionChangeEventHandler(sender, args);
}
else
{
scheduler.Schedule(() => collectionChangeEventHandler(sender, args));
}
There is CurrentThreadScheduler.ScheduleRequired that looks promising but the documentation is sparse.

No, but you can write your own CheckAccessDispatcherScheduler that decorates DispatcherScheduler.
https://github.com/Reactive-Extensions/Rx.NET/blob/master/Rx.NET/Source/System.Reactive.Windows.Threading/Reactive/Concurrency/DispatcherScheduler.cs
class CheckAccessDispatcherScheduler : LocalScheduler, ISchedulerPeriodic
{
...
public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
if (decoratedDispatcher.Dispatcher.CheckAccess())
{
action(this, state, Disposable.Empty);
return Disposable.Empty;
}
else
{
return decoratedDispatcher.Schedule(state, action);
}
}
...
}

Related

Unity Crash. What causes QObject: Cannot create children for a parent that is in a different thread?

Specs: Unity 2021.3.16/17, MacOS, Android/iOS. I use the rest client plugin with RSG IPromise. Often unity crashes when executing debug.log in the promise resolved callback.
public abstract class ProcedureStep<T> : AbstractProcedureStep, IProcedureStep<T>
{
IPromise<T> IProcedureStep<T>.Run(T context)
{
return new Promise<T>((resolve, reject) =>
{
Run(context).Then(result =>
{
try
{
OnResolve();
resolve(result);
}
catch (Exception e)
{
OnReject(e);
reject(e);
}
}).Catch(e =>
{
OnReject(e);
reject(e);
});
});
}
protected abstract IPromise<T> Run(T context);
protected virtual void OnResolve()
{
//unity crash!!!
//"QObject: Cannot create children for a parent that is in a different thread"
Debug.Log("success");
}
protected virtual void OnReject(Exception e)
{
Debug.LogError(e);
}
}
I found this post forum.gt.iobut i couldn't apply it for my case.

VertX JUnit 5 MongoDB test does not complete (TimeoutException) or completes too early (testContext.awaitCompletion not working)

Background:
During migration from JUnit4 to JUnit5 using VertX I read the migration guides which explain:
how to use the changed Promise and Future Vertx interfaces
how to VertxTestContext, Vertx auto-injection in Vertx Tests
how to use testContext.awaitCondition(), textContext.completing(), testContext.completeNow() etc.
Having this information in mind I wrote the following test:
Test Code:
import io.vertx.core.Promise;
import io.vertx.core.Future;
#ExtendWith(VertxExtension.class)
class RestApiTest {
#BeforeAll
static void setUpMongoDatabase() throws IOException {
(...)
}
#BeforeEach
void setUp(Vertx vertx, VertxTestContext ctx) {
vertx.deployVerticle(ApiVerticle.class.getName(), options, ctx.completing());
return WebClient.create(vertx);
}
#AfterEach
void tearDown(Vertx vertx, VertxTestContext testContext) {
assertThat(vertx.deploymentIDs().size(), is(equalTo(2)));
}
#AfterAll
static void stopMongoDatabase() {
(...)
}
#Test
void test(Vertx vertx, VertxTestContext testContext) {
Future<Void> insertFuture = insertTestData();
future.setHandler(testContext.completing());
// This ether throws a TimeoutException or does not block until the insert completed
testContext.awaitCompletion(5, TimeUnit.SECONDS);
// assert
mongoClient.findOne(COLLECTION, QUERY, result -> {
if (result.succeeded()) testContext.completeNow();
else testContext.failNow();
});
}
Future<Void> insertTestData() {
Promise<Void> promise = Promise.promise();
Future<Void> future = promise.future();
mongoClient.insert(COLLECTION, QUERY, result -> {
if (result.succeeded()) {
promise.complete();
} else {
promise.fail();
}
});
return future;
}
}
Problem:
testContext.awaitCompletion() ether throws a TimeoutException
or does not block until the async insert completed so that my assert returns successfully
Question:
How can I wait for the async mongo query to complete before I continue with my test?
The problem was that I am using the VertX Promise and Future classes:
those classes only work on a VertX Verticle
my insertTestData() method is not executed on a Verticle
One solution is to use the java.util.concurrent.ReentrantLock and Condition classes instead:
#Test
void test() {
insertTestData(); // This is now synchronous as required
// assert
mongoClient.findOne(COLLECTION, QUERY, result -> {
if (result.succeeded()) testContext.completeNow();
else testContext.failNow();
});
}
void insertTestData() {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
mongoClient.insert(COLLECTION, QUERY, result -> {
if (result.succeeded()) {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
} else {
fail();
}
});
lock.lock();
try {
condition.await(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
} finally {
lock.unlock();
}
}
}

ABP EF Core multiple DbContext access in IDomainService throws transaction error

The specified transaction is not associated with the current connection. Only transactions associated with the current connection may be used.
How do I use multiple DbContext in one transaction?
Update 1
If I use ExistingConnection,
then all the DbContext will use the same connection string.
Did I add multiple DbContext in the wrong way?
In EntityFrameworkModule:
public override void PreInitialize()
{
var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder());
Configuration.Modules.AbpEfCore().AddDbContext<BPDbContext>(options =>
{
if (options.ExistingConnection != null)
{
options.DbContextOptions.UseSqlServer(options.ExistingConnection);
}
else
{
options.DbContextOptions.UseSqlServer(configuration.GetConnectionString(ABPCoreConsts.BPConnectionStringName));
}
//options.DbContextOptions.UseSqlServer(
// configuration.GetConnectionString(ABPCoreConsts.BPConnectionStringName));
});
Configuration.Modules.AbpEfCore().AddDbContext<EPlusDBConext>(options =>
{
if (options.ExistingConnection != null)
{
options.DbContextOptions.UseSqlServer(options.ExistingConnection);
}
else
{
options.DbContextOptions.UseSqlServer(configuration.GetConnectionString(ABPCoreConsts.EECPlusConnectionStringName));
}
//options.DbContextOptions.UseSqlServer(
// configuration.GetConnectionString(ABPCoreConsts.EECPlusConnectionStringName));
});
Configuration.Modules.AbpEfCore().AddDbContext<ProjectManageDbContext>(options =>
{
if (options.ExistingConnection != null)
{
options.DbContextOptions.UseSqlServer(options.ExistingConnection);
}
else
{
options.DbContextOptions.UseSqlServer(configuration.GetConnectionString(ABPCoreConsts.PMConnectionStringName));
}
//options.DbContextOptions.UseSqlServer(
// configuration.GetConnectionString(ABPCoreConsts.PMConnectionStringName));
});
RegisterGenericRepositories();
}
Update 2
I got it to work by implementing IConnectionStringResolver for custom connections:
public class MyDBConnectionStringResolver : DefaultConnectionStringResolver
{
public override string GetNameOrConnectionString(ConnectionStringResolveArgs args)
{
var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder());
switch (args["DbContextType"].ToString())
{
case "ABPCore.EPlusDBConext":
return configuration.GetConnectionString(ABPCoreConsts.EECPlusConnectionStringName);
case "ABPCore.BPDbContext":
return configuration.GetConnectionString(ABPCoreConsts.BPConnectionStringName);
case "ABPCore.ProjectManageDbContext":
return configuration.GetConnectionString(ABPCoreConsts.PMConnectionStringName);
}
return string.Empty;
}
}
Don't forget to replace service in EntityFrameworkModule's PreInitialize method:
Configuration.ReplaceService<IConnectionStringResolver, MyDbConnectionStringResolver>(DependencyLifeStyle.Transient);
Add this in *DbContextConfigurer.cs:
public static void Configure(DbContextOptionsBuilder<*DbContext> builder, DbConnection connection)
{
builder.UseSqlServer(connection);
}
Change this in *EntityFrameworkModule.cs:
public override void PreInitialize()
{
if (!SkipDbContextRegistration)
{
Configuration.Modules.AbpEfCore().AddDbContext<*DbContext>(options =>
{
if (options.ExistingConnection != null)
{
options.DbContextOptions.UseSqlServer(options.ExistingConnection);
}
else
{
options.DbContextOptions.UseSqlServer(options.ConnectionString);
}
});
}
}
Reference: https://github.com/aspnetboilerplate/module-zero-core-template/commit/da522e76ca2ecefdb7670f009f78575c5b97b4a0
Important
If each DbContext has its own connection string, you need to implement IConnectionStringResolver as explained here and replace the service:
Configuration.ReplaceService<IConnectionStringResolver, MyConnectionStringResolver>(DependencyLifeStyle.Transient);

Replacement of BsonBaseSerializer in MongoDB driver v2.4.0

We have migrated MongoDB drivers from v1.9.3 to v2.4.0. we have used BsonBaseSerializer, which does not exists in v2.4.0. what is the replacement of BsonBaseSerializer in v2.4.0?
There's not really enough of a question to give a full answer to, but the change you're looking for is documented under serialization in the mongo docs.
http://mongodb.github.io/mongo-csharp-driver/2.4/reference/bson/serialization/#implementation-1
The biggest change being that they take a type now on the base class.
So
V1 Driver code
public class IntegerCoercion : BsonBaseSerializer
{
public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
{
if (bsonReader.CurrentBsonType == BsonType.Int32)
{
return bsonReader.ReadInt32();
}
if (bsonReader.CurrentBsonType == BsonType.String)
{
var value = bsonReader.ReadString();
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
return Convert.ToInt32(value);
}
bsonReader.SkipValue();
return null;
}
public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
if (value == null)
{
bsonWriter.WriteNull();
return;
}
bsonWriter.WriteInt32(Convert.ToInt32(value));
}
}
V2 Driver Code
public class IntegerCoercion : SerializerBase<object>
{
public override object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
if (context.Reader.CurrentBsonType == BsonType.Int32)
{
return context.Reader.ReadInt32();
}
if (context.Reader.CurrentBsonType == BsonType.String)
{
var value = context.Reader.ReadString();
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
return Convert.ToInt32(value);
}
context.Reader.SkipValue();
return null;
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
if (value == null)
{
context.Writer.WriteNull();
return;
}
context.Writer.WriteInt32(Convert.ToInt32(value));
}
}
Not a huge difference but as with most of the driver changes they're minimal but breaking.

Interface analog in Swift for callbacks realization

Please, help me to make interface in Swift to use it for callbacks purposes.
Example in Java:
public interface ErrorListener {
void onError(String errorMsg);
}
class SomeUiClass implements ErrorListener {
public SomeUiClass () {
SomeWorkingClass s = new SomeWorkingClass();
s.setErrorListener(this);
s.doSomething(true);
}
#Override
void onError(String errorMsg) {
System.out.println("Error msg: " + errorMsg);
}
}
class SomeWorkingClass {
ErrorListener listener;
void setErrorListener (ErrorListener listener) {
this.listener = listener;
}
void doSomething (boolean withError) {
if (withError) listener.onError("Test error");
}
}
//....
SomeUiClass ui = new SomeUiClass(); // prints: Error msg: Test error
So, I tried to use protocol in Swift for this purpose, but I didn't understand, how to use it properly.
It would look like this in swift
protocol ErrorListener {
func onError(errorMsg:String)
}
class SomeUiClass : UIViewController , ErrorListener {
func onError(errorMsg:String)
print("Error msg: ", errorMsg)
}
}
class SomeWorkingClass : UIViewController{
weak var listener:ErrorListener?
func setErrorListener (listener:ErrorListener) {
self.listener = listener
}
}
let ui = SomeUiClass() // prints: Error msg: Test error