网站备案网站名称怎么填,云南省建设学校网站,建网站出现ie6,专业网站建设信息ASP.NET MVC 引入了 ModelBinder 技术#xff0c;让我们可以在 Action 中以强类型参数的形式接收 Request 中的数据#xff0c;极大的方便了我们的编程#xff0c;提高了生产力。在查询 Action 中#xff0c;我们可以将 Expression Trees 用作参数#xff0c;通过自定义的…ASP.NET MVC 引入了 ModelBinder 技术让我们可以在 Action 中以强类型参数的形式接收 Request 中的数据极大的方便了我们的编程提高了生产力。在查询 Action 中我们可以将 Expression Trees 用作参数通过自定义的 ModelBinder 动态自动构建查询表达式树进一步发挥 MVC 的威力简化编码工作。 MVC 查询和存在的不足 下面是一个查询 Employee 的 Action在 MVC 项目中经常可以见到 public ActionResult Index(string firstName, string lastName, DateTime? birthday, bool? sex) {var employees repository.Query();if (firstName.IsNotNullAndEmpty()) employees employees.Where(e e.FirstName.Contains(firstName));if (firstName.IsNotNullAndEmpty()) employees employees.Where(e e.LastName.Contains(lastName));if (birthday.HasValue) employees employees.Where(e e.Birthday.Value.Date birthday.Value.Date);if (sex.HasValue) employees employees.Where(e e.Sex sex);return View(employees);
} 得益于 MVC 的绑定技术我们可以简单通过 Action 的参数来获取请求的值很少再使用 Request[XXXX] 的方式。 仔细观察会发现上面这个 Action 中充斥着大量 if 判断以致代码行数比较多不是特别清晰。 public ActionResult Index2(string firstName, string lastName, DateTime? birthday, bool? sex) {var employees repository.Query().WhereIf(e e.FirstName.Contains(firstName), firstName.IsNotNullAndEmpty()).WhereIf(e e.LastName.Contains(lastName), lastName.IsNotNullAndEmpty()).WhereIf(e e.Birthday.Value.Date birthday.Value.Date, birthday.HasValue).WhereIf(e e.Sex sex, sex.HasValue);return View(Index, employees);
} 代码相清晰了许多我之前的几个 MVC 项目中也是这样处理的。 但时间一长我逐步也发现了这种方式一些不足之处 首先网站中有很多类似的查询如Customer、Order、Product 等等。而且大致也有点规律字符串的一般模糊查询时间日期类的一般按日期查询忽略时间其它类型则相等查询。不同 Model 查询的 Action 编码总有八、九分相似但又不是简单的重复却又难以重构。需求变动如增加一个查询条件修改 View 是必须的但也要修改 Action增加一个参数还要加一行 Where 或 WhereIf。简单变动却多处修改烦人啊而且这种需求变动又是比较频繁的尤其是在项目初期。若能只修改 View 而不修改 Action 就爽了。思考后我决定使用 Expression Trees 作为查询 Action的参数来弥补这些不足。 使用 ExpressionFuncT, bool 作为 Action 的参数 public ActionResult Index3(ExpressionFuncEmployee, bool predicate) {var employees repository.Query().Where(predicate);return View(Index, employees);
} 将 Expression Trees 作为 Action 的唯一的参数暂不考虑分页、排序等将所有的查询条件都统一汇集至 predicate 参数。 所有的查询不管是 Employee 还是 Customer都使用如上代码。其它实体查询只需修改参数的类型如 Customer 查询改为 ExpressionFuncCustomer, bool 。 如上修改代码后直接运行会报错因为 MVC 中默认的数据绑定器 DefaultModelBinder 不能正确绑定 ExpressionFuncT, bool 类型的参数。 我们要新创一个新的 ModelBinder。 创建 QueryConditionExpressionModelBinder 需要一个新的 ModelBinder 来为 ExpressionFuncT, bool 类型的参数赋值且命名为 QueryConditionExpressionModelBinder。 QueryConditionExpressionModelBinder 要根据上下文来自动生成查询的 Expression Trees。主要关注的上下文有两点首先是当前 Model 的类型即 typeof(T)其次是 Request 提供的值可通过 ValueProvider 获取。 下面给出一个粗略实现仅用来说明这个思路是可行的 public class QueryConditionExpressionModelBinder : IModelBinder {public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {var modelType GetModelTypeFromExpressionType(bindingContext.ModelType);if (modelType null) return null;var body default(Expression);var parameter Expression.Parameter(modelType, modelType.Name);foreach (var property in modelType.GetProperties()){var queryValue GetValueAndHandleModelState(property, bindingContext.ValueProvider, controllerContext.Controller);if (queryValue null) continue;Expression proeprtyCondition null;if (property.PropertyType typeof (string)){if (!string.IsNullOrEmpty(queryValue as string)){proeprtyCondition parameter.Property(property.Name).Call(Contains, Expression.Constant(queryValue));}}else if (property.PropertyType typeof (DateTime?)){proeprtyCondition parameter.Property(property.Name).Property(Value).Property(Date).Equal(Expression.Constant(queryValue));}else{proeprtyCondition parameter.Property(property.Name).Equal(Expression.Constant(queryValue));}if (proeprtyCondition ! null)body body ! null ? body.AndAlso(proeprtyCondition) : proeprtyCondition;}if (body null) body Expression.Constant(true);return body.ToLambda(parameter);}/// summary/// 获取 ExpressionFuncTXXX, bool 中 TXXX 的类型/// /summaryprivate Type GetModelTypeFromExpressionType(Type lambdaExpressionType) {if (lambdaExpressionType.GetGenericTypeDefinition() ! typeof (Expression)) return null;var funcType lambdaExpressionType.GetGenericArguments()[0];if (funcType.GetGenericTypeDefinition() ! typeof (Func,)) return null;var funcTypeArgs funcType.GetGenericArguments();if (funcTypeArgs[1] ! typeof (bool)) return null;return funcTypeArgs[0];}/// summary/// 获取属性的查询值并处理 Controller.ModelState /// /summaryprivate object GetValueAndHandleModelState(PropertyInfo property, IValueProvider valueProvider, ControllerBase controller) {var result valueProvider.GetValue(property.Name);if (result null) return null;var modelState new ModelState {Value result};controller.ViewData.ModelState.Add(property.Name, modelState);object value null;try{value result.ConvertTo(property.PropertyType);}catch (Exception ex){modelState.Errors.Add(ex);}return value;}
} 如果不想在 Global.asax 文件中设置 ExpressionFuncT, bool 的 ModelBinder 可以借助用下面这个 Attribute 类 public class QueryConditionBinderAttribute : CustomModelBinderAttribute {public override IModelBinder GetBinder() {return new QueryConditionExpressionModelBinder();}
} Index3 简单修改如下 public ActionResult Index3([QueryConditionBinder]ExpressionFuncEmployee, bool predicate) { //... } 转载于:https://www.cnblogs.com/wd0730/p/3213457.html