I'm following this tutorial in order to use Row Level security in SQL Server via Entity Framework 6 CodeFirst. The tutorial code sample shows how to use IDbConnectionInterceptor and set the current user id in session_context
. To retrieve the user id, it uses static accessor method HttpContext.Current.User.Identity.GetUserId()
which is coupled with Asp.Net identity and System.Web namespace.
In my multi-tenant web app, I wanted to have the tenantId injected into the DbConnectionInterceptor
using Unity (without creating hard-coupling with HttpContext
) and set the tenantId in the session_context
. I found out that the DbConnectionInterceptor
needs to be registered globally (eg. at application startup) and therefore you cannot have Unity create DbConnectionInterceptor
instance per request.
I also have 2 DbContexts in my solution representing 2 different databases (Tenant database and a system database) and I only want to apply session_context
to the Tenant database only.
It seems that the only option remaining to me is have the tenantId injected into the DbContext
isntance via Unity and access the DbContext
instance inside the Opened()
method of the DbConnectionInterceptor
. For this purpose I thought of using the interceptionContext
parameter in the Opened()
method. interceptionContext
has a DbContexts
(plural) property. There's no documentation on this so I assumed something like this would work:
public void Opened(DbConnection connection, DbConnectionInterceptionContext interceptionContext)
{
var firstDbContext = interceptionContext.DbContexts.FirstOrDefault(d => d is TenantDataContext);
if (firstDbContext != null)
{
var dataContext = firstDbContext as TenantDataContext;
var tenantId = dataContext.TenantId;
DbCommand cmd = connection.CreateCommand();
cmd.CommandText = $"EXEC sp_set_session_context @key=N'TenantId', @value={tenantId};";
cmd.ExecuteNonQuery();
}
}
My code checks whether the DbContexts collection contains the TenantDataContext
as the first element and executes the sp_set_session_context
. But what I'm worried about is whether there's any chance for both DbContexts to be there at the same time? If that was the case, the connection to my other database would also set the session_context
which I don't need. I'm wondering why Microsoft has provided this as a collection property rather than a single DbContext
property. This property makes you wonder whether the same connection can be used by multiple DbContexts.
Is there anyone who has achieved what I want? Any explanation on this interceptionContext would also be helpful for me.