Hi Guys,
We're working on a function that needs to create or update records across 4 different entities.
When running each CreateOrEdit method synchronously we were receiving an "Existing task is running on the same context" error, and when running each CreateOrEdit method asynchronously, the DB context gets disposed of after the completion of the first method, thus raising "DBcontext disposed of" errors in the subsequent method calls.
We have tried implementing different unit of work methods around the CreateOrEdit method calls, to varying degrees of success, but really need all of the methods to operate under a single transaction, as all are required to succeed in order to continue.
If anyone has worked with a scenario like this before and can explain how to make this work or if there is a direction we can be pointed in, any help would be greatly appreciated.
8 Answer(s)
-
0
Can you show the code for both "synchronously" and "asynchronously"?
-
0
Running the functions synchronously
_recordsFolderManager.CreateOrEditFolder(NewFolder); _recordManager.CreateOrEditRecord(NewRecord); _recordManager.CreateOrEditRecordMatter(NewRecordMatter); _recordManager.CreateOrEditRecordMatterItem(NewRecordMatterItem);
Running the functions asynchronously
await _recordsFolderManager.CreateOrEditFolder(NewFolder); await _recordManager.CreateOrEditRecord(NewRecord); await _recordManager.CreateOrEditRecordMatter(NewRecordMatter); await _recordManager.CreateOrEditRecordMatterItem(NewRecordMatterItem);
We're also tried runnning the functions in a new unit of work
using (var unitOfWork = _unitOfWorkManager.Begin()) { await _recordsFolderManager.CreateOrEditFolder(NewFolder); await _recordManager.CreateOrEditRecord(NewRecord); await _recordManager.CreateOrEditRecordMatter(NewRecordMatter); await _recordManager.CreateOrEditRecordMatterItem(NewRecordMatterItem); unitOfWork.Complete(); }
-
0
If CreateOrEditFolder etc. are async, then you have to await them. Not putting await doesn't mean you run them synchronously. It means you don't wait for it to finish executing before starting another, which causes the "Existing task is running on the same context" error.
Can you show the implementation of one of those methods?
-
0
Hi Aaron
Thanks for the clarification around async awaiting.
Here is the code we're currently trying to execute our functions from within:
using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew)) { NewRecord = _recordRepository.Get(Guid.Parse(RecordID)); await CreateOrEditRecord(NewRecord); await _unitOfWorkManager.Current.SaveChangesAsync(); NewRecordMatter = _recordMatterRepository.Get(Guid.Parse(RecordMatterID)); await CreateOrEditRecordMatter(NewRecordMatter); await _unitOfWorkManager.Current.SaveChangesAsync(); await uow.CompleteAsync(); }
Here is one of the functions sets that get called. Each of the function sets follows the same pattern as this one.
public async Task CreateOrEditRecord(Record Record) { if (Record.Id == null || !_recordRepository.GetAll().Any(i => i.Id == Record.Id)) { await CreateRecord(Record); } else { await UpdateRecord(Record); } } [AbpAuthorize(AppPermissions.Pages_Records_Create)] private async Task CreateRecord(Record Record) { await _recordRepository.InsertAsync(Record); } [AbpAuthorize(AppPermissions.Pages_Records_Edit)] private async Task UpdateRecord(Record Record) { var record = await _recordRepository.FirstOrDefaultAsync((Guid)Record.Id); ObjectMapper.Map(Record, record); }
The current UOW seems to get closed when returning from CreateOrEditRecord(), which disrupts the subsequent actions shown in the top code block.
-
0
Can you show the stack trace?
-
0
Here is the stack trace info in question:
{System.NullReferenceException: Object reference not set to an instance of an object. at Syntaq.Falcon.Documents.DocumentsAppService.Automate(Object JSONObject) in D:\Source\Syntaq.Falcon\src\Syntaq.Falcon.Application\Documents\DocumentsAppService.cs:line 88}
The null object is the _unitOfWorkManager.Current.
Line 88 is marked below:
84: using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew)) 85: { 86: NewRecord = _recordRepository.Get(Guid.Parse(RecordID)); 87: await CreateOrEditRecord(NewRecord); 88: await _unitOfWorkManager.Current.SaveChangesAsync();
-
0
Try to put [UnitOfWork(IsDisabled = true)] attribute before you method. It will disable any other unit of work.
-
0
make your methods virtual and add [UnitOfWork] attribute to them.