【问题标题】:How to use async methods with Dependency Injection如何在依赖注入中使用异步方法
【发布时间】:2019-11-07 20:59:35
【问题描述】:

我正在开发一个 .net core (2.2) web 应用程序,并且有一个控制器负责按需数据同步处理。同样,我保留了一个单击按钮,单击该按钮会触发对服务的异步方法的调用。

在内部,此服务调用在操作下方处理

  1. 从数据库中获取数据以进行数据同步处理
  2. 将数据分批进行数据同步处理的批处理模式
  3. 为相关批次数据准备数据模型
  4. 将准备好的数据批次发送到目标消息队列

为了从服务内部与数据库交互,使用 IOC / 依赖注入(即通过构造函数)提供了 Db-context 对象。

为了确定问题原因,我使用多种方式进行服务方法调用:

  • 使用 Task.Run() 调用异步方法
  • 在没有 Task.Run() 的情况下调用异步方法
  • 使用 Task.Run() 调用同步方法
  • 使用 ConfigWait(true) 调用异步方法

在所有情况下,结果都没有改变,仍然得到 ObjectDisposedException for DbContext 对象。

在更多地了解 IOC 的范围系统时,在我看来, 响应后,范围正在为 db-context 对象处置 提供给用户。

代码 sn-p 用最少的行表示如下:

AzureSearchIndexController.cs

public class AzureSearchIndexController : Controller
{
   [HttpGet]
   public IActionResult StartIndex()
   {
      _azureSearchDataSyncService.StartIndexingAsync(_siteId, _siteName);
   }
}

AzureSearchDataSyncService.cs

public class AzureSearchDataSyncService : IAzureSearchDataSyncService
{
   public AzureSearchDataSyncService(JobContext context,
            ICacheHandler<AzureSearchDataSyncModel> cacheHandler,
            AzureJobsTopicBus azureJobsTopicBus)
   {
      _context = context;
      _cacheHandler = cacheHandler;
      _azureJobsTopicBus = azureJobsTopicBus;
      azureSearchDataSyncModel = new AzureSearchDataSyncModel();
   }

   public async Task StartIndexingAsync(int siteId, string siteName)
   {
      try
      {
         int fetchedData = 0;
         int _batchSize = 10;
         List<AzureJobMessageModel> azureJobMessages = new List<AzureJobMessageModel>();

         var jobsToAdd_Update= GetData(siteId);
         while (dataSyncModel.SyncStatus && 
            fetchedData < jobsToAdd_Update.Count)
         {
            var batchData = jobsToAdd_Update.Skip(fetchedData)
                          .Take(_batchSize - azureJobMessages.Count)
                          .ToList();
            if (batchData.Count <= 0)
               continue;

            azureJobMessages.AddRange( 
               PrepareAzureJobMessageModel( 
                      PrepareAzureSearchIndexerModel(batchData), 
                  EntityActionEnum.updated)
            );

            fetchedData += batchData.Count();

            if (azureJobMessages.Count >= _batchSize)
            {
               //Method sending batch data
               await _azureJobsTopicBus.SendMessageAsync(azureJobMessages);
               dataSyncModel.ProcessedData += azureJobMessages.Count();
               dataSyncModel.ProcessedBatches += 1;
               azureJobMessages = new List<AzureJobMessageModel>();
            }
         }
      }
      catch(Exception ex)
      {
          throw ex;
      }
   }
}

期望的结果:希望在按钮单击时具有数据同步过程的异步模式。

实际结果:

出现错误“ObjectDisposedException - 无法访问 Disposed Object (数据库上下文)”

。有人对此有任何想法吗?

注意:-我不想让操作方法异步。我将在服务方法或包含 CRUD 操作逻辑的 CRUD 操作中使用此方法调用。我希望数据同步逻辑在后台运行而不影响 CRUD 操作的响应时间。

【问题讨论】:

    标签: c# asp.net-core dependency-injection async-await


    【解决方案1】:

    因为没有等待服务调用,所以响应在服务之前完成,这将处理上下文。当服务尝试访问上下文时导致错误。

    使操作异步,然后等待服务

    public class AzureSearchIndexController : Controller {
    
        //...
    
       [HttpGet]
       public async Task<IActionResult> StartIndex() {
    
            //...
    
            await _azureSearchDataSyncService.StartIndexingAsync(_siteId, _siteName);
    
            //...
        }
    }
    

    【讨论】:

    • 是的,确实如此,但我不能将其应用于我的案例,因为此数据同步方法调用也需要为 CRUD 操作操作实现。您能否建议任何其他可行的机制,因为我无法按照当前项目结构使我的操作异步
    • @rakeshgirase 你是什么意思。如何使其异步不允许 crud?
    • 如前所述,我的操作方法的创建主要目标是执行 CRUD 操作。对于每个 crud 操作动作,我希望这个进程作为独立于我的动作逻辑的后台进程在单独的线程中运行。当我使操作异步时,它会在我的操作逻辑和数据同步逻辑都完成时做出响应。我不希望它等待数据同步过程完成。
    • @rakeshgirase 可以这样做,但结果是调用者将不知道操作是成功还是失败。你知道你会如何处理失败吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    相关资源
    最近更新 更多