2016-11-30 59 views
2

我正在關注this tutorial以便通過實體框架6 CodeFirst在SQL Server中使用行級別安全性。教程代碼示例演示如何使用IDbConnectionInterceptor並在session_context中設置當前用戶標識。要檢索用戶標識,它使用靜態訪問方法HttpContext.Current.User.Identity.GetUserId(),它與Asp.Net標識和System.Web名稱空間相結合。實體框架 - 使用IDbConnectionInterceptor設置session_context

在我的多租戶Web應用程序,我想有tenantId注入到使用Unity的DbConnectionInterceptor(且不會與HttpContext硬耦合),並在session_context設置tenantId。我發現DbConnectionInterceptor需要全局註冊(例如,在應用程序啓動時),因此不能讓Unity爲每個請求創建DbConnectionInterceptor實例。

我的解決方案中還有2個DbContext代表2個不同的數據庫(租戶數據庫和系統數據庫),我只想將session_context僅應用於租戶數據庫。

看來,留給我唯一的選擇是有注入通過統一的DbContext isntance的tenantId並訪問DbConnectionInterceptorOpened()方法裏面DbContext實例。爲此,我想在Opened()方法中使用interceptionContext參數。 interceptionContextDbContexts(複數)財產。有沒有這方面的資料,所以我認爲像這樣的工作:收集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(); 
    } 
} 

我的代碼檢查是否包含TenantDataContext作爲第一個元素,並執行sp_set_session_context。但是我擔心的是DbContexts是否有機會同時在那裏?如果是這種情況,與我的其他數據庫的連接也將設置我不需要的session_context。我想知道爲什麼微軟提供這個作爲收集財產,而不是一個DbContext財產。這個屬性讓你想知道多個DbContext是否可以使用相同的連接。

有沒有人獲得我想要的?對這個interceptionContext的任何解釋對我也是有幫助的。

+0

我正面臨同樣的問題。你有沒有想過這個? – stoneMaster

+0

不幸的是沒有。我的代碼仍然是一樣的。我們還沒有投入生產,但迄今沒有遇到明顯的問題。 – ravinsp

回答

0

如果您像使用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(); 
     } 
    }