Quelle est les meilleures pratiques pour obtenir le nom d'utilisateur courant dans la couche d'accès aux données?

StackOverflow https://stackoverflow.com/questions/1980814

  •  22-09-2019
  •  | 
  •  

Question

Nous audit récemment ajouté à notre base de données. Un collègue mis en œuvre à l'aide de déclencheurs et m'a demandé d'appeler une procédure stockée lors de la connexion sur le site. La procédure stockée insère le nom d'utilisateur et l'identifiant de session courant oracle dans une table afin que le déclencheur pourrait mapper un ID de session à un nom d'utilisateur. Le problème est (ou était) qu'il assumait que la session Internet d'un utilisateur associé à une session de base de données. Ce n'est pas le cas, et nous utilisons la mise en commun de connexion, si la session oracle ids peut mapper à de nombreux utilisateurs, pas nécessairement l'utilisateur connecté sur cette session. J'ai donc créé une méthode d'utilité dans ma couche d'accès aux données qui appelle sa procédure sur chaque insert, update et delete (assurant qu'il est dans la même transaction):

/// <summary>
/// Performs an insert, update or delete against the database
/// </summary>
/// <param name="transaction"></param>
/// <param name="command">The command.</param>
/// <param name="transaction">A transaction, can be null. 
/// No override provided without a transaction, to remind developer to always consider transaction for inserts, updates and deletes</param>
/// <returns>The number of rows affected by the operation</returns>
public static int InsertUpdateDelete(OracleCommand command, OracleTransaction transaction)
{
  if (command == null)
    throw new ArgumentNullException("command", "command is null.");

  OracleConnection connection = null;
  bool doCommit = false;
  try
  {
    if (transaction == null)
    {
      //We always need a transaction for the audit insert
      connection = GetOpenConnection();
      transaction = connection.BeginTransaction();
      doCommit = true;
    }

    command.Transaction = transaction;
    command.Connection = transaction.Connection;

    //TODO HttpContext requires that presentation layer is a website. So this call should NOT be in the data access layer.
    string username = HttpContext.Current.User.Identity.Name;
    if (!String.IsNullOrEmpty(username))
      pInsertCurrentUserForAudit(username, command.Transaction);

    int recordsAffected = command.ExecuteNonQuery();

    if (doCommit)
      transaction.Commit();

    return recordsAffected;
  }
  finally
  {
    if (doCommit)
    {
      if (transaction != null)
        transaction.Dispose();
      if (connection != null)
        connection.Dispose();
    }
  }
}

Cela fonctionne et l'audit travaille maintenant au besoin. Cependant, je n'aime pas l'appel à HttpContext:

string username = HttpContext.Current.User.Identity.Name;

Il était le moyen le plus rapide de mettre en œuvre la tâche, mais je ne pense pas qu'il devrait être dans l'accès aux données couche. Et si, à un moment inconnu dans l'avenir, je voulais accéder à la base de données en utilisant une application de formulaires? Est-ce que je reçois une erreur lorsque j'accède HttpContext? Y at-il une meilleure façon d'obtenir au nom d'utilisateur qui sépare les préoccupations correctement? En passant le nom d'utilisateur en tant que paramètre à chaque insertion, mise à jour et supprimer est une option, mais ce sera une tâche longue et je me demandais s'il y avait une façon plus élégante de le faire.

Était-ce utile?

La solution

Qu'est-ce que vous avez fait est certainement pas la meilleure approche, (comme vous l'avez décrit ci-dessus dans votre question) Ceci est une de ces choses qui est appelé une préoccupation transversale - d'autres sont des choses comme l'exploitation forestière, etc.)

Une approche qui est utilisée est de passer autour d'un objet de contexte qui implémente la fonctionnalité pour toutes ces questions transversales, de sorte que chaque méthode dans chaque couche ne doit pas être modifié pour être passé les données nécessaires pour mettre en œuvre la fonctionnalité souhaitée.

Dans le cas contraire, comme vous le suggérez, vous allez devoir passer le nom d'utilisateur dans la couche de données de plus haut la pile dans toutes les méthodes qui en a besoin. Si possible, une autre solution consiste à injecter une classe de base pour toutes ces méthodes (toutes les méthodes de la couche de données) et de mettre cette méthode dans cette classe de base ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top