Question

Je posais une question connexe, mais j'ai foiré le titre et personne ne l'a compris. Étant donné que je peux maintenant poser la question plus précisément, j'ai décidé de la reformuler en une nouvelle question et de fermer l'ancienne. Désolé pour ça.

Je souhaite donc transmettre des données (le pseudo de mon utilisateur personnalisé tel qu'il est stocké dans la base de données) au LoginUserControl. Cette connexion est générée à partir de la page principale via Html.RenderPartial (). Ce que je dois vraiment faire, c'est donc m'assurer que, par exemple, ViewData ["quot UserNickname"] est présent à chaque appel. Mais je ne veux pas peupler ViewData [" UserNickname "] dans chacune des actions de chaque contrôleur. J'ai donc décidé d'utiliser cette approche et créez un contrôleur de base abstrait qui fera le travail pour moi, comme suit:

public abstract class ApplicationController : Controller
    {
        private IUserRepository _repUser;

        public ApplicationController()
        {
            _repUser = RepositoryFactory.getUserRepository();
            var loggedInUser = _repUser.FindById(User.Identity.Name); //Problem!
            ViewData["LoggedInUser"] = loggedInUser;
        }
    }

De cette façon, quel que soit le contrôleur dérivé, les informations utilisateur seront déjà présentes.

Jusqu'ici, tout va bien. Maintenant pour le problème:

Je ne peux pas appeler User.Identity.Name car Utilisateur est déjà nul. Ce n'est pas le cas dans tous mes contrôleurs dérivés. C'est donc spécifique au contrôleur de base abstrait.

Je configure User.Identity.Name via FormsAuthentication à un autre endroit du code, mais je pense que cela ne peut pas être le problème - après tout, User.Identity.Name peut être null, mais pas l'utilisateur lui-même.

Il me semble que le HttpContext n'est pas disponible (puisque également null ;-) et qu'il me manque un point simple mais important ici. Quelqu'un peut-il me donner des indices? Je l'apprécierais vraiment.

Était-ce utile?

La solution

Je suppose que le constructeur de base du contrôleur ne remplit pas l'utilisateur, mais qu'il n'est connu que plus tard lorsque ControllerContext est défini pour le contrôleur. Vous devriez vérifier cela dans la documentation sur le cycle de vie d'une application MVC (celle ici sera probablement utile, bien que cela puisse être un peu obsolète car il s'agit de la version d'aperçu), ou vérifiez simplement le code source de MVC.

à partir du code que j'ai de MVC (aussi une version preview, mais ça devrait aller): (Dans le contrôleur)

 public IPrincipal User {
            get {
                return HttpContext == null ? null : HttpContext.User;
            }
        }

...

public HttpContextBase HttpContext {
        get {
            return ControllerContext == null ? null : ControllerContext.HttpContext;
        }
    }

Je ne vois pas une implémentation d'un constructeur par défaut dans le code. Cela prouverait que le ControllerContext est nul au moment de la construction.

Vous devez donc exécuter votre code ailleurs.

Autres conseils

La réponse à ce problème est en fait assez simple. Je ne peux pas exécuter le code depuis le constructeur pour les raisons indiquées par Raimond, mais je peux le faire en dehors du constructeur.

J'ai donc redéfini onActionExecuting () dans la classe du contrôleur de base (j'ai créé un attribut personnalisé, mais la substitution de la méthode devrait également fonctionner), puis ma recherche d'utilisateur à partir de là.

Maintenant, cela fonctionne comme prévu et je n'ai pas de code répété.

La propriété User n'est affectée qu'une fois le contrôleur instancié, mais vous pouvez obtenir un accès anticipé à partir de votre constructeur avec:

System.Web.HttpContext.Current.User

Pouvez-vous saisir ceci en utilisant quelque chose comme:

HttpContext currentContext = HttpContext.Current;
string userName = currentContext.User.Identity.Name;

Ou le HttpContext est-il toujours vide ??

Pourriez-vous définir le httpContext via le constructeur de la classe abstraite? et l'utiliser de cette façon?

Merci Raimond. J'étais trop fatigué pour voir l'évidence. @ Keeney: Oui, le contexte est toujours nul. Raimond a expliqué pourquoi. Merci quand même, je n'ai pas vu pourquoi aussi: -)

Ma solution de travail actuelle (bien que ce ne soit pas ce que je voulais) est un attribut que j'utilise pour décorer toutes mes actions de contrôleur. Voici la mise en œuvre:

public class MasterPageDataAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            IUserRepository _repUser = RepositoryFactory.getUserRepository();
            IPrincipal siteUser = filterContext.Controller.ControllerContext.HttpContext.User;
            User loggedInUser = null;

            if (siteUser == null || siteUser.Identity.Name == null)
            {
                //do nothing
            }
            else
            {
                loggedInUser = _repUser.findUserById(siteUser.Identity.Name);
            }
            filterContext.Controller.ViewData["LoggedInUser"] = loggedInUser ?? new User { Nickname = "Guest" };
        }
    }

J'examinerai comment faire exécuter ce code de manière conforme au principe de DRY, car utiliser des attributs pour cela signifie clairement se répéter. Peut-être une sorte d'intercepteur -interceptors.aspx "rel =" nofollow noreferrer "> idée intéressante ) ou un crochet pourrait vous aider.

Bravo pour cela.

Je le fais dans une implémentation de contrôleur de base et cela fonctionne comme prévu.

public abstract class BaseController : Controller
{
    public bool LoggedOn
    {
        get { return User.Identity.IsAuthenticated; }
    }
}

Ceci retourne toujours vrai ou faux pour moi, donc Utilisateur! = null

à Masterfu: J'ai fait quelque chose de similaire avec votre aide, souhait qui peut aider ces derniers visiteurs. Dans mon cas, je dois créer un répertoire de contrôleurs pour différents utilisateurs, mais dans le constructeur de contrôleurs, l'utilisateur (principal) n'est pas prêt. J'ai donc créé un attribut pour les contrôleurs:

[CreateRepositoryByUser]
public class MFCController : Controller
{
    protected MFCRepository _repository
    {
        get { return ViewData["repository"] as MFCRepository; }
    }
...

le _repository, en effet, n'est pas une variable privée de contrôleur, mais quelque chose crée par l'attribut:

public class CreateRepositoryByUser : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        CreateRepository(filterContext);
    }

    public static void CreateRepository(ActionExecutingContext filterContext)
    {
        if (filterContext.Controller.ViewData["repository"] == null)
        {
            filterContext.Controller.ViewData["repository"] =
                MFCRepository.CreateMFCRepository(filterContext.Controller.ControllerContext.HttpContext.User);
        }
    }
}

Je mets les codes de création du référentiel dans une méthode séparée, au cas où d'autres attributs pourraient vouloir utiliser (principal) l'utilisateur avant que cet attribut ne soit déclenché.

L'appel depuis un constructeur est trop tôt dans le pipeline MVC.

En déplaçant le code sur OnAuthorization, vous obtenez un utilisateur autorisé dans un paramètre. Travaillé pour moi!

D'après votre exemple, je ferais quelque chose comme ceci:

public abstract class ApplicationController : Controller {
    private IUserRepository _repUser;

    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        _repUser = RepositoryFactory.getUserRepository();
        var loggedInUser = _repUser.FindById(filterContext.HttpContext.User.Identity.Name); //Problem!
        ViewData["LoggedInUser"] = loggedInUser;
    }


}

Injectez IPrincipal si vous avez besoin de Utilisateur dans le constructeur.

 // startup.cs
 // Inject IPrincipal
 services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);

Ajoutez ensuite IPrincipal dans votre constructeur. Notez qu’il est garanti que ce soit ClaimsPrincipal avec ASPNET - car c’est ce que HttpContext.User est.

question similaire

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top