Решение этой проблемы было найдено в этом Github посте
Кусок кода, который помог мне решить проблему
Realm GetInstanceWithoutCapturingContext(RealmConfiguration config)
{
var context = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
Realm realm = null;
try
{
realm = Realm.GetInstance(config);
}
finally
{
SynchronizationContext.SetSynchronizationContext(context);
}
return realm;
}
Хотя мне потребовалось некоторое время, чтобы применить это к моему решению.
Прежде всего, вместо установки контекста на null
я использую Nito.AsyncEx.AsyncContext. Потому что в противном случае автоматические изменения не будут распространяться через потоки, так как для этой функции для области требуется ненулевое значение SynchronizationContext
. Итак, в моем случае метод выглядит примерно так:
public class MockRealmFactory : IRealmFactory
{
private readonly SynchronizationContext _synchronizationContext;
private readonly string _defaultDatabaseId;
public MockRealmFactory()
{
_synchronizationContext = new AsyncContext().SynchronizationContext;
_defaultDatabaseId = Guid.NewGuid().ToString();
}
public Realm GetRealmWithPath(string realmDbPath)
{
var context = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(_synchronizationContext);
Realm realm;
try
{
realm = Realm.GetInstance(new InMemoryConfiguration(realmDbPath));
}
finally
{
SynchronizationContext.SetSynchronizationContext(context);
}
return realm;
}
}
Кроме того, исправлено множество неудачных юнит-тестов. Но я все еще получал то же исключение - доступ к Realm из неправильного потока. И я понятия не имел, почему, потому что все было установлено правильно. Затем я обнаружил, что неудачные тесты были связаны с методами, в которых я использовал async realm api, в частности realm.WriteAsync
. После еще нескольких копаний я нашел следующие строки в документации по области.
Это не проблема, если вы установили SynchronisationContext.Current
, но
это приведет к повторной отправке WriteAsync в пул потоков, который
может создать другой рабочий поток. Итак, если вы используете Current
в вашем
темы, рассмотрите возможность вызова только Write
вместо WriteAsync
.
В моем коде не было прямой необходимости использовать асинхронный API. Я удалил и заменил на sync Write
, и все тесты снова стали зелеными! Я полагаю, что если я окажусь в ситуации, когда мне нужно будет использовать асинхронный API из-за каких-то массовых вставок, я бы либо высмеял этот конкретный API, либо заменил бы своим собственным фоновым потоком, используя Task.Run
вместо использования Realm версия.