OData DataServiceContext的使用

时间:2019-04-02 10:37:03

标签: c# thread-safety odata wcf-data-services wcf-data-services-client

我想知道DataServiceContext类的正确用法是什么。 我是否应该为每个工作单元和/或范围创建一个新实例,例如:

public SomeEntity GetSomeEntities()
{ 
   DataServiceContext context = new DataServiceContext(...);
   DataServiceQuery<SomeEntity> query = context.SomeEntity
      .Where(x => x.SomeProperty == someValue);

   IEnumerable<SomeEntity> someEntities = await Task.Factory.FromAsync(
      query.BeginExecute, query.EndExecute, null);

   return someEntities.ToList();
}

还是应该使用共享实例:

private readonly DataServiceContext context = new DataServiceContext(...);

public SomeEntity GetSomeEntities()
{ 
   DataServiceQuery<SomeEntity> query = context.SomeEntity
      .Where(x => x.SomeProperty == someValue);

   IEnumerable<SomeEntity> someEntities = await Task.Factory.FromAsync(
      query.BeginExecute, query.EndExecute, null);

   return someEntities.ToList();
}

我了解在使用EntityFramework上下文的情况下,您可以使用第一种方法,但是我不确定OData的情况-特别是是否始终在重新创建Context时不会像重新创建那样导致套接字耗尽HttpClient就可以了。

一个与上下文有关的线程安全性相关问题-从多个并发线程中使用相同的上下文是否安全,如下所示:

DataServiceContext context = new DataServiceContext(...);
List<Task<IEnumerable<SomeEntity>>> downloadTasks = new List<Task<IEnumerable<SomeEntity>>>();

using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
{
   foreach (var batch in someEntitiesList.Batch(_defaultBatchSize))
   {
      if (cancellationTokenSource.IsCancellationRequested)
         break;

      string filter = string.Join(" or ", batch.Select(i => $"(Id eq '{i.Id}')"));

      Task<IEnumerable<SomeEntity>> task = Task.Run(() =>
      {
         try
         {
            DataServiceQuery<SomeEntity> query = context.SomeEntity
               .AddQueryOption("$filter", filter)
               .OrderBy(x => x.Id)
               as DataServiceQuery<SomeEntity>;

               IEnumerable<SomeEntity> someEntities = query.Execute();

               return someEntities;
         } 
         catch(Exception)
         {
            cancellationTokenSource.Cancel();
            throw;
         }
      }, cancellationTokenSource.Token);

      downloadTasks.Add(task);
   }

   await Task.WhenAll(downloadTasks);
   //do something with results
}

还是我需要针对每个任务使用新的上下文?

List<Task<IEnumerable<SomeEntity>>> downloadTasks = new List<Task<IEnumerable<SomeEntity>>>();

using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
{
   foreach (var batch in someEntitiesList.Batch(_defaultBatchSize))
   {
      if (cancellationTokenSource.IsCancellationRequested)
         break;

      string filter = string.Join(" or ", batch.Select(i => $"(Id eq '{i.Id}')"));

      Task<IEnumerable<SomeEntity>> task = Task.Run(() =>
      {
         try
         {
            DataServiceContext context = new DataServiceContext(...);

            DataServiceQuery<SomeEntity> query = context.SomeEntity
               .AddQueryOption("$filter", filter)
               .OrderBy(x => x.Id)
               as DataServiceQuery<SomeEntity>;

               IEnumerable<SomeEntity> someEntities = query.Execute();

               return someEntities;
         } 
         catch(Exception)
         {
            cancellationTokenSource.Cancel();
            throw;
         }
      }, cancellationTokenSource.Token);

      downloadTasks.Add(task);
   }

   await Task.WhenAll(downloadTasks);
   //do something with results
}

0 个答案:

没有答案