1. 程式人生 > >Asp.Net Core 專案 EntityFramework Core 根據登入使用者名稱過濾資料

Asp.Net Core 專案 EntityFramework Core 根據登入使用者名稱過濾資料

 1、建立ASP.NET Core Web Applicatoin (MVC)專案,並且使用 Individual User Account

 

 

 

 2、建立資料篩選介面 Models->IDataFilter.cs

    public interface IDataFilter
    {
        string UserName { get; set; }
    }

3、建立實體 Models->Book.cs 並繼承 IDataFilter介面,並將實體加入到 Data->ApplicatoinDbContext.cs 上下文中.

    public class Book : IDataFilter
    {
        public int Id { get; set; }
        [Display(Name = "書名")]
        public string Name { get; set; }
        public string UserName { get; set; }
    }
    public class ApplicationDbContext : IdentityDbContext
    {
        public DbSet<Book> Books { get; set; }
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    }

4、利用模板建立Book類的 CRUD介面。在 Controllers資料夾上 右鍵 選擇 Add(新增)->Controller(控制器)

 

  

5、自動生成Book的增刪改查之後,我們在這裡要做一個細微的修改,因為我們IDataFilter欄位 UserName是系統生成的,所以我們要修改兩個地方

  將BooksController.cs 下的 Create Action(由於只做演示,沒有去修改Update頁面)裡面的 Bind UserName去掉。修改後結果如下

   並將建立頁面 Views->Books->Create.cshtml 中的 UserName 部份備註

  

 

  在母版頁新增Book菜單鏈接 Views->Shared->_Layout.cshtml

6、開啟Nuget管理控制檯 遷移資料庫,並F5執行,點選Book連結。檢查一下程式 有沒問題。

Add-Migration Init //建立遷移檔案
Update-Database //更新到資料庫

7、由於Book實體實現了IDataFilter,UserName我們會通過重寫ApplicationDbContext的SaveChanges的實現,進行自動填充使用者名稱.由於要獲取登入資訊,在ApplicationDbContext中我們需注入 IHttpContextAccessor

 

    public class ApplicationDbContext : IdentityDbContext
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        public DbSet<Book> Books { get; set; }
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IHttpContextAccessor httpContextAccessor)
            : base(options)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public override int SaveChanges()
        {
            FillDataFilterInfo();
            return base.SaveChanges();
        }
        public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            FillDataFilterInfo();
            return base.SaveChangesAsync(cancellationToken);
        }
        protected void FillDataFilterInfo() =>
            ChangeTracker
            .Entries()
            .Where(w => w.Entity is IDataFilter && w.State == EntityState.Added)
            .ToList()
            .ForEach(entry => ((IDataFilter)entry.Entity).UserName = CurrentUserName);

        private string CurrentUserName => _httpContextAccessor.HttpContext.User?.Identity?.Name;
    }

8、驗證結果,執行專案,首先註冊一個帳號。然後進行建立一本書。最終結果。

9、最後我們來實現資料過濾部份程式碼,開啟 ApplicatonDbContex.cs

  新增私有方法DataFilters

        private void DataFilters<T>(ModelBuilder builder)
            where T : class
        {
            builder.Entity<T>().HasQueryFilter(s => ((IDataFilter)s).UserName == CurrentUserName);
        }

  新增一個靜態MethodInfo方法。這裡用到返射實現

        private static readonly MethodInfo _dataFiltersMethodInfo = typeof(ApplicationDbContext).GetMethod(nameof(DataFilters), BindingFlags.Instance | BindingFlags.NonPublic);

 

  在重寫OnModelCreating ,針對所有實現 IDataFilter的實體新增資料過濾

  

        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Model
                .GetEntityTypes()
                .Where(w => typeof(IDataFilter).IsAssignableFrom(w.ClrType))
                .ToList().ForEach(entityType =>
                {
                    _dataFiltersMethodInfo
                      .MakeGenericMethod(entityType.ClrType)
                      .Invoke(this, new object[] { builder });
                });
            base.OnModelCreating(builder);
        }

10、執行程式,分別用不同的瀏覽器。註冊兩個帳號。然後建立幾本書。最終結果

 

 

 

完結!第一次寫,見諒。

原始碼地址:https://github.com/CC1027CC/DataFilter

&n