2016-04-04 40 views
5

Sto cercando di sviluppare una libreria di classi in cui voglio implementare l'DbContext personalizzato. Nel metodo SaveChanges di DbContext, ho bisogno di ottenere le informazioni dell'utente corrente (dipartimento, nome utente ecc.) Per scopi di controllo. Una parte del codice DbContext è qui sotto:Come ottenere le informazioni dell'utente in DbContext utilizzando Net Core

public override int SaveChanges() 
{ 
    // find all changed entities which is ICreateAuditedEntity 
    var addedAuditedEntities = ChangeTracker.Entries<ICreateAuditedEntity>() 
      .Where(p => p.State == EntityState.Added) 
      .Select(p => p.Entity); 

    var now = DateTime.Now; 

    foreach (var added in addedAuditedEntities) 
    { 
     added.CreatedAt = now; 
     added.CreatedBy = ?; 
     added.CreatedByDepartment = ? 
    } 
    return base.SaveChanges(); 
} 

Due opzioni che vengono a mente:

  • Utilizzando HttpContext.Items di mantenere le informazioni dell'utente, l'iniezione IHttpContextAccessor e ottenere informazioni dal HttpContext.Items (In questo caso DbContext dipende HttpContext, è corretto?)
  • Utilizzo dell'oggetto ThreadStatic anziché HttpContext.Items e ottenere informazioni dall'oggetto ct (ho letto alcuni post che ThreadStatic non è sicuro)

Domanda: Qual è la soluzione migliore nel mio caso? C'è un altro modo che suggerisci?

+1

invece di prendere una dipendenza su IHttpContextAccessor direttamente nel tuo DbContext perché non creare una classe di servizio come AuditLogger e lasciare che DbContext dipenda da esso, AuditLogger può dipendere da IHttpContextAccessor come proprio dettaglio di implementazione interna –

+0

che sembra davvero un buon modo, lo farò prova ad implementarlo. Grazie. –

risposta

12

ho implementato un approccio simile a questo che è coperto in this blog post e fondamentalmente comporta la creazione di un servizio che utilizzerà dipendenza iniezione per iniettare il HttpContext (e sottostanti informazioni dell'utente) in un particolare contesto, o comunque si preferisce utilizzare .

Un'implementazione molto di base potrebbe essere simile a questo:

public class UserResolverService 
{ 
    private readonly IHttpContextAccessor _context; 
    public UserResolverService(IHttpContextAccessor context) 
    { 
     _context = context; 
    } 

    public string GetUser() 
    { 
     return await _context.HttpContext.User?.Identity?.Name; 
    } 
} 

Si sarebbe solo bisogno di iniettare questo nella pipeline all'interno del metodo ConfigureServices nel Startup.cs del file:

services.AddTransient<UserResolverService>(); 

E poi finalmente , basta accedervi all'interno del costruttore del numero specificato DbContext:

public partial class ExampleContext : IExampleContext 
{ 
    private YourContext _context; 
    private string _user; 
    public ExampleContext(YourContext context, UserResolverService userService) 
    { 
     _context = context; 
     _user = userService.GetUser(); 
    } 
} 

Quindi dovresti essere in grado di utilizzare _user per fare riferimento all'utente corrente nel tuo contesto. Questo può essere facilmente esteso per archiviare/accedere a qualsiasi contenuto disponibile all'interno della richiesta corrente.

+5

Rimuovi attesa parola chiave dopo il reso, come questo 'stringa pubblica GetUser() { return _context.HttpContext.User? .Identity? .Name; } ' –

+5

Ora IHttpContextAccessor non è registrato nei servizi per impostazione predefinita. Dobbiamo collegarlo manualmente in Startup.cs 'services.TryAddSingleton ();' –

Problemi correlati