0

看來,我的數據庫上下文不是線程安全的,短暫的,甚至儘管我規定:實體框架的核心 - 不是線程安全的 - ServiceLifetime.Transient

ServiceLifetime.Transient 

在數據庫的啓動配置。

Startup.cs

services.AddEntityFrameworkSqlServer().AddDbContext<DatabaseContext>((serviceProvider, options) => options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking).UseSqlServer(connectionString).UseInternalServiceProvider(serviceProvider), ServiceLifetime.Transient); 

阿比

[HttpPost("GetOrganisations")] //Yes post, dont harass me :) 
public async Task<IActionResult> GetOrganisations([FromBody] GetOrganisationsModel model) 
{ 
    Task<IEnumerable<OrganisationModel>> organisations = _organisationService.GetOrganisations(model?.Id, model?.StatusIds); 

    Task<int> organisationTotalCount = _organisationService.GetOrganisationCount(); 

    await Task.WhenAll(organisations, organisationTotalCount); 

    return Ok(new OrganisationViewModel 
    { 
     Organisations = await organisations, 
     OrganisationTotalCount = await organisationTotalCount 
    }); 
} 

回購

public class OrganisationRepository : IOrganisationRepository 
{ 
    private readonly DatabaseContext _database; 

    public OrganisationRepository(DatabaseContext database) 
    { 
     _database = database; 
    } 

    public async Task<List<OrganisationEntity>> GetOrganisations(int? organisationId, List<int> statusIds) 
    { 
     IQueryable<OrganisationEntity> organisations = Database.Organisation.Include(o => o.Status).OrderByDescending(d => d.Created).AsQueryable(); 

     if (organisationId != null) 
     { 
      organisations = organisations.Where(o => o.Id == organisationId); 
     } 

     if (statusIds != null && statusIds.Count > 0) 
     { 
      organisations = organisations.Where(o => statusIds.Contains(o.StatusId)); 
     } 

     return await organisations.ToListAsync(); 
    } 

    public async Task<int> GetOrganisationCount() 
    { 
     return await Database.Organisation.CountAsync(); 
    } 
} 

異常

System.InvalidOperationException:連接未關閉。 連接的當前狀態正在連接。

這裏的問題是,我稱之爲GetOrganisations()和GetOrganisationCount()異步的,由於某種原因,(我認爲),同一個數據庫CONTEX用於兩個電話,(不同的線程)..我認爲,通過添加選項:

ServiceLifetime.Transient 

這將解決我的問題,(因爲默認的作用範圍),但沒有..

但是如果我添加using語句..

public async Task<List<OrganisationEntity>> GetOrganisations(int? organisationId, List<int> statusIds) 
{ 
    var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>(); 
    optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) 
     .UseSqlServer(
      "Data Source=.;Initial Catalog=MYDATABASE;Integrated Security=True;Connect Timeout=30;"); 

    using (var db = new DatabaseContext(optionsBuilder.Options, null)) 
    { 
     IQueryable<OrganisationEntity> organisations = 
      db.Organisation.Include(o => o.Status).OrderByDescending(d => d.Created).AsQueryable(); 

     if (organisationId != null) 
     { 
      organisations = organisations.Where(o => o.Id == organisationId); 
     } 

     if (statusIds != null && statusIds.Count > 0) 
     { 
      organisations = organisations.Where(o => statusIds.Contains(o.StatusId)); 
     } 

     return await organisations.ToListAsync(); 
    } 
} 

public async Task<int> GetOrganisationCount() 
{ 
    var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>(); 
    optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) 
     .UseSqlServer(
      "Data Source=.;Initial Catalog=MYDATABASE;Integrated Security=True;Connect Timeout=30;"); 

    using (var db = new DatabaseContext(optionsBuilder.Options, null)) 
    { 
     return await db.Organisation.CountAsync(); 
    } 
} 

一切正常!

爲什麼依賴注入不能正常工作?

我完全錯了嗎?如果我需要瞬態上下文,我是否被迫爲所有我的任務使用語句?

ServiceLifetime.Transient有bug?!

編輯:

Stacktrade,(一些信息屏蔽)

「在 System.Data.ProviderBase.DbConnectionClosedConnecting.TryOpenConnection(的DbConnection outerConnection,DbConnectionFactory connectionFactory的, TaskCompletionSource 重試)\ r \ n在 System.Data.SqlClient.SqlConnection.OpenAsync(CancellationToken cancellationToken)\ r \ n ---以前位置的堆棧跟蹤結束 拋出異常--- \ r \ n在 System.Runtime.ExceptionServices.ExceptionDispatchInfo。扔(個)\ r \ n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任務 任務)\ r \ n在 Microsoft.EntityFrameworkCore.Storage.RelationalConnection.d__31.MoveNext(個)\ r \ N-- - 從 先前位置棧跟蹤其中例外在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()拋出 --- \ r \ n結束\ r \ n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (任務 任務)\ r \ n在 Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.d__9.MoveNext()\ r \ n --- 從previo我們的位置,其中的例外是在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw(個)\ r \ n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任務 任務)\ r拋出 --- \ r \ n \ n在 Microsoft.EntityFrameworkCore.Storage.Internal.SqlServerExecutionStrategy.d__6 2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.<MoveNext>d__8.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.EntityFrameworkCore.Query.AsyncQueryMethodProvider.<GetResult>d__16
1.MoveNext()\ r \ n --- 從以前位置拋出異常的堆棧跟蹤結束 --- \ r \ n在System .Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\ r \ n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任務 任務)\ r \ n在 Microsoft.EntityFrameworkCore.Query.Internal.TaskResultAsyncEnumerable 1.Enumerator.<MoveNext>d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor
1.EnumeratorExceptionInterceptor.d__5.MoveNext()\ r \ n --- 從之前位置拋出異常的堆棧跟蹤結束 --- \ r \ n在System中。 Runtime.ExceptionServices.ExceptionDispatchInfo.Throw(個)\ r \ n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任務 任務)\ r \ n在 System.Runtime.CompilerServices.TaskAwaiter 1.GetResult()\r\n at XXXXXXX.Data.Repositories.Organisation.OrganisationRepository.<GetOrganisationCount>d__8.MoveNext() in C:\\Users\\XXXXXXX\\Documents\\Visual Studio 2017\\Projects\\XXXXXXX\\XXXXXXX.Data\\Repositories\\Organisation\\OrganisationRepository.cs:line 65\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult() \ r \ n at XXXXXXX.Api.Services.Organisation.OrganisationService.d__4.MoveNext() in C:\ Users \ XXXXXXX \ Documents \ Visual Studio 2017 \ Projects \ XXXXXXX \ XXXXXXX.Api \ Services \ Organisa \ OrganisationService.cs:行 31 \ r \ n ---以前位置的堆棧跟蹤結束,其中拋出異常 --- \ r \ n在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\ r \ n
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任務 任務個)\ r \ n在 System.Runtime.CompilerServices.TaskAwaiter.GetResult(個)\ r \ n在 XXXXXXX.Api.Controllers.Administration .OrganisationController.d__5.MoveNext() in C:\ Users \ XXXXXXX \ Documents \ Visual Studio 2017 \ Projects \ XXXXXXX \ XXXXXXX.Api \ Controllers \ Administration \ OrganisationController.cs:line 51「

回答

1

ServiceLifetime.Transient錯誤?!

這不是bug。因爲我們知道DbContext不是線程安全的,所以兩個方法調用都使用相同的OrganisationService實例,該實例本身是使用DatabaseContext的相同實例創建的。

Task<IEnumerable<OrganisationModel>> organisations = 
    _organisationService.GetOrganisations(model?.Id, model?.StatusIds); 

Task<int> organisationTotalCount = _organisationService.GetOrganisationCount(); 

這是線程切換環境中實體框架'DbContext的限制。因此,我們使用以下傳統的方法 -

[HttpPost("GetOrganisations")] 
public async Task<IActionResult> GetOrganisations([FromBody] GetOrganisationsModel model) 
{ 
    var organisations = 
     await _organisationService.GetOrganisations(model?.Id, model?.StatusIds); 

    var organisationTotalCount = await _organisationService.GetOrganisationCount(); 

    return Ok(new OrganisationViewModel 
    { 
     Organisations = organisations, 
     OrganisationTotalCount = organisationTotalCount 
    }); 
} 

newing了倉庫裏被他們緊緊地成爲情侶缺點是,你不能單元測試庫像this。如果我必須在之間選擇任務。當所有對單元測試在那特定場景,我會選擇單元測試。

如果你看到自己使用Task.WhenAll很多,你可能想看看Dapper ORM它可以與EF一起使用。

+0

Aha .. Okey ..其實我一開始並沒有WhenAll,但如果我沒有錯,沒有WhenAll,GetOrganisationCount()只會在getOrganisations()完成後執行,所以..同步調用? (只是爲了澄清)謝謝 – Reft

+0

如果使用'await','GetOrganisationCount'僅在'GetOrganisations'完成後調用。 – Win