【问题标题】:How to replace a base controller with MVC ActionFilter (or something else)?如何用 MVC ActionFilter(或其他东西)替换基本控制器?
【发布时间】:2013-02-04 11:06:21
【问题描述】:

我正在尝试改进我的 MVC 设计。在每个页面上,我都需要读取一个 cookie 并基于它设置一个具有各种值的 User 对象(与身份验证无关)。

我目前所做的是让所有控制器都从 BaseController 继承,并在 BaseController 中使用 User 对象。

public class BaseController : Controller
{
    protected User thisUser { get; private set; }

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
         // ... read cookie, set values of thisUser
    }
}

这是一个糟糕的设计吗?我喜欢它只定义一次User,但我已经阅读了What are good candidates for base controller class in ASP.NET MVC? 上的答案,如果有更好的方法,我愿意重做。但我绝对不想要一种意味着在每个控制器上重复 User thisUser = new User(); 的方法,而且我看不出如果没有基本控制器,我怎么能这样实现。我找不到以这种方式使用 ActionFilters 的好例子。

我还没有使用 DI 框架,但如果它能解决问题,我会。如果这意味着将 User 作为参数传递给每个控制器或动作,我不确定这是否是对 DRY 赌注的改进。

我确定我缺少一些东西。任何帮助将不胜感激...

【问题讨论】:

    标签: c# asp.net-mvc model-view-controller design-patterns architecture


    【解决方案1】:

    创建界面

    interface ICustomPrincipal : IPrincipal
    {
        int UserId { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
    }
    

    自定义主体

    public class CustomPrincipal : ICustomPrincipal
    {
        public IIdentity Identity { get; private set; }
        public bool IsInRole(string role) { return false; }
    
        public CustomPrincipal(string email)
        {
            this.Identity = new GenericIdentity(email);
        }
    
        public int UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    

    CustomPrincipalSerializeModel - 用于将自定义信息序列化到 FormsAuthenticationTicket 对象中的 userdata 字段中。

    public class CustomPrincipalSerializeModel
    {
        public int UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    

    LogIn 方法 - 使用自定义信息设置 cookie

    if (Membership.ValidateUser(viewModel.Email, viewModel.Password))
    {
        var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
    
        CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
        serializeModel.UserId = user.Id;
        serializeModel.FirstName = user.FirstName;
        serializeModel.LastName = user.LastName;
    
        JavaScriptSerializer serializer = new JavaScriptSerializer();
    
        string userData = serializer.Serialize(serializeModel);
    
        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                 1,
                 viewModel.Email,
                 DateTime.Now,
                 DateTime.Now.AddMinutes(15),
                 false,
                 userData);
    
        string encTicket = FormsAuthentication.Encrypt(authTicket);
        HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
        Response.Cookies.Add(faCookie);
    
        return RedirectToAction("Index", "Home");
    }
    

    Global.asax.cs - 读取 cookie 并替换 HttpContext.User 对象,这是通过覆盖 PostAuthenticateRequest 来完成的

    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    
        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    
            JavaScriptSerializer serializer = new JavaScriptSerializer();
    
            CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
    
            CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
            newUser.UserId = serializeModel.UserId;
            newUser.FirstName = serializeModel.FirstName;
            newUser.LastName = serializeModel.LastName;
    
            HttpContext.Current.User = newUser;
        }
    }
    

    在 Razor 视图中访问

    @((User as CustomPrincipal).Id)
    @((User as CustomPrincipal).FirstName)
    @((User as CustomPrincipal).LastName)
    

    要获得完整答案,请使用此主题: ASP.NET MVC - Set custom IIdentity or IPrincipal

    【讨论】:

    • +1。但是我会在我的CustomPrincipal 中提供一个静态吸气剂,它为我制作演员表(public static CustomPrincipal Current get { return (CustomPrincipal)Thread.CurrentPrincipal; } }),所以我只需要使用CustomPrincipal.Current.LastName
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-09
    • 1970-01-01
    • 2023-02-26
    相关资源
    最近更新 更多