Qual è le migliori pratiche per ottenere nome utente corrente a livello di accesso ai dati?

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

  •  22-09-2019
  •  | 
  •  

Domanda

Recentemente abbiamo aggiunto il controllo nella banca dati. Un collega implementato utilizzando i trigger e mi ha chiesto di chiamare una stored procedure di accesso al sito. La stored procedure inserisce il nome utente corrente, e la corrente ID di sessione Oracle in una tabella in modo che il grilletto potrebbe mappare un ID di sessione a un nome utente. Il problema è (o era) che stava assumendo che la sessione Internet di un utente mappato a una sessione di database. Questo non è il caso, e usiamo il pool di connessioni, in modo da ID di sessione Oracle può mappare a molti utenti, non necessariamente l'utente che ha registrato in su quella sessione. Così ho creato un metodo di utilità nel mio livello di accesso ai dati che chiama la sua procedura su ogni inserimento, aggiornamento ed eliminare (assicurando che è nella stessa transazione):

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

Questo funziona e il controllo ora lavora come richiesto. Tuttavia, non mi piace la chiamata a HttpContext:

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

E 'stato il modo più rapido di attuare il compito, ma non credo che dovrebbe essere nel livello di accesso ai dati. Che cosa succede se a un certo momento sconosciuta in futuro ho voluto accedere al database utilizzando un'applicazione forme? Dovrei ottenere un errore quando accedo HttpContext? C'è un modo migliore di arrivare al nome utente che separa adeguatamente le riserve? Passando il nome utente come un parametro per ogni inserimento, aggiornamento e cancellazione è un'opzione, ma sarà un lavoro lungo e mi chiedevo se ci fosse un modo più elegante di farlo.

È stato utile?

Soluzione

Quello che hai fatto non è sicuramente l'approccio migliore, (come avete descritto sopra nella tua domanda) Si tratta di una di quelle cose che si chiama una preoccupazione trasversale - gli altri sono cose come la registrazione, etc)

Un approccio che viene utilizzato è passare attorno ad un contesto dell'oggetto che implementa la funzionalità per tutte queste preoccupazioni trasversali, in modo che ogni metodo in ciascuno strato non deve essere modificato per essere passato i dati necessari per implementare la funzionalità desiderata.

In caso contrario, come lei suggerisce, si sta andando ad avere per passare il nome utente nello strato di dati da più in alto nello stack in ogni metodo che ne ha bisogno. Se possibile, un'alternativa è quello di iniettare una classe base per tutti questi metodi (tutti i metodi del livello dati) e mettere questo metodo in quella classe base ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top