在控制器(或更高)级别而不是方法级别,将SQL结果缩小给所有者

时间:2018-07-07 23:36:56

标签: asp.net asp.net-core

我正在Asp.net Core 2.1(EF,MVC,SQL Server)中做一个项目,通常我正在做类似以下的事情来获取当前用户(即所有者)的记录:

        [HttpPost]
        [Authorize]
        public JsonResult GetOrders()
        {
            string userId = _userManager.GetUserId(User);

            var applicationDbContext = _context.Order
                .Where(m => m.UserID == userId);
               ...etc...
         }

但是,我想知道是否有一种更广泛的(对于控制器,甚至是更全局的)结果过滤器,而不是必须在每个方法中包括上面的代码?

我很不高兴尝试了这个

        public OrderController(ApplicationDbContext context, IAuthorizationService authorizationService, UserManager<IdentityUser> userManager)
        {
            _authorizationService = authorizationService;
            _userManager = userManager;

            string userId = _userManager.GetUserId(User);
            _context = context.Where(m => m.UserID == userId);
        }

我有点理解为什么这行不通。但是,基本上,我的整个项目将精炼到所有者,很高兴只在一个地方指定它,然后知道_context(或ApplicationDbContext?或其他适当方法)已经包括了所有者记录。

2 个答案:

答案 0 :(得分:0)

请尝试使用EF Core 2.0中针对此用例引入的Global Query Filters

答案 1 :(得分:0)

有两个部分可以满足您的要求,一个是实现Global Query Filters,另一个是将UserId传递给Global Query Filters

我建议您按照以下步骤操作:

  1. Moidfy the DbContexxt

     public class ApplicationDbContext : IdentityDbContext
    {
        protected virtual string CurrentUserId
        {
            get
            {
                return Users.FirstOrDefault(u => u.UserName == _contextAccessor.HttpContext.User.Identity.Name)?.Id;
            }
        }
        private readonly IHttpContextAccessor _contextAccessor;
        private readonly UserResolverService _userResolverService;
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options
             , IHttpContextAccessor contextAccessor
            )
            : base(options)
        {
            _contextAccessor = contextAccessor;
        }
        public DbSet<Order> Orders { get; set; }
    
        private static MethodInfo ConfigureGlobalFiltersMethodInfo = typeof(ApplicationDbContext).GetMethod(nameof(ConfigureGlobalFilters), BindingFlags.Instance | BindingFlags.NonPublic);
    
        protected override void OnModelCreating(ModelBuilder builder)
        {
            //Configure Query Filter
            foreach (var entityType in builder.Model.GetEntityTypes())
            {
                ConfigureGlobalFiltersMethodInfo
                    .MakeGenericMethod(entityType.ClrType)
                    .Invoke(this, new object[] { builder, entityType });
            }
    
            base.OnModelCreating(builder);            
        }
    
        protected void ConfigureGlobalFilters<TEntity>(ModelBuilder builder, IMutableEntityType entityType)
                            where TEntity : class
        {
            Expression<Func<TEntity, bool>> expression = null;
            if (typeof(IEntityBase).IsAssignableFrom(typeof(TEntity)))
            {
                expression = e => ((IEntityBase)e).UserId == CurrentUserId;
                builder.Entity<TEntity>().HasQueryFilter(expression);
            }
        }
    }
    
    1. 通过下面的代码

      注册IHttpContextAccessor
          services.AddHttpContextAccessor();
      
    2. 为了集中控制UserId过滤器,我定义了IEntityBase
      //IEntityBase.cs

       public interface IEntityBase    {
          string UserId { get; set; }
          IdentityUser User { get; set; }
       }
      

//订单

    public class Order: IEntityBase
{
    public string Id { get; set; }
    public string OrderNo { get; set; }
    public string UserId { get; set; }
    public IdentityUser User { get; set; }
    public string Description { get; set; }
}