问题
I've started getting these errors. It was working perfectly on my previous server.
using System;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Threading.BackgroundWorkers;
using EMS.IPs;
using System.Threading.Tasks.Dataflow;
using System.Threading.Tasks;
using System.Linq;
using EMS.Contacts;
using System.Collections.Concurrent;
using Abp.Domain.Uow;
using System.Collections.Generic;
using EMS.EmailValidation;
using Microsoft.AspNetCore.SignalR;
using KellermanSoftware.NetEmailValidation;
using System.Net;
using System.Collections;
using System.Threading;
using System.ComponentModel;
using System.Transactions;
namespace EMS.BackgroundWorkers
{
public class ContactValidationBackgroundWorker : BackgroundWorkerBase, ITransientDependency
{
private readonly IRepository<IP> _ipsRepository;
private readonly IRepository<Contact> _contactsRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IUnitOfWorkManager _unitOfWorkManager2;
private readonly IRepository<Contact> _contactRepository;
private BackgroundWorker bgworker = new BackgroundWorker();
ActionBlock<ValidationObject> workerBlock;
public ContactValidationBackgroundWorker(
IRepository<IP> ipsRepository,
IRepository<Contact> contactsRepository,
IUnitOfWorkManager unitOfWorkManager,
IUnitOfWorkManager unitOfWorkManager2,
IRepository<Contact> contactRepository)
{
_ipsRepository = ipsRepository;
_contactsRepository = contactsRepository;
_unitOfWorkManager = unitOfWorkManager;
_unitOfWorkManager2 = unitOfWorkManager2;
_contactRepository = contactRepository;
bgworker.DoWork += Worker;
}
public override void Start()
{
base.Start();
bgworker.RunWorkerAsync();
}
public override void Stop()
{
bgworker.DoWork -= Worker;
}
public void Worker(object sender, DoWorkEventArgs e)
{
using (var unitOfWork = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
{
var contacts = _contactsRepository.GetAll().Where(x => !x.IsChecked);
if (!contacts.Any())
{
Logger.Debug("No contacts");
return;
}
workerBlock = new ActionBlock<ValidationObject>(
async (arg) => await Validate(arg),
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 5
});
foreach (var contact in contacts)
{
workerBlock.Post(new ValidationObject()
{
Contact = contact
});
}
unitOfWork.Complete();
}
Logger.Debug("End posting jobs to threads. Awaits results...");
workerBlock.Complete();
workerBlock.Completion.Wait();
}
public override void WaitToStop()
{
base.WaitToStop();
}
private async Task Validate(ValidationObject validationObject)
{
try
{
using (var contactUnitOfWork = _unitOfWorkManager2.Begin(TransactionScopeOption.RequiresNew))
{
Contact contact = validationObject.Contact;
contact.IsChecked = true;
await _contactRepository.UpdateAsync(contact);
await contactUnitOfWork.CompleteAsync();
}
} catch (Exception ex) {
Logger.Error(ex.ToString());
throw;
}
}
}
public class ValidationResult
{
public ValidationResult()
{
IsValid = false;
Message = "";
}
public string Message { get; set; }
public bool IsValid { get; set; }
}
public class ValidationObject
{
public Contact Contact { get; set; }
}
}
It works inside background worker; it worked before. Now it doesn't. Contact
object is not null.
It seems to ask me to add unitOfWork
parameter to Update
method. Please help me figure this out.
ERROR 2017-12-26 12:02:34,768 [14 ] orkers.ContactValidationBackgroundWorker - System.ArgumentNullException: Value cannot be null.
Parameter name: unitOfWork
at Abp.EntityFrameworkCore.Uow.UnitOfWorkExtensions.GetDbContext[TDbContext](IActiveUnitOfWork unitOfWork, Nullable`1 multiTenancySide)
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.Update(TEntity entity)
at Castle.Proxies.Invocations.IRepository`2_Update_8.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.IRepository`1Proxy_3.Update(Contact entity)
at EMS.BackgroundWorkers.ContactValidationBackgroundWorker.<Validate>d__21.MoveNext() in /Users/grinay/Projects/EMSBackend/src/EMS.Application/BackgroundWorkers/ContactValidationBackgroundWorker.cs:line 329
UPDATE1
ERROR 2017-12-27 05:31:34,500 [9 ] orkers.ContactValidationBackgroundWorker - System.ArgumentNullException: Value cannot be null.
Parameter name: unitOfWork
at Abp.EntityFrameworkCore.Uow.UnitOfWorkExtensions.GetDbContext[TDbContext](IActiveUnitOfWork unitOfWork, Nullable`1 multiTenancySide)
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.UpdateAsync(TEntity entity)
at Castle.Proxies.Invocations.IRepository`2_UpdateAsync_8.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformAsyncUow(IInvocation invocation, UnitOfWorkOptions options)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.IRepository`1Proxy_3.UpdateAsync(Contact entity)
at EMS.BackgroundWorkers.ContactValidationBackgroundWorker.<>c__DisplayClass23_0.<<Validate>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task)
at Nito.AsyncEx.AsyncContext.Run(Func`1 action)
at EMS.BackgroundWorkers.ContactValidationBackgroundWorker.Validate(ValidationObject validationObject)
回答1:
You cannot use async
methods with unitOfWork
like that in background worker.
Make the changes in these 5 lines:
public void Worker(object sender, DoWorkEventArgs e)
{
// ...
workerBlock = new ActionBlock<ValidationObject>(
(arg) => Validate(arg), // This line #1
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 5
});
// ...
}
private void Validate(ValidationObject validationObject) // This line #2
{
try
{
using (var contactUnitOfWork = _unitOfWorkManager2.Begin(TransactionScopeOption.RequiresNew))
{
Contact contact = validationObject.Contact;
contact.IsChecked = true;
AsyncHelper.RunSync(async () => // This line #3
{ // This line #4
await _contactRepository.UpdateAsync(contact);
await contactUnitOfWork.CompleteAsync();
}); // This line #5
}
} catch (Exception ex) {
Logger.Error(ex.ToString());
throw;
}
}
来源:https://stackoverflow.com/questions/47978448/unitofwork-parameter-cannot-be-null-in-background-worker