简体   繁体   中英

Handling DB transactions/ DbContext with ASP.NET MVC with Entity Framework, UnityConfig and Multi-Tenancy

I am getting the error "System.Data.SqlClient.SqlException: New transaction is not allowed because there are other threads running in the session." when we hit 2 or more simultaneous users conducting the same DB action.

It doesn't matter whether its a query or we are making actual data changes using the entity framework, we continue to get this issue when multiple users hit the same web functions.

From looking at other posts it is my understanding we should ensure the DbContext is initialized/unique for each web request which should ensure the transaction issue is resolved.

We are using ASP.NET MVC 4 w/ UnityConfig, EntityFramework and a Multi-Tenancy architecture connecting to Azure SQL from an Azure Web App.

The DB gets initialized in Unity here:

container.RegisterType<IStorageUnitOfWork, StorageElasticScaleUoW<int>>(new InjectionConstructor(sharding.ShardMap, tenantId, connStrBldr.ConnectionString));

and this IStorageUnitOfWork is setup like:

    public class StorageElasticScaleUoW<T> : DbContext, IStorageUnitOfWork
    {


        public StorageElasticScaleUoW()
        {
            this.Database.CommandTimeout = 0;
        }


        protected internal StorageElasticScaleUoW(string connectionString)
            : base(SetInitializerForConnection(connectionString))
        {
            this.Database.CommandTimeout = 0;
        }

I am unclear on the best approach to move this to a per web request architecture (assuming that is the be the appropriate solution).

I have seen some posts talking about using TransientLifetimeManager and PerThreadLifetimeManager on initializing the unitofWork but I am not clear how that will work with multi-tenancy. In case it helps, our multi-tenancy/sharding setup mirrors the one Microsoft suggest here: https://docs.microsoft.com/en-nz/azure/sql-database/saas-tenancy-elastic-tools-multi-tenant-row-level-security Thanks!

The tenant ID is (or should be) simply another parameter you should be passing into your DbContext constructor that you then use to define query filters (different depending on version you're using). You want each request to your application to have their own instance of that DbContext , so you'd use PerRequestLifetimeManager (see this answer).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM