c# - una - ¿Es este principal personalizado en el controlador base ASP.NET MVC 3 terriblemente ineficiente?
mvc c# tutorial (2)
A pesar de que he estado aquí por un tiempo, esta es mi primera pregunta sobre SO, así que sean amables conmigo.
Estoy usando ASP.NET MVC 3
y quiero crear un Principal
personalizado para poder almacenar un poco más de información sobre el usuario actual que el estándar, por lo que no tengo que ir a la base de datos con demasiada frecuencia. Es bastante estándar lo que estoy buscando. Digamos la dirección de correo electrónico y la identificación del usuario en primera instancia.
He decidido almacenar el objeto en el caché, ya que soy consciente de que no se recomienda almacenarlo en la sesión.
Tampoco quiero tener que continuar lanzando el objeto User
, por lo que quería anular el objeto User
en el controlador. Así que puedo ir a User.UserId
y estar seguro de algo.
Así que creé un principio personalizado como este:
public class MyPrincipal : IPrincipal
{
public MyPrincipal(IIdentity ident, List<string> roles, string email, Guid userId)
{
this._identity = ident;
this._roles = roles;
this._email = email;
this._userId = userId;
}
IIdentity _identity;
public IIdentity Identity
{
get { return _identity; }
}
private List<string> _roles;
public bool IsInRole(string role)
{
return _roles.Contains(role);
}
private string _email;
public string Email
{
get { return _email; }
}
private Guid _userId;
public Guid UserId
{
get { return _userId; }
}
}
Y tengo un controlador base como este:
public class BaseController : Controller
{
protected virtual new MyPrincipal User
{
get
{
if (base.User is MyPrincipal)
{
return base.User as MyPrincipal;
}
else
{
return new MyPrincipal(base.User.Identity, new List<string>(0), "", Guid.Empty );
}
}
}
protected override void OnAuthorization(AuthorizationContext filterContext)
{
if (User != null)
{
if (User.Identity.IsAuthenticated)
{
if (User.Identity is FormsIdentity)
{
FormsIdentity id = base.User.Identity as FormsIdentity;
MyPrincipal principal = (MyPrincipal)filterContext.HttpContext.Cache.Get(id.Name);
if (principal == null)
{
MembershipUser user = Membership.GetUser();
// Create and populate your Principal object with the needed data and Roles.
principal = new MyPrincipal(id, Roles.GetRolesForUser(id.Name).ToList(), user.Email, (Guid)user.ProviderUserKey);
filterContext.HttpContext.Cache.Add(
id.Name,
principal,
null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
new System.TimeSpan(0, 30, 0),
System.Web.Caching.CacheItemPriority.Default,
null);
}
filterContext.HttpContext.User = principal;
System.Threading.Thread.CurrentPrincipal = principal;
base.OnAuthorization(filterContext);
}
}
}
}
}
Si lo mira, rápidamente se dará cuenta de que si el usuario no ha iniciado sesión, cualquier llamada al objeto User
deberá ejecutarse a través de este código:
return new MyPrincipal(base.User.Identity, new List<string>(0), "", Guid.Empty );
y esto se siente terriblemente ineficiente para mí, aunque solo crea objetos vacíos para las cosas que faltan.
Funciona bien.
Así que supongo que quiero saber si esto está realmente bien y debería dejar de ser tan anal con el rendimiento y la eficiencia, o si mis temores son correctos, en cuyo caso, ¿qué debería estar haciendo? [Por favor, no digas "¡Conseguir una vida, amigo!"]
No, no hay nada específicamente incorrecto con este código desde un punto de vista de rendimiento que se destaca. MUCHOS objetos se crean en el back-end en ASP.NET, su único objeto es una gota en el cubo. Como la creación de instancias de clase es extremadamente rápida, no me preocuparía.
¿Por qué estás ignorando las sesiones aquí? La información de la sesión no tiene fechas de vencimiento, por lo que no hay controles adicionales detrás de escena. A menos que esté utilizando un servidor de sesión fuera de proc, no hay serialización de su objeto (ninguno con el caché tampoco). La memoria caché es para cada usuario, por lo que tiene la posibilidad (aunque leve) de un error de código que devuelve el principal incorrecto donde está el caché por usuario, no se arriesga.
Si desea que esté disponible para todas las solicitudes allí (no solo para MVC), consideraría establecer esto en Application_PostAuthenticateRequest
Esta publicación puede ser de utilidad. Observe el uso de datos de usuario en el ticket de autenticación.
ASP.NET MVC: establezca IIdentity personalizado o IPrincipal