我添加了一个带有actionfilter的类,让我知道当前记录的用户是否是Admin(记录中的布尔值)。因为我需要在许多视图和控制器这个信息,我把动作过滤器在Global.asax中来自ActionFilter的ViewBag数据即使在数据库后仍然保留在会话中
的问题是,如果用户获得更新和IsAdmin复选框被选中时,视图不抢,除非新的更新信息我要么重建项目,要么重新开始视觉工作室。
这是我的代码设置。
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>
}
global 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);
}
以防万一这里是更新分配给该APPUSER
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);
}
}
}
}
我认为这是Chrome,但该部门的方法,如果我打开与其他浏览器,如火狐,数据应用仍然坚持。这是因为它已被添加到global.asax?
以防万一,我确认我剃刀的观点是正确的,我添加
`<label>@ViewBag.AppUserIsAdmin</label>` to verify.
的问题是数据库上下文没有得到安置。我修改了我的动作过滤器。不过,我相信有一个更干净的方法来做到这一点。
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;
}
}
}
不确定这是否与您所看到的问题有关,但由于'CrewLogContext'是在类级别创建的,并且该类在'GlobalFilters.Filters'集合中被注册为单例,所以'CrewLogContext '实例从不处理。你应该把它放在一个使用块中,或者使用DI将它注入到你的过滤器中。您可以使用[自定义FilterProvider](https://stackoverflow.com/a/38493666/)来允许一次性依赖项。 – NightOwl888
@ NightOwl888谢谢!我通过使用使用。我仍然会寻找一种更干净的方式来做到这一点,但现在这样做。 – causita