Узкие результаты SQL для владельца на уровне контроллера (или выше), а не на уровне метода

SumNone спросил: 13 июня 2018 в 09:56 в: asp.net

Я выполняю проект в 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 ответа

Mark G ответил: 13 июня 2018 в 10:55

Попробуйте использовать Global Query Filters, которые были введены в EF Core 2.0 для этого варианта использования.

Edward ответил: 14 июня 2018 в 04:06

Для достижения вашего требования есть две части: один реализует 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. Зарегистрировать по коду ниже

          services.AddHttpContextAccessor();
      
    2. Для центра управления фильтром UserId я определил IHttpContextAccessor
      / /IEntityBase.cs

       public interface IEntityBase    {
          string UserId { get; set; }
          IdentityUser User { get; set; }
       }
      
    3. ол>
  2. ол> // Order
        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; }
    }
    

Дополнительное видео по вопросу: Узкие результаты SQL для владельца на уровне контроллера (или выше), а не на уровне метода

ASP.NET. Система регистрации на C# + SQL. Урок 8

ASP NET MVC 5 - 5.2. Подключение к базе данных

ASP.NET Core 2.1 Web API with SQL Server