Как получить доступ к экземпляру области в том же потоке, который был создан в .NET (Xamarin-UWP)?

#c# #xamarin #uwp #realm #synchronizationcontext

Вопрос:

Я работаю над переходом с SQLite/WebAPIs на Realms в приложении в формах Xamarin.

Это приложение управляет службой обмена сообщениями (чат через SignalR).

Проблема, которая возникла, заключается в том, что при получении сообщения, которое я пытаюсь сохранить в базе данных, приложение неожиданно выходит из строя. (Вопрос, которого не было с SQLite).

Я получаю знаменитую ошибку: область, доступ к которой осуществляется неправильно, точно, когда 3-е или 4-е сообщение пытается вставить, было немного сложно увидеть точный момент.

Как я мог прочитать, как в вопросах прямо здесь, на Stackoverflow, так и в GitHub области Dot-Net. доступ к экземпляру должен осуществляться в том же потоке, в котором он был создан.

Как они предполагают, один из способов добиться этого-использовать правильный контекст синхронизации через AsyncContext.Run Nito.AsyncEx Стивена Клири или Device.BeginInvokeOnMainThread .

Я задаю этот вопрос, потому что, к сожалению, я занимаюсь темой потоков и задач на базовом уровне, каким образом я должен подходить к предыдущим предложениям в своем коде? или что я должен правильно настроить, чтобы получить доступ к потоку, в котором он был создан?

Это мой код:

 LobbyViewModel
public LobbyViewModel()
{
     ChatService.OnReceivePrivateMessage  = ChatService_OnReceivePrivateMessage;
}

private async void ChatService_OnReceivePrivateMessage(object sender, MessageEventArgs args)
{
    await SendMessage(…);
}

private async Task SendMessage(…)
{
    await UpdateMetaData(…);
}

public async Task UpdateMetaData(…)
{
    await ManagerService.InsertMetaDataChatAsync(metaDataChat);
}

ManagerService
public async Task InsertMetaDataChatAsync (MetaDataChatModel MetaDataChatModel)
{

    IMetaDataChatServices MetaDataChatServices = App.AppContainer.Resolve<IMetaDataChatServices>();

    IResponse DataResult = (await MetaDataChatServices.Insert(MetaDataChatModel));

}

Repository
public async Task<IResponse> CreateAsync(MetaDataChatModel MetaDataChatModel)
        {
            MetaDataChatModel.Id = Guid.NewGuid().ToString();
            MetaDataChatModel.Partition = _realmManager.projectPartition;

            var MetaDataChatDto = MetaDataChatModel.ToDto();

            var realmInstance = await _realmManager.GetInstanceAsync();
            if (realmInstance == null)
                return new Response(false, "Realm instance can't be null");

            await realmInstance.WriteAsync(realm =>
            {
                realm.Add(MetaDataChatDto, false);
            });

            return new Response(true);
        }
        
RealmManager
public RealmManager()
{
    RealmApp = App.Create(appId);
    //DataBase = Realms.Realm.GetInstance(syncConfig);
}

public Task<Realms.Realm> GetInstanceAsync()
{
    return Realms.Realm.GetInstanceAsync(syncConfig);
}

public async Task RealmLogInAsync()
{
    if (RealmApp.CurrentUser == null)
    {
        User user = await RealmApp.
        LogInAsync(Credentials.EmailPassword("email", "password"));

        if (user == null)
        {
            return;
        }
    }

    projectPartition = $"project={RealmApp.CurrentUser.Id}";
    syncConfig = new SyncConfiguration(projectPartition, RealmApp.CurrentUser);
}

public async Task RealmLogOutAsync()
{
    if (RealmApp != null amp;amp; RealmApp.CurrentUser!=null)
    {
        await RealmApp.CurrentUser?.LogOutAsync();
    }
}
 

Комментарии:

1. Привет @Ivanrlg ваш код немного сбивает с толку. Можете ли вы выделить в своем фрагменте кода, в какой момент вы получаете исключение?

2. ПРИВЕТ @papafe Я пытаюсь немного привести его в порядок. исключение происходит здесь: public async Task <IResponse> CreateAsync (MetaDataChatModel MetaDataChatModel) . Я думаю, что в какой-то момент он не закончил вставку, когда вставляется другой поток, и происходит сбой.

3. @ Ivanrlg, просто чтобы убедиться, что у CreateAsync тебя есть realm.Add(MetaDataChatDto) . Это на самом деле realmInstance.Add(MetaDataChatDto) или я что-то упускаю?

4. Привет @papafe, это риэлм. Добавить(МетаДатаЧатьДто, ложь);. используйте область внутри. ссылка отсюда: [ссылка] docs.mongodb.com/realm-legacy/docs/dotnet/latest/api/reference/…

5. ах да, извините, я неправильно понял, мой плохой! 🙂