ASP.NET MVC中如何将predicate作为参数传入IActionResult方法
问题根源
这种传参方式本身不可行,原因有两个:
RedirectToAction是通过将参数序列化到URL的查询字符串来传递数据的,而Func<model,bool>是委托类型,无法被序列化为普通字符串;同时ASP.NET Core MVC的默认模型绑定器也没有能力将URL字符串反序列化为委托实例,所以当你给Index方法加上这个参数后,无论是直接访问首页没有传参触发模型绑定校验失败,还是从搜索方法跳转传参失败,都会导致页面报错。- 你当前的写法存在性能问题:
IQueryable的Where方法如果接收的是Func<T,bool>类型参数,会直接触发查询把全表数据加载到内存中再执行过滤,而非在数据库层面执行WHERE语句,数据量大时性能会非常差,正确的应该使用Expression<Func<model,bool>>作为参数类型,哪怕是这样表达式树依然无法通过URL序列化传递。
解决方案
不要试图在Action之间传递谓词,将查询条件构建逻辑封装为独立的公共方法,所有需要用到查询的地方直接调用该方法构建条件即可,参考实现如下:
// 通用条件构建方法 private Expression<Func<Model, bool>> BuildSearchPredicate(object searchArgs = null) { var predicate = PredicateBuilder.New<Model>(true); // 匹配Search1的参数类型 if (searchArgs is Parameters search1Params) { predicate = predicate.And(s => s.Number1 == search1Params.Number1); predicate = predicate.And(s => s.Number2 >= search1Params.Number2); // 其他Search1的条件 } // 匹配Search2的参数类型 else if (searchArgs is string search2Str && !string.IsNullOrWhiteSpace(search2Str)) { var searchStr = search2Str.Trim(); predicate = predicate.And(s => s.publisher1.Contains(searchStr) || s.publisher2.Contains(searchStr)); // 其他Search2的条件 } return predicate; } // 首页方法移除委托参数 public async Task<IActionResult> Index() { var predicate = BuildSearchPredicate(); var data = await _context.Model.Where(predicate).ToListAsync(); return View(data); } // Search1方法直接返回Index视图,不需要跳转 [HttpPost] public async Task<IActionResult> Search1(Parameters parameters) { if (!ModelState.IsValid) { return RedirectToAction(nameof(Index)); } var predicate = BuildSearchPredicate(parameters); var data = await _context.Model.Where(predicate).ToListAsync(); return View("Index", data); } // Search2方法同理 [HttpPost] public async Task<IActionResult> Search2(string searchString) { var predicate = BuildSearchPredicate(searchString); var data = await _context.Model.Where(predicate).ToListAsync(); return View("Index", data); }
如果确实需要使用跳转逻辑而非直接返回视图,可以将搜索参数通过TempData或者URL查询字符串传递,在Index方法中接收参数后再调用条件构建方法生成谓词即可。
内容的提问来源于stack exchange,提问作者mark_da_rat
相关产品推荐
相关产品推荐

