【发布时间】:2020-10-20 18:44:58
【问题描述】:
我正在使用 ASP.NET Core 3.1 中的 SignalR 编写 API。我对 .NET Core 完全陌生,对 SignalR 也很陌生。我在执行事务中运行的 MongoDB (Atlas) 查询时遇到问题。事务会话似乎在查询执行之前到期。我很确定这是 async/await 问题,但似乎无法解决。
我的 Hub 方法如下所示:
public async Task<bool> UpdateProfile(object profileDto)
{
try
{
ProfileDTO profile = ((JsonElement) profileDto).ToObject<ProfileDTO>();
_profile.UpdateProfile(profile);
return true;
}
catch
{
return false;
}
}
_profile.UpdateProfile() 方法看起来像这样:
public void UpdateProfile(ProfileDTO profileDto)
{
_databaseService.ExecuteInTransaction(async session =>
{
var profile = _mapper.Map<ProfileModel>(profileDto);
var existingUser = (await _userCollectionService
.FindAsync(session, user => user.Profille.Sub == profileDto.sub)
).FirstOrDefault();
if (existingUser == null)
{
var newUser = new UserModel();
newUser.Profille = profile;
await _userCollectionService.CreateAsync(session, newUser);
}
else
{
existingUser.Profille = profile;
// the error occurs on the following line
await _userCollectionService.UpdateAsync(session, existingUser.Id, existingUser);
}
});
}
我的ExecuteInTransaction() 方法是尝试泛化事务/会话过程,看起来像这样:
public async void ExecuteInTransaction(DatabaseAction databaseAction)
{
using (var session = await Client.StartSessionAsync())
{
try
{
session.StartTransaction();
databaseAction(session);
await session.CommitTransactionAsync();
}
catch (Exception e)
{
await session.AbortTransactionAsync();
throw e;
}
}
}
我已经在UpdateProfile() 中指出了发生错误的行。完整的错误如下所示:
System.ObjectDisposedException:无法访问已处置的对象。 对象名称:'MongoDB.Driver.Core.Bindings.CoreSessionHandle'。 在 MongoDB.Driver.Core.Bindings.WrappingCoreSession.ThrowIfDisposed() 在 MongoDB.Driver.Core.Bindings.WrappingCoreSession.get_IsInTransaction() 在 MongoDB.Driver.ClientSessionHandle.get_IsInTransaction() 在 MongoDB.Driver.MongoCollectionImpl
1.CreateBulkWriteOperation(IClientSessionHandle session, IEnumerable1 请求,BulkWriteOptions 选项) 在 MongoDB.Driver.MongoCollectionImpl1.BulkWriteAsync(IClientSessionHandle session, IEnumerable1 请求,BulkWriteOptions 选项,CancellationToken cancelToken) 在 MongoDB.Driver.MongoCollectionBase1.ReplaceOneAsync(FilterDefinition1 过滤器,TDocument 替换,ReplaceOptions 选项,Func3 bulkWriteAsync) at IndistinctChatter.API.Services.Business.Profile.<>c__DisplayClass5_0.<<UpdateProfile>b__0>d.MoveNext() in /Volumes/Data/Users/marknorgate/Documents/Development/source/indistinct-chatter/api-dotnet/Services/Business/Profile.cs:line 48 --- End of stack trace from previous location where exception was thrown --- at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__139_1(Object state) at System.Threading.QueueUserWorkItemCallback.<>c.<.cctor>b__6_0(QueueUserWorkItemCallback quwi) at System.Threading.ExecutionContext.RunForThreadPoolUnsafe[TState](ExecutionContext executionContext, Action1 回调,TState& 状态) 在 System.Threading.QueueUserWorkItemCallback.Execute() 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
所以看来session 对象在await _userCollectionService.UpdateAsync(session, existingUser.Id, existingUser); 行执行之前就到期了。 await session.CommitTransactionAsync(); 行首先执行。
我哪里出错了?我觉得Task 来了……
【问题讨论】:
-
将
ExecuteInTransaction更改为async Task并在您的 Hub 方法中等待它。提示:尽可能避免使用async void。旁注,尽量避免在您的 Hub 方法中使用object,您应该能够通过在 Hub 方法签名中接受ProfileDTO来处理丑陋的((JsonElement) profileDto).ToObject<ProfileDTO>();代码。
标签: c# asp.net mongodb async-await signalr