代码之家  ›  专栏  ›  技术社区  ›  causita

来自ActionFilter的ViewBag数据即使在数据库之后也会在会话中持久化

  •  -1
  • causita  · 技术社区  · 8 年前

    问题是,如果用户得到更新并且未选中IsAdmin复选框,则视图不会获取新的更新信息,除非我重建了项目或重新启动了visual studio。

    这是我的代码设置。

    AppUser实体

       public class AppUser
        {
            [DatabaseGenerated(DatabaseGeneratedOption.None)]
            [Display(Name = "User Name")]
            [Required]
            public string Id { get; set; }
    
            [Display(Name = "Display Name")]
            [Required]
            public string Name { get; set; }
            public bool IsSuperUser { get; set; }
            public bool IsAdmin { get; set; }
            [Display(Name = "Default Location")]
    
            public int LocationID { get; set; }
            public virtual Location Location { get; set; }
            public virtual ICollection<Department> Departments { get; set; }
        }
    

    ActionFilter:

      public class AppUserActionFilter : System.Web.Mvc.ActionFilterAttribute
        {
            private CrewLogContext db = new CrewLogContext();
    
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                //TODO remove repeating code..////////////
                var currentAppUser = HttpContext.Current.User.Identity.Name.Split('\\')[1];
                var appUser = db.AppUsers.Where(i => i.Id == currentAppUser).Single();
                var currentAppUserLocation = appUser.LocationID;
                var departments = appUser.Departments.ToList();
                filterContext.Controller.ViewData.Add("AppUserDepartments", departments);
                filterContext.Controller.ViewData.Add("AppUserLoca", currentAppUserLocation);
                filterContext.Controller.ViewData.Add("appUser", appUser.Id);
                //TODO remove repeating code..////////////
            }
    
            public override void OnResultExecuting(ResultExecutingContext filterContext)
            {
                //Remove domain\ from windows authenticated user. 
                var currentAppUser = HttpContext.Current.User.Identity.Name.Split('\\')[1];
    
                //Get user from db. 
                var appUser = db.AppUsers.Where(i => i.Id == currentAppUser).Single();
                var currentAppUserLocation = appUser.LocationID;
                //get IsAdmin flag. 
                //TODO not updating in VIEW
                bool currentAppUserIsAdmin = appUser.IsAdmin;
    
                //department related to user. 
                //TODO not updating in VIEW
                var departments = appUser.Departments.ToList();
                filterContext.Controller.ViewBag.AppUserDepartments = new SelectList(departments, "Id", "Name");
    
                //Flag tells me if current user is ADMIN
    
                filterContext.Controller.ViewBag.AppUserIsAdmin = currentAppUserIsAdmin;
                filterContext.Controller.ViewBag.AppUserLocation = currentAppUserLocation;
    
            }
        }
    

    视图:如果用户是否为管理员,则切换显示链接。

    @{
        ViewBag.Title = "Index";
        var isAdmin = ViewBag.AppUserIsAdmin;
    }
    
    
    <label>@ViewBag.AppUserIsAdmin</label>
    @if (isAdmin)
    {
        <p>
            @Html.ActionLink("Create New", "Create")
        </p>
    }
    

    全球asax。

    namespace CrewLog
    {
        public class MvcApplication : System.Web.HttpApplication
        {
            protected void Application_Start()
            {
                GlobalTrackingConfig.DisconnectedContext = true;
                AreaRegistration.RegisterAllAreas();
                //added actionfilter globally
                GlobalFilters.Filters.Add(new AppUserActionFilter(), 0);
                GlobalConfiguration.Configure(WebApiConfig.Register);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
            }
        }
    }
    

    我可以看到编辑正在工作,因为我可以验证数据库中的更改。

    这里是我用来更新AppUser的代码。

    [HttpPost]
            [ValidateAntiForgeryToken]
            //[Bind(Include = "Id,Name,IsSuperUser,IsAdmin,LocationID")]
            public ActionResult Edit(string id,string[] selectedDepartments)
            {
                if (id == null)
                {
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                }
                var appUserToUpdate = db.AppUsers
                    .Include(i => i.Location)
                    .Include(i => i.Departments)
                    .Where(i => i.Id == id).Single();
    
                if(TryUpdateModel(appUserToUpdate,"",new string[] {"Name","IsAdmin","IsSuperUser","LocationID"}))
                {
                    try
                    {
                        UpdateAppUserDepartments(selectedDepartments, appUserToUpdate);
    
                        db.SaveChanges();
    
                        return RedirectToAction("Index");
    
    
                    }
                    catch (RetryLimitExceededException /* dex */)
                    {
                        //Log the error (uncomment dex variable name and add a line here to write a log.
                        ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
                    }
                }
                PopulateAssignedDepartmentData(appUserToUpdate);
                return View(appUserToUpdate);
            }
    

    为了以防万一,这里有一种方法可以更新分配给这个应用程序用户的部门

    private void UpdateAppUserDepartments(string[] selectedDepartments, AppUser appUserToUpdate)
            {
                if (selectedDepartments == null)
                {
                    appUserToUpdate.Departments = new List<Department>();
                    return;
                }
    
                var selectedDepartmentsHS = new HashSet<string>(selectedDepartments);
                var appUserDepartments = new HashSet<int>
                    (appUserToUpdate.Departments.Select(c => c.Id));
                foreach (var department in db.Departments)
                {
                    if (selectedDepartmentsHS.Contains(department.Id.ToString()))
                    {
                        if (!appUserDepartments.Contains(department.Id))
                        {
                            appUserToUpdate.Departments.Add(department);
                        }
                    }
                    else
                    {
                        if (appUserDepartments.Contains(department.Id))
                        {
                            appUserToUpdate.Departments.Remove(department);
                        }
                    }
                }
            }
    

    `<label>@ViewBag.AppUserIsAdmin</label>` to verify. 
    

    问题是没有处理db上下文。我修改了动作过滤器。然而,我相信有一种更干净的方法可以做到这一点。

    public class AppUserActionFilter : System.Web.Mvc.ActionFilterAttribute
        {
            //private CrewLogContext db = new CrewLogContext();
    
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                //TODO remove repeating code..////////////
                using (CrewLogContext db1 = new CrewLogContext())
                {
                    var currentAppUser = HttpContext.Current.User.Identity.Name.Split('\\')[1];
                    var appUser = db1.AppUsers.Where(i => i.Id == currentAppUser).Single();
                    var currentAppUserLocation = appUser.LocationID;
                    var departments = appUser.Departments.ToList();
                    filterContext.Controller.ViewData.Add("AppUserDepartments", departments);
                    filterContext.Controller.ViewData.Add("AppUserLoca", currentAppUserLocation);
                    filterContext.Controller.ViewData.Add("appUser", appUser.Id);
                }
    
                //TODO remove repeating code..////////////
            }
    
            public override void OnResultExecuting(ResultExecutingContext filterContext)
            {
                //Remove domain\ from windows authenticated user. 
                using (CrewLogContext db2 = new CrewLogContext())
                {
                    var currentAppUser = HttpContext.Current.User.Identity.Name.Split('\\')[1];
    
                    //Get user from db. 
                    var appUser = db2.AppUsers.Where(i => i.Id == currentAppUser).Single();
                    var currentAppUserLocation = appUser.LocationID;
                    //get IsAdmin flag. 
                    //TODO not updating in VIEW
                    bool currentAppUserIsAdmin = appUser.IsAdmin;
    
                    //department related to user. 
                    //TODO not updating in VIEW
                    var departments = appUser.Departments.ToList();
                    filterContext.Controller.ViewBag.AppUserDepartments = new SelectList(departments, "Id", "Name");
    
                    //Flag tells me if current user is ADMIN
    
                    filterContext.Controller.ViewBag.AppUserIsAdmin = currentAppUserIsAdmin;
                    filterContext.Controller.ViewBag.AppUserLocation = currentAppUserLocation;
                }
            }
    
    
    
        }
    
    1 回复  |  直到 8 年前
        1
  •  0
  •   causita    8 年前

    以防我留下这个作为回答。就像@NightOwl888建议的那样,我必须处理上下文。 在动作过滤器中

    public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            //Remove domain\ from windows authenticated user. 
            using (CrewLogContext db2 = new CrewLogContext())
            {
                var currentAppUser = HttpContext.Current.User.Identity.Name.Split('\\')[1];
    
                //Get user from db. 
                var appUser = db2.AppUsers.Where(i => i.Id == currentAppUser).Single();
                var currentAppUserLocation = appUser.LocationID;
                //get IsAdmin flag. 
                //TODO not updating in VIEW
                bool currentAppUserIsAdmin = appUser.IsAdmin;
    
                //department related to user. 
                //TODO not updating in VIEW
                var departments = appUser.Departments.ToList();
                filterContext.Controller.ViewBag.AppUserDepartments = new SelectList(departments, "Id", "Name");
    
                //Flag tells me if current user is ADMIN
    
                filterContext.Controller.ViewBag.AppUserIsAdmin = currentAppUserIsAdmin;
                filterContext.Controller.ViewBag.AppUserLocation = currentAppUserLocation;
            }
        }
    

    我会找到一个更干净的方式来做,但至少它的工作,因为它应该。