¿Cuál es las mejores prácticas para conseguir mismo nombre de usuario en la capa de acceso a datos?

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

  •  22-09-2019
  •  | 
  •  

Pregunta

Recientemente hemos añadido a nuestra base de datos de auditoría. Un colega implementado usando disparadores y me pidió que llamar a un procedimiento almacenado en inicio de sesión a la página web. El procedimiento almacenado inserta el nombre de usuario actual, y el id de sesión actual de Oracle en una mesa para que el gatillo se pudo asignar un identificador de sesión a un nombre de usuario. El problema es (o era) que estaba suponiendo que la sesión de un usuario de Internet asigna a una sesión de base de datos. Ese no es el caso, y que utiliza la agrupación de conexiones, por lo que los identificadores de sesión de Oracle pueden asignar a muchos usuarios, no necesariamente el usuario que ha iniciado sesión en esa sesión. Así que creé un método de utilidad en mi capa de acceso a datos que llama a su procedimiento en cada inserción, actualización y borrado (asegurando que se encuentra en la misma transacción):

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

Este obras y auditoría está trabajando como se requiere. Sin embargo, no me gusta la llamada a HttpContext:

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

Era la forma más rápida de ejecutar la tarea, pero no creo que debería estar en la capa de acceso de datos. ¿Y si en algún momento desconocido en el futuro que quería para acceder a la base de datos utilizando una aplicación de formas? Me sale un error al acceder HttpContext? ¿Hay una mejor manera de conseguir que el nombre de usuario que separa adecuadamente a las objeciones? Al pasar el nombre de usuario como un parámetro para cada inserción, actualización y borrado es una opción, pero será una tarea larga y me preguntaba si había una forma más elegante de hacerlo.

¿Fue útil?

Solución

Lo que ha hecho definitivamente no es el mejor enfoque, (como se ha descrito anteriormente en su pregunta) Esta es una de esas cosas que se llama una preocupación transversal - demás son cosas como el registro, etc)

Un enfoque que se utiliza es para pasar alrededor de un objeto de contexto que implementa la funcionalidad para todas estas preocupaciones transversales, de modo que cada método en cada capa no tiene que ser modificado para ser pasado los datos necesarios para implementar la funcionalidad deseada.

Por lo demás, como usted sugiere, usted va a tener que pasar el nombre de usuario en la capa de datos de más arriba en la pila en cada método que lo necesita. Si es posible, una alternativa es inyectar una clase base para todos estos métodos (todos los métodos de capa de datos) y poner este método en el que la clase base ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top