C# 正在验证ASP.NET MVC 3控制器';使用动态表达式API时的s操作参数

C# 正在验证ASP.NET MVC 3控制器';使用动态表达式API时的s操作参数,c#,asp.net-mvc-3,dynamic-linq,C#,Asp.net Mvc 3,Dynamic Linq,我有一个标准ASP.NET MVC 3控制器,其操作具有以下签名: public ActionResult索引(int?页,字符串排序,字符串排序) 我的视图使用WebGrid,因此参数由它自动生成 接下来,我使用动态表达式API(也称为动态LINQ)将参数转换为查询。例如: var customerSummary = CustomerManager.CustomerRepository.GetQuery() .OrderBy(sort + " " + sortDir)

我有一个标准ASP.NET MVC 3控制器,其操作具有以下签名:
public ActionResult索引(int?页,字符串排序,字符串排序)
我的视图使用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();
目标 我想做的是使用它自己来验证排序参数(也许还可以创建一个有效的lambda)。例如,我想使用
DynamicExpression.Parse()
DynamicExpression.ParseLambda()
方法查看它们是否生成
ParseException
,在这种情况下,我可以用默认值替换错误的参数(例如,按名称升序排序“名称ASC”)

问题 问题是,
IQueryable
扩展只接受一个字符串 如果我想使用
ParseLambda
,然后将其馈送到
.OrderBy
,我就不能使用direction(它只接受属性名)。例如,我可以这样做:

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(“名称”);//现在我可以使用.OrderBy(se),它与.OrderBy(c=>c.Name)相同
但不是这个

var se = DynamicExpression.ParseLambda<Customer, string>("Name DESC"); 
var se=DynamicExpression.ParseLambda(“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
}
bool doSort = typeof(Product).GetProperty(sort, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy /*Or whatever flags you need*/) != null
常见的一点是,在调用助手之前和之后,您可以自由应用任何筛选或smth

非常方便

当我需要扩展ViewModel时,我会继承它并向子模型添加新成员

UPD:如果您决定保留DLINQ,请尝试以下签名-
OrderBy(“名称”,“升序”)

UPD2:如果要验证排序参数,我认为反射是唯一的选择。大概是这样的:

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
}
bool doSort = typeof(Product).GetProperty(sort, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy /*Or whatever flags you need*/) != null
这样,只有当
doSort
为true时,才应该应用
OrderBy
/
OrderByDescending
逻辑。否则,只需跳过排序或应用任何默认逻辑即可

在我看来,您希望从代码中获得的功能越多,DLINQ似乎就越不适合它。一旦获得了
PropertyInfo
,下一个合理的步骤就是在表达式中使用它。一旦我们这样做了,DLINQ的位置在哪里?:)


我同意表达式和反射代码在操作上非常难看,但将其移到外部,例如,到ExtensionMethod(在我的例子中),或者在控制器基类的非操作方法中,可以避免您的眼睛看到它:)

我想使用动态LINQ(作为皮尤问题)。但除此之外,如何在示例中验证“sort”参数?如何确保“排序”是参考底图模型上的有效属性?:)我已经更新了答案(见UPD2)。为了向DLINQ订购,你没看到我的第一个UPD吗?它对你有用吗?顺便说一句,如果你传递了一个错误的字段名,DLINQ会怎么做?它会引发异常吗?是的,动态LINQ有解析方法,当表达式不正确时会引发ParseException。您使用反射的方法是有效的,我以前也曾使用过这种方法,但我的问题是如何使用动态LINQ实现它。。。