Вторая операция началась в этом контексте до завершения предыдущей асинхронной операции. Используйте «ожидание», чтобы убедиться, что все асинхронные операции завершены, прежде чем вызывать другой метод в этом контексте. Любые члены экземпляра не гарантируют потокобезопасность.
Мой код единицы работы
public class UnitOfWork : IUnitOfWork
{
private readonly CAMSDbEntities _context;
private bool _disposed;
public Dictionary<Type, object> repositories = new Dictionary<Type, object>();
private Guid _objectId;
public UnitOfWork(IContextFactory contextFactory)
{
_context = contextFactory.DbContext as CAMSDbEntities;
_objectId = Guid.NewGuid();
}
public IGenericRepository<T> Repository<T>() where T : class
{
if (repositories.Keys.Contains(typeof(T)) == true)
{
return repositories[typeof(T)] as GenericRepository<T>;
}
GenericRepository<T> repo = new GenericRepository<T>(_context);
repositories.Add(typeof(T), repo);
return repo;
}
Моя конфигурация Unity
container.RegisterType<IHttpContext, HttpContextObject>();
container.RegisterType<IDataBaseManager, DataBaseManager>();
container.RegisterType<IContextFactory, ContextFactory>();
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<>));
container.RegisterType<IUnitOfWork, UnitOfWork>();
container.RegisterType<IAnalytics, DashbordService>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
Контроллер веб-API
public class DashbordController : ApiController
{
private static IAnalytics _analytics;
public DashbordController(IAnalytics dashbordService)
{
_analytics = dashbordService;
}
[HttpGet]
[Route("GetStudentAssessmentHistory")]
public IHttpActionResult GetStudentAssessmentHistory(int studentID)
{
var result = _analytics.GetStudentAssessmentHistoryGraphData(studentID);
return Ok(result);
}
[HttpGet]
[Route("GetStudentFeePaymentHistory")]
public async Task<IHttpActionResult> GetStudentFeePaymentData(int studentID)
{
var result = await _analytics.GetStudentFeePaymentData(studentID);
return Ok(result);
}
[HttpGet]
[Route("GetLedgerHitoryByDepartment")]
public async Task<IHttpActionResult> GetLedgerHitoryByDepartment(int schoolID, int departmentId)
{
var result = await _analytics.GetLedgerHitory(schoolID, departmentId);
return Ok(result);
}
[HttpGet]
[Route("GetLedgerExpenseTrendByDepartment")]
public async Task<IHttpActionResult> GetLedgerExpenseTrendByDepartment(int schoolID)
{
var result = await _analytics.GetLedgerExpenseTrend(schoolID);
return Ok(result);
}
код службы панели управления
public async Task<List<LedgerExpense>> GetLedgerExpenseTrend(int schoolId)
{
try
{
var ledgerExpenses = new List<LedgerExpense>();
var currentDate = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, INDIAN_ZONE);
DateTime previoYearDate = currentDate.AddYears(-1);
var ledgerPayments = await _unitOfWork.Repository<LedgerDetail>().GetManyAsync(x => x.SchoolID == schoolId && x.PaymentDate <= currentDate
&& x.PaymentDate >= previoYearDate);
foreach (var ledgerPayment in ledgerPayments.OrderBy(x => x.PaymentDate).GroupBy(y => y.DepartmentID))
{
var department = await _unitOfWork.Repository<DeptartmentType>().GetAsync(x => x.ID == ledgerPayment.Key);
var ledgerData = new LedgerExpense
{
Department = department.DepartmentName,
TotalLedgerExpense = 0
};
foreach (var departmentPayment in ledgerPayment)
{
ledgerData.TotalLedgerExpense += departmentPayment.TotalPaidAmount;
}
ledgerExpenses.Add(ledgerData);
}
return ledgerExpenses;
}
catch (Exception ex)
{
logger.Log("An error occurred while fetching ledger expenses");
return null;
}
}
У меня есть аналогичный тип асинхронных методов, реализованных в моем коде службы приборной панели. всякий раз, когда я запрашиваю пользовательский интерфейс панели управления, все запросы одновременно поступают на один и тот же контроллер и создают новый объект для unitofwork и dbcontext для каждого запроса один за другим. иногда это работает отлично, но иногда я думаю, что объект unitofwork и dbcontext перетекает с неправильным потоком и выдает эту ошибку. Я думаю, что каким-то образом он выбирает неправильный dbcontext, который уже занят каким-то другим запросом API от службы панели инструментов.
repositories.Keys.Contains()
. Это то, что вы должны оставить в контейнере DI или просто использовать одноразовые. - person Henk Holterman   schedule 09.04.2018