2017-10-19 73 views
-1

我添加了一個帶有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; 
      } 
     } 



    } 
+0

不確定這是否與您所看到的問題有關,但由於'CrewLogContext'是在類級別創建的,並且該類在'GlobalFilters.Filters'集合中被註冊爲單例,所以'CrewLogContext '實例從不處理。你應該把它放在一個使用塊中,或者使用DI將它注入到你的過濾器中。您可以使用[自定義FilterProvider](https://stackoverflow.com/a/38493666/)來允許一次性依賴項。 – NightOwl888

+0

@ NightOwl888謝謝!我通過使用使用。我仍然會尋找一種更乾淨的方式來做到這一點,但現在這樣做。 – causita

回答

0

以防萬一我將此作爲答案。就像@ 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; 
     } 
    } 

我會找到一個更清潔的方式做,但至少它的工作,因爲它應該。

相關問題