Realm не работает с ядром xUnite и .net - PullRequest
0 голосов
/ 06 апреля 2019

У меня проблемы с управлением областью с ядром xUnite и Net. Вот очень простой тест, который я хочу запустить

public class UnitTest1
    {
        [Scenario]
        public void Test1()
        {
            var realm = Realm.GetInstance(new InMemoryConfiguration("Test123"));
            realm.Write(() =>
                        {
                            realm.Add(new Product());
                        });
            var test = realm.All<Product>().First();
            realm.Write(() => realm.RemoveAll());
        }
    }

Я получаю разные исключения на разных компьютерах (Windows & Mac) в сети, где я пытаюсь создать объект Realm с помощью InMemoryConfiguration. На Mac я получаю следующее исключение

libc++abi.dylib: terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread.

В Windows я получаю следующее исключение при запуске

ERROR Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. at 
System.Net.Sockets.NetworkStream.Read(Span1 destination) at 
System.Net.Sockets.NetworkStream.ReadByte() at 
System.IO.BinaryReader.ReadByte() at 
System.IO.BinaryReader.Read7BitEncodedInt() at 
System.IO.BinaryReader.ReadString() at 
Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.LengthPrefixCommunicationChannel.NotifyDataAvailable() at 
Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TcpClientExtensions.MessageLoopAsync(TcpClient client, ICommunicationChannel channel, Action1 errorHandler, CancellationToken cancellationToken) Source: System.Net.Sockets HResult: -2146232800 Inner Exception: An existing connection was forcibly closed by the remote host HResult: -2147467259

Я использую Realm 3.3.0 и xUnit 2.4.1 Я пытался перейти на Realm 2.2.0, и он тоже не работал.

1 Ответ

0 голосов
/ 08 апреля 2019

Решение этой проблемы было найдено в этом 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 версия.

...