Support forum for ASP.NET Zero (https://aspnetzero.com/).
User avatar
By DavidHarrison
#31537 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.
User avatar
By DavidHarrison
#31563 Running the functions synchronously
Code: Select all_recordsFolderManager.CreateOrEditFolder(NewFolder);
_recordManager.CreateOrEditRecord(NewRecord);
_recordManager.CreateOrEditRecordMatter(NewRecordMatter);
_recordManager.CreateOrEditRecordMatterItem(NewRecordMatterItem);


Running the functions asynchronously
Code: Select allawait _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
Code: Select all   using (var unitOfWork = _unitOfWorkManager.Begin())
                {
                    await _recordsFolderManager.CreateOrEditFolder(NewFolder);
                    await _recordManager.CreateOrEditRecord(NewRecord);
                    await _recordManager.CreateOrEditRecordMatter(NewRecordMatter);
                    await _recordManager.CreateOrEditRecordMatterItem(NewRecordMatterItem);
                    unitOfWork.Complete();
                }
User avatar
By aaron
#31564 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?
User avatar
By DavidHarrison
#31566 Hi Aaron

Thanks for the clarification around async awaiting.

Here is the code we're currently trying to execute our functions from within:
Code: Select all  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.
Code: Select all        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.
User avatar
By DavidHarrison
#31570 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:
Code: Select all               
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();