我正在关注
this tutorial,以便通过Entity Framework 6 CodeFirst在SQL Server中使用行级安全性.教程代码示例演示如何使用IDbConnectionInterceptor并在session_context中设置当前用户ID.要检索用户ID,它使用静态访问器方法HttpContext.Current.User.Identity.GetUserId(),它与Asp.Net标识和System.Web命名空间相结合.
在我的多租户Web应用程序中,我希望使用Unity将tenantId注入到DbConnectionInterceptor中(不创建与HttpContext的硬耦合)并在session_context中设置tenantId.我发现DbConnectionInterceptor需要全局注册(例如,在应用程序启动时),因此每个请求都不能让Unity创建DbConnectionInterceptor实例.
我的解决方案中还有2个DbContexts代表2个不同的数据库(租户数据库和系统数据库),我只想将session_context应用于租户数据库.
似乎剩下的唯一选择是让tenantId通过Unity注入DbContext isntance并访问DbConnectionInterceptor的Opened()方法内的DbContext实例.为此,我想到在Opened()方法中使用interceptionContext参数. interceptionContext具有DbContexts(复数)属性.没有关于此的文档,所以我假设这样的东西会起作用:
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();
}
}
我的代码检查DbContexts集合是否包含TenantDataContext作为第一个元素并执行sp_set_session_context.但我担心的是,DbContexts是否有机会在同一时间出现?如果是这种情况,与我的其他数据库的连接也会设置我不需要的session_context.我想知道为什么Microsoft将此作为集合属性而不是单个DbContext属性提供.此属性使您想知道多个DbContexts是否可以使用相同的连接.
有没有人达到我想要的目标?对此interceptionContext的任何解释对我也有帮助.
最佳答案 如果您正在使用EF,则可以使用DbContext的Connection_StateChaned事件.
static void Main(string[] args)
{
using (var db = new AdventureWorks2016CTP3Entities())
{
db.Database.Connection.StateChange += Connection_StateChange;
db.Database.Log = (log) => System.Diagnostics.Debug.WriteLine(log);
var purchase = db.SalesOrderHeader.Select(i => i.SalesPersonID);
foreach (var m in purchase)
{
Console.WriteLine(m);
}
}
}
private static void Connection_StateChange(object sender, System.Data.StateChangeEventArgs e)
{
if(e.CurrentState == System.Data.ConnectionState.Open)
{
var cmd = (sender as System.Data.SqlClient.SqlConnection).CreateCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "exec sp_set_session_context 'UserId', N'290'";
cmd.ExecuteNonQuery();
}
}