2015-10-16 12 views
6

Viene visualizzato il seguente errore: Il valore non può essere nullo. Nome parametro: principalUser.GetUserId() non riesce nel costruttore del controllore

Come accedere a Identity (userId) all'interno del costruttore del controller? Posso solo farlo funzionare avvolgendo la chiamata fallita in una funzione (entrambe evidenziate sotto).

C'è qualcosa che devo iniettare?

public class BaseController : Controller { 
    protected readonly MylDbContext dbContext; 
    protected readonly string userId; 

    public BaseController(MylDbContext dbContext) { 
     this.dbContext = dbContext; 
     userId = User.GetUserId(); // fails here 
    } 

    public string GetUserId() { 
     return User.GetUserId(); // works here 
    } 
} 

risposta

6

Come accennato @Henk, verranno eseguiti il ​​costruttore di controllo prima che l'ActionContext è stata impostata, quindi non avrai accesso a proprietà come Context, Request o User. È necessario recuperare l'ID utente nel contesto di una richiesta.

È possibile utilizzare l'approccio vecchio stile dello action filters che fa ancora parte della pipeline MVC6 (che supporta anche i filtri di azione asincrona tramite IAsyncActionFilter).

Poiché si desidera impostare una proprietà nel controller, il modo più semplice per implementarlo è ignorando il metodo OnActionExecuting nella classe controller. Funziona perché si eredita da Controller, che già implementa IActionFilter.

public override void OnActionExecuting(ActionExecutingContext context) 
{ 
    //Get user id 
    userId = User.GetUserId(); 
} 

Modifica

Se si seleziona la DefaultControllerFactory si vedrà che:

  1. prima il controller è creato
  2. poi l'ActionContext è impostata (Tramite il DefaultControllerPropertyActivator che è uno degli attivatori di proprietà):

    var controller = _controllerActivator.Create(actionContext, controllerType); 
    foreach (var propertyActivator in _propertyActivators) 
    { 
        propertyActivator.Activate(actionContext, controller); 
    } 
    
+0

Grazie! Questo è esattamente quello che stavo cercando, e grazie per aver spiegato :) – Toonsylvania

1

Quando il controller viene istanziato, non è possibile garantire che le informazioni sulla richiesta siano ancora disponibili in HttpContext. Potrebbe non esserci una richiesta. C'è una ragione per cui hai bisogno di quelle informazioni nel costruttore?

Modifica
capisco il problema. Quello che faccio di solito in uno scenario come questo, è creare una struttura con un campo di supporto, che solo le query una volta per controller:

private int? _userId; 
public int UserId 
{ 
    get 
    { 
     if (!_userId.HasValue) 
     { 
      // query from db. 
      _userId = 42; 
     } 
     return _userId.Value; 
    } 
} 
+0

Grazie per la risposta. Sì, voglio che tutti i miei controller API ereditino da questo cosiddetto 'BaseController'. Utilizzerà tale ID utente per esporre altri valori che verranno utilizzati nell'app. Ad esempio, userId viene utilizzato per interrogare l'ID dell'azienda dell'utente, che sarà anche un membro di questo controller in modo che tutti i controller possano ereditarne il valore. Perché ci sono molte query in ogni controller che necessiteranno quei valori (userId e companyId). Quindi ci sono alcune variabili che voglio rendere disponibili in tutti i miei controller, senza dover eseguire una query in ogni controller. – Toonsylvania

+0

@Toonsylvania, capisco la tua preoccupazione. Ho aggiunto un esempio. –

Problemi correlati