使用动态表达式 API 时验证 MVC 3 控制器 ASP.NET 操作参数
本文关键字:控制器 ASP NET 参数 操作 MVC 验证 动态 表达式 API | 更新日期: 2023-09-27 18:30:25
我有一个标准的 ASP.NET MVC 3 控制器,其操作具有以下签名: public ActionResult Index(int? page, string sort, string sortDir)
我的视图使用的是WebGrid,因此参数是由它自动生成的。
接下来,我使用动态表达式 API(又名动态 LINQ)将参数转换为查询。例:
var customerSummary = CustomerManager.CustomerRepository.GetQuery()
.OrderBy(sort + " " + sortDir)
.Select(c => new CustomerSummaryViewModel()
{
Id = c.Id,
Name = c.Name,
IsActive = c.IsActive,
OrderCount = c.Orders.Count
})
.Skip(page.Value - 1 * 10) //10 is page size
.Take(10)
.ToList();
目标
我想做的是使用动态表达式 API 本身来验证排序参数(并可能创建一个有效的 lambda)。例如,我想使用DynamicExpression.Parse()
或DynamicExpression.ParseLambda()
方法来查看它们是否产生ParseException
,在这种情况下,我可以用默认值替换错误的参数(例如,按名称升序排序"名称ASC")...
问题所在
问题是IQueryable
扩展只接受一个字符串如果我想使用 ParseLambda
然后将其提供给.OrderBy
我不能使用方向(它只接受属性名称)。例如,我可以这样做:
var se = DynamicExpression.ParseLambda<Customer, string>("Name"); // now I can use .OrderBy(se) which is same as .OrderBy(c=>c.Name)
但不是这个
var se = DynamicExpression.ParseLambda<Customer, string>("Name DESC");
回顾
我想使用动态 LINQ 来 1) 验证和 2) 基于操作参数构建谓词(用于排序)
我对 Dymaic LINQ 不是很熟悉,但您可以执行以下操作:
var customerSummary = CustomerManager.CustomerRepository.GetQuery();
if ("desc".Equals(sortDir, StringComparison.CurrentCultureIgnoreCase))
customerSummary = customerSummary.OrderByDescending(sort);
else
customerSummary = customerSummary.OrderBy(sort);
var pageNumber = page.GetValueOrDefault();
if (pageNumber < 1)
pageNumber = 1;
customerSummary = customerSummary
.Select(c => new CustomerSummaryViewModel()
{
Id = c.Id,
Name = c.Name,
IsActive = c.IsActive,
OrderCount = c.Orders.Count
})
.Skip((pageNumber - 1) * 10)
.Take(10)
.ToList();
我在我的项目中做了类似的事情(除了我使用了原始表达式),但走得更远。
我创建了一个基本的视图模型,如下所示:
class TableViewModel
{
public string SortColumn { get; set; }
public bool IsAsc { get; set; }
public int? PageNumber { get; set; }
}
并创建了一个完成所有分页/排序工作的帮助程序方法。签名是这样的:
public static IQueryable<T> TableHelper(this IQueryable<T> source, TableViewModel model) { ... }
当我需要从表控件接收数据并返回请求的数据片段时,控制器操作如下所示:
public ActionResult Index(TableViewModel model)
{
var data = _productRepository.AsQueryable().TableHelper(model);
... //Operation on data
}
通常的事情是,在调用助手之前和之后,您可以自由应用任何过滤或smth。
这非常方便。
当我需要扩展我的视图模型时,我会继承它并向子模型添加新成员。
UPD:如果您决定保留 DLINQ,请尝试以下签名 - OrderBy("Name", "ascending");
UPD2:如果你想验证你的排序参数,我认为反射是唯一的选择。像这样:
bool doSort = typeof(Product).GetProperty(sort, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy /*Or whatever flags you need*/) != null
这样,只有当doSort
为真时,才应该应用 OrderBy
/OrderByDescending
逻辑。否则,只需跳过排序或应用任何默认逻辑。
在我看来,您希望从代码中获得的功能越多,DLINQ 似乎就越不适合它。获得PropertyInfo
后,下一个合理的步骤可能是在表达中使用它。一旦我们这样做了,DLINQ会在哪里?:)
我同意表达式和反射代码在操作中非常丑陋,但是将其移到外面,例如,移动到 ExtensionMethod,就像我的情况一样,或者在控制器基类的非操作 mehod 中,可以避免你的眼睛看到它:)