2016-11-30 4 views
2

Je suis this tutorial afin d'utiliser la sécurité au niveau de la ligne dans SQL Server via Entity Framework 6 CodeFirst. L'exemple de code tutoriel montre comment utiliser IDbConnectionInterceptor et définir l'ID utilisateur actuel dans session_context. Pour récupérer l'ID utilisateur, il utilise la méthode d'accès statique HttpContext.Current.User.Identity.GetUserId() qui est couplée avec l'identité Asp.Net et l'espace de noms System.Web.Entity Framework - Définition de session_context à l'aide de IDbConnectionInterceptor

Dans mon application web multi-locataire, je voulais avoir le TenantID injecté dans le DbConnectionInterceptor avec Unity (sans créer dur couplage avec HttpContext) et régler la TenantID dans le session_context. J'ai découvert que le DbConnectionInterceptor doit être enregistré globalement (par exemple au démarrage de l'application) et par conséquent vous ne pouvez pas créer une instance DbConnectionInterceptor par requête.

J'ai également 2 DbContexts dans ma solution représentant 2 bases de données différentes (base de données de locataire et une base de données système) et je veux seulement appliquer session_context à la base de données de locataire seulement.

Il semble que la seule option qui me reste est d'avoir le TenantID injecté dans le DbContext isntance par l'unité et accéder à l'instance DbContext dans la méthode Opened() du DbConnectionInterceptor. Pour ce faire j'ai pensé utiliser le paramètre interceptionContext dans la méthode Opened(). interceptionContext a une propriété DbContexts (pluriel). Il n'y a pas de documentation sur ce donc je suppose quelque chose comme ça fonctionnerait:

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(); 
    } 
} 

Mes code vérifie si la collection DbContexts contient le TenantDataContext comme premier élément et exécute la sp_set_session_context. Mais ce qui m'inquiète, c'est de savoir s'il y a une chance que DbContexts soit là en même temps? Si tel était le cas, la connexion à mon autre base de données définirait également le session_context dont je n'ai pas besoin. Je me demande pourquoi Microsoft a fourni cela comme une propriété de collection plutôt qu'une seule propriété DbContext. Cette propriété vous permet de vous demander si la même connexion peut être utilisée par plusieurs DbContexts.

Y at-il quelqu'un qui a réalisé ce que je veux? Toute explication sur interceptionContext serait également utile pour moi.

+0

Je suis confronté au même problème. Avez-vous déjà compris cela? – stoneMaster

+0

Malheureusement non. Mon code est toujours le même. Nous ne sommes pas encore allés en production, mais jusqu'à présent, nous n'avons pas rencontré de problème visible avec cela. – ravinsp

Répondre

0

Vous pouvez utiliser l'événement Connection_StateChaned de votre DbContext si vous utilisez EF comme cela.

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(); 
     } 
    }