tutorial net name mvc example asp c# asp.net-mvc controller user-controls httpcontext

name - roles asp.net c#



¿Por qué es nulo el Usuario(como en User.Identity.Name) en mi controlador base abstracto? (8)

Estaba haciendo una pregunta relacionada pero arruiné el título y nadie lo entendería. Como ahora puedo hacer la pregunta con mayor precisión, decidí reformularla en una nueva pregunta y cerrar la anterior. Lo siento por eso.

Entonces, lo que quiero hacer es pasar datos (el apodo de mi usuario personalizado almacenado en el archivo db) al LoginUserControl. Este inicio de sesión se representa desde la página maestra a través de Html.RenderPartial (), así que lo que realmente necesito hacer es asegurarme de que, digamos ViewData ["UserNickname"] esté presente en cada llamada. Pero no quiero llenar ViewData ["UserNickname"] en todas y cada una de las acciones de cada controlador, así que decidí usar este enfoque y crear un controlador base abstracto que me haga el trabajo, así:

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 esta forma, cualquiera que sea mi controlador derivado, la información del usuario ya estará presente.

Hasta aquí todo bien. Ahora para el problema:

No puedo llamar a User.Identity.Name porque el User ya es nulo. Este no es el caso en todos mis controladores derivados, así que esto es específico para el controlador base abstracto.

Estoy configurando el User.Identity.Name a través de FormsAuthentication en otro lugar del código, pero creo que este no puede ser el problema: afaik User.Identity.Name puede ser nulo, pero no el mismo usuario.

Me parece que el HttpContext no está disponible (ya que también es nulo ;-) y que me falta un punto simple pero importante aquí. ¿Alguien puede darme algunas pistas? Yo realmente lo apreciaría.


Creo que el constructor base del Controlador no está completando el Usuario, pero que solo se conocerá más adelante cuando ControllerContext esté configurado para el Controlador. Debería verificar esto en la documentación sobre el ciclo de vida de una aplicación MVC (probablemente la que está aquí , aunque podría estar un poco desactualizada ya que es para la versión de vista previa), o simplemente verificar el código fuente de MVC.

del código que tengo de MVC (también una versión de vista previa, pero eso debería estar bien): (En el controlador)

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

...

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

No veo una implementación de un constructor predeterminado en el código. Eso probaría que ControllerContext es nulo en el momento de la construcción.

Entonces deberías ejecutar tu código en otro lugar.


Gracias Raimond. Estaba demasiado cansado para ver lo obvio. @ Keney: Sí, el contexto siempre es nulo. Raimond señaló por qué. Gracias de todos modos, no vi por qué también :-)

Mi solución de trabajo actual (aunque no es lo que quería) es un atributo que utilizo para decorar todas las acciones de mi controlador. Aquí está la implementación:

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

Voy a buscar cómo ejecutar el código de una manera que siga el principio DRY, ya que usar atributos para eso definitivamente significa repetir uno mismo. Tal vez algún tipo de interceptor ( idea interesante ) o gancho podría ayudar.

Saludos por eso.


Puedes agarrar esto usando algo como:

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

¿O el HttpContext está siempre vacío?

¿Podría establecer el httpContext a través del constructor de la clase abstracta? y usarlo de esta manera?


Estoy haciendo esto en una implementación de controlador de base y funciona como se esperaba.

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

Esto siempre devuelve verdadero o falso para mí, así User != null


La respuesta a este problema es bastante simple. No puedo ejecutar el código desde dentro del constructor por razones señaladas por Raimond, pero puedo hacerlo fuera del constructor.

Entonces, lo que hice fue anular onActionExecuting () en la clase de controlador base (creé un atributo personalizado para él, pero solo anular el método también debería funcionar) y luego realizar mi búsqueda de usuario desde allí.

Ahora funciona como se esperaba y no tengo código repetido.


a Masterfu: hice algo similar con su ayuda, deseo que pueda ayudar a los visitantes posteriores. En mi caso, necesito crear un repositorio de controladores para diferentes usuarios, sin embargo, en el constructor de controladores, el usuario (principal) no está listo. Así que creé un atributo para los controladores:

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

el repositorio, de hecho, no es una variable privada de controlador, sino algo creado por el atributo:

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

Puse códigos de creación del repositorio en un método separado, en el caso de que otros atributos puedan querer usar Usuario (principal) antes de que se active este atributo.


Llamar desde un constructor es demasiado pronto en la tubería de MVC.

Al mover el código a OnAuthorization, obtiene un usuario autorizado en un parámetro. ¡Trabajó para mi!

De su ejemplo, yo haría algo como esto:

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


La propiedad del usuario no se asigna hasta después de que se haya instanciado el controlador, pero puede obtener acceso anticipado de su constructor con:

System.Web.HttpContext.Current.User