2015-10-16 30 views
6

Otrzymuję następujący błąd: Wartość nie może być pusta. Nazwa parametru: głównyUser.GetUserId() kończy się niepowodzeniem w konstruktorze kontrolera

Jak uzyskać dostęp do Tożsamości (userId) wewnątrz konstruktora kontrolera? Mogę go uruchomić tylko przez zawinięcie nieudanego połączenia w funkcję (obie podświetlone poniżej).

Czy jest coś, co muszę wstrzyknąć?

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 
    } 
} 

Odpowiedz

6

Jak wspomniano @Henk, konstruktor kontroler będzie wykonywany przed ActionContext został ustawiony, więc nie będziesz mieć dostępu do usług takich jak Context, Request lub User. Musisz pobrać identyfikator użytkownika w kontekście żądania.

Można użyć staroświeckiego podejścia z action filters, które są nadal częścią potoku MVC6 (który obsługuje także filtry akcji asynchronicznej za pośrednictwem IAsyncActionFilter).

Ponieważ chcesz ustawić właściwość w kontrolerze, najprostszym sposobem, w jaki można to zaimplementować, jest przesłonięcie metody OnActionExecuting w klasie kontrolera. Działa to, ponieważ dziedziczysz po Controller, która już implementuje IActionFilter.

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

Edit

Jeśli zaznaczysz DefaultControllerFactory widać, że:

  1. pierwszy kontroler jest stworzony
  2. wtedy ActionContext jest ustawiony (Za pomocą DefaultControllerPropertyActivator który jest jeden z aktywatorów właściwości):

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

Dziękujemy! Właśnie tego szukałem i dziękuję za wyjaśnienie :) – Toonsylvania

1

Po utworzeniu kontrolera nie ma gwarancji, że informacje o żądaniu są dostępne w jeszcze HttpContext. Może wcale nie być prośby. Czy istnieje powód, dla którego potrzebujesz tej informacji w konstruktorze?

Edytuj
2 Rozumiem twój problem. Co zwykle zrobić w sytuacji jak ta, jest utworzyć właściwość z polem podkładowej, która tylko raz na kontrolerze zapytania:

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

Dzięki za odpowiedź. Tak, chcę, aby wszystkie moje kontrolery API dziedziczyły z tak zwanego "BaseController". Będzie używać tego identyfikatora użytkownika, aby ujawnić inne wartości, które będą używane w całej aplikacji. Na przykład id_użytkownika służy do wysyłania zapytań do identyfikatora firmy - który również będzie członkiem tego kontrolera, aby wszystkie kontrolery mogły dziedziczyć jego wartość. Powód jest tam wiele zapytań w każdym kontrolerem, które będą potrzebować tych wartości (userId i companyId). Jest więc kilka zmiennych, które chcę udostępnić we wszystkich kontrolerach, bez konieczności uruchamiania zapytania w każdym kontrolerze. – Toonsylvania

+0

@ Toonsylvania Rozumiem twoją troskę. Dodałem przykład. –

Powiązane problemy