在先前的异步操作通过UnitofWork和async完成之前,第二个操作在此上下文上开始 [英] A second operation started on this context before a previous asynchronous operation completed with UnitofWork and async

查看:147
本文介绍了在先前的异步操作通过UnitofWork和async完成之前,第二个操作在此上下文上开始的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在先前的异步操作完成之前,第二个操作在此上下文上开始.使用"await"来确保在此上下文上调用另一个方法之前,所有异步操作都已完成.不保证任何实例成员都是线程安全的.

A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.

我的工作单位代码

 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;
        }

我的统一配置

      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);

webApi控制器

 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;
            }
        }

我在我的仪表板服务代码中实现了类似类型的异步方法.每当我请求仪表板UI时,所有请求都同时到达同一控制器,并为每个请求一个一个地为unitofwork和dbcontext创建新对象.它有时工作完美,但有时我认为unitofwork和dbcontext对象使用错误的线程流动并引发此错误.我认为它以某种方式选择了错误的dbcontext,而该上下文已经忙于来自仪表板服务的其他api请求.

I have similar type of asynchronous metods implemented in my dashboardservice code. whenever I request a dashboard UI all request comes to the same controller at the same time and creates the new object for unitofwork and dbcontext for each request one by one. it works perfectly sometimes but Sometimes I think unitofwork and dbcontext object flows with the wrong thread and throws this error. I think somehow its picking wrong dbcontext which is already busy with someother api request from dashboard service.

推荐答案

请从此代码中删除控制器中的static关键字:

Please remove the static keyword in your controller from this code:

private static IAnalytics _analytics;`

一旦创建,就不会再创建它,除非应用程序池被回收(手动或IIS重新启动等).由于您对所有请求都使用相同的实例,因此会随机得到该错误.如果一个请求在下一个请求到达之前完成,它将 NOT 导致错误.否则会的.因此,并非总是得到错误的原因(就像您在问题中提到的那样).

Once that has been created, it will never be created again unless the application pool is recycled (manual or IIS restart etc.) Since you are using the same instance for all requests, you are getting that error at random. If a request finishes before the next one arrives, it will NOT result in an error. Otherwise it will. Hence the reason for not always getting the error (as you mention in your question).

请阅读有关static如何影响Web场景(或服务器)中的设计的信息.

Please read about how static affects the design in a web scenario (or server).

尝试将Web请求视为一个事务,将为每个请求创建所有类,然后在为请求提供服务后将其丢弃.这意味着,如果您具有static或任何其他共享的机制,它将在请求之间共享.

Try and think of web requests as a single transaction, all classes are created for each request and then thrown away after the request has been served. That means if you have static or any other mechanism which is for sharing, it will be shared between requests.

这篇关于在先前的异步操作通过UnitofWork和async完成之前,第二个操作在此上下文上开始的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆