You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.Net MVC控制器构造函数Session为空错误及客户全局过滤方案咨询

嘿,我来帮你理清这个问题哈!首先你遇到的Session.get returned null错误,原因很明确——在ASP.NET MVC控制器的构造函数执行时,Session对象还没被框架初始化呢!这时候去拿Session里的值肯定拿不到。

那要实现「仅在单一位置过滤db.Customers,让控制器其余部分直接使用」的需求,有几个靠谱的方案,我给你拆解一下:

方案一:重写控制器的Initialize方法

控制器的Initialize方法是在Session已经可用之后才会执行的,刚好适合在这里做过滤操作。你可以这样修改代码:

public class SOSRController : Controller { 
    private BusinessContext db; 

    protected override void Initialize(RequestContext requestContext) {
        base.Initialize(requestContext);
        db = new BusinessContext();
        
        // 现在Session已经能正常访问了
        Employee employee = (Employee)Session["CurrentUser"];
        // 注意:直接强制转换DbSet可能有问题,建议改用IQueryable存储过滤结果
        // 可以给控制器新增一个属性:public IQueryable<Customer> FilteredCustomers { get; private set; }
        // 然后赋值:FilteredCustomers = db.Customers.Where(x => x.Business.Id == employee.bizId);
        db.Customers = db.Customers.Where(x => x.Business.Id == employee.bizId) as DbSet<Customer>;
    } 

    public ActionResult Index() { 
        // 后续直接用过滤后的集合即可
        List<Customer> LstCust= db.Customers.Where(x => x.Name.Contains("asd")).ToList();
        return View(LstCust);
    } 
}

这个方案的好处是控制器级别的过滤逻辑集中在Initialize里,后续Action直接调用就行,完美避开了Session未初始化的问题。

方案二:给DbContext添加全局查询过滤器(推荐)

如果这个业务过滤逻辑是全局的(所有用到BusinessContext的地方都需要过滤当前业务的客户),那把过滤逻辑放到DbContext里会更优雅。EF6及以上(包括EF Core)都支持全局查询过滤器:

EF Core版本实现:

在你的BusinessContext中添加全局过滤规则:

public class BusinessContext : DbContext {
    public DbSet<Customer> Customers { get; set; }
    // 新增属性存储当前用户的业务ID
    public int CurrentBizId { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        base.OnModelCreating(modelBuilder);
        
        // 添加全局查询过滤器,所有查询都会自动带上这个条件
        modelBuilder.Entity<Customer>().HasQueryFilter(c => c.Business.Id == CurrentBizId);
    }
}

然后在控制器的Initialize方法中设置当前业务ID:

public class SOSRController : Controller { 
    private BusinessContext db; 

    protected override void Initialize(RequestContext requestContext) {
        base.Initialize(requestContext);
        db = new BusinessContext();
        Employee employee = (Employee)Session["CurrentUser"];
        db.CurrentBizId = employee.bizId;
    } 

    public ActionResult Index() { 
        // 这里db.Customers会自动应用全局过滤条件
        List<Customer> LstCust= db.Customers.Where(x => x.Name.Contains("asd")).ToList();
        return View(LstCust);
    } 
}

EF6版本实现:

EF6没有原生的HasQueryFilter,但可以通过自定义DbSet包装类实现类似效果:

public class FilteredDbSet<T> : DbSet<T>, IQueryable<T> where T : class {
    private readonly DbSet<T> _innerSet;
    private readonly Expression<Func<T, bool>> _filter;

    public FilteredDbSet(DbSet<T> innerSet, Expression<Func<T, bool>> filter) {
        _innerSet = innerSet;
        _filter = filter;
    }

    public override IQueryable<T> AsQueryable() {
        return _innerSet.Where(_filter).AsQueryable();
    }

    // 根据需求重写Add、Remove等其他方法
}

然后在BusinessContext中替换Customers的声明:

public class BusinessContext : DbContext {
    private DbSet<Customer> _customers;
    public int CurrentBizId { get; set; }

    public DbSet<Customer> Customers {
        get {
            return new FilteredDbSet<Customer>(_customers, c => c.Business.Id == CurrentBizId);
        }
        set {
            _customers = value;
        }
    }
}

控制器的用法和EF Core版本一致,只需设置CurrentBizId即可。

这个方案的优势是过滤逻辑和数据上下文绑定,所有使用该DbContext的地方都会自动应用过滤,不用在每个控制器重复编写,维护起来更省心。

方案三:使用Action Filter

创建自定义Action Filter,在Action执行前完成过滤操作:

public class FilterCustomersAttribute : ActionFilterAttribute {
    public override void OnActionExecuting(ActionExecutingContext filterContext) {
        base.OnActionExecuting(filterContext);
        var controller = filterContext.Controller as SOSRController;
        if (controller != null) {
            Employee employee = (Employee)controller.Session["CurrentUser"];
            controller.db.Customers = controller.db.Customers.Where(x => x.Business.Id == employee.bizId) as DbSet<Customer>;
        }
    }
}

然后在控制器或特定Action上添加该特性:

[FilterCustomers]
public class SOSRController : Controller { 
    public BusinessContext db = new BusinessContext(); 

    public ActionResult Index() { 
        List<Customer> LstCust= db.Customers.Where(x => x.Name.Contains("asd")).ToList();
        return View(LstCust);
    } 
}

这个方案适合仅在特定Action上应用过滤的场景,但控制器和过滤器的耦合度稍高。

总结一下:如果需要全局过滤,优先选方案二(全局查询过滤器);如果只是当前控制器需要过滤,**方案一(重写Initialize)**更直接高效。

内容的提问来源于stack exchange,提问作者Waqas Javaid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:29:05