我有一个Javascript Kendo Grid,我试图使用MVC Web Api进行服务器端排序。一切都在工作,除了排序。这是HTML代码:
<script type="text/javascript">
$(function() {
$("#gridTrades").kendoGrid({
sortable: true,
columns: [{ field: "tradeName", title: "Name", width: "250px" }, { field: "isActive", title: "Active", template: '#= isActive ? "<i class=\'fa fa-check\'></i>" : "" #', width: "100px" }],
dataSource: {
serverPaging: true,
serverFiltering: false,
serverSorting: true,
pageSize: 3,
schema: {
data: "data",
total: "total",
model: {
fields: {
id: { editable: false, type: "number" },
tradeName: { editable: false, type: "string" },
isActive: { editable: false, type: "boolean"}
}
}
},
batch: false,
transport: {
read: {
url: "/api/v1/Trades"
}
}
}
});
});
</script>
这是我的Web Api代码:
[System.Web.Http.HttpGet]
[System.Web.Http.Route("api/v1/Trades")]
public IHttpActionResult GetTrades(int page = -1, int pageSize = -1, int skip = -1, int take = -1, string[][] sort = null)
{
var trades = new BusinessLayer.VipScheduler.Trades();
var total = BusinessLayer.VipScheduler.LoadData.FromSqlStatement<Models.Settings.GetTradesReturnModel>($"SELECT COUNT(*) AS Total FROM {BusinessLayer.VipScheduler.Trade.LgTableName}");
trades.GetAll();
var retval = new Models.Settings.GetTradesReturnModel {Total = total[0].Total};
foreach (var trade in trades.OrderByDescending(z => z.IsActive).ThenBy(z => z.TradeName))
{
retval.Data.Add(new Models.Settings.GetTradesReturnModelData
{
Id = trade.TradeId,
IsActive = trade.IsActive,
TradeName = trade.TradeName
});
}
return Ok(retval);
}
我遇到的问题是使用sort参数。如果我完全取消sort参数,Kendo Grid工作正常,除了排序不起作用。如果我按照上面的说法打开sort参数,我会收到500错误:
可选参数&#39; sort&#39; &#39; FormatterParameterBinding&#39;。
不支持
以下是Kendo Grid发送的请求:
GET /api/v1/Trades?take=3&skip=0&page=1&pageSize=3&sort%5B0%5D%5Bfield%5D=tradeName&sort%5B0%5D%5Bdir%5D=asc
任何有关使此排序参数起作用的帮助都将不胜感激!
答案 0 :(得分:1)
为了防止您现在遇到错误 - 只需将sort
参数设为非可选项(将其移至参数列表的开头并删除= null
)。如果它无法绑定(例如,在查询字符串中未指定排序) - 它仍然会有null
值,因此在这种情况下没有理由使= null
默认。
现在,您的排序规范分为多个查询字符串参数:
sort[0][field]=tradeName&sort[0][dir]=asc
因此要将其绑定到模型,您需要一个自定义模型绑定器。首先创建表示排序规范的类:
public class KendoSortSpecifier {
public string Field { get; set; }
public string Direction { get; set; }
}
然后自定义模型绑定器(这只是一个示例,必要时根据您自己的需要调整):
public class KendoSortSpecifierBinder : System.Web.Http.ModelBinding.IModelBinder {
private static readonly Regex _sortFieldMatcher;
private static readonly Regex _sortDirMatcher;
const int MaxSortSpecifiers = 5;
static KendoSortSpecifierBinder() {
_sortFieldMatcher = new Regex(@"^sort\[(?<index>\d+)\](\[field\]|\.field)$", RegexOptions.Singleline | RegexOptions.Compiled);
_sortDirMatcher = new Regex(@"^sort\[(?<index>\d+)\](\[dir\]|\.dir)$", RegexOptions.Singleline | RegexOptions.Compiled);
}
public bool BindModel(HttpActionContext actionContext, System.Web.Http.ModelBinding.ModelBindingContext bindingContext) {
if (bindingContext.ModelType != typeof(KendoSortSpecifier[]))
return false;
var request = actionContext.Request;
var queryString = request.GetQueryNameValuePairs();
var result = new List<KendoSortSpecifier>();
foreach (var kv in queryString) {
var match = _sortFieldMatcher.Match(kv.Key);
if (match.Success) {
var index = int.Parse(match.Groups["index"].Value);
if (index >= MaxSortSpecifiers)
continue;
while (result.Count <= index) {
result.Add(new KendoSortSpecifier());
}
result[index].Field = kv.Value;
}
else {
match = _sortDirMatcher.Match(kv.Key);
if (match.Success) {
var index = int.Parse(match.Groups["index"].Value);
if (index >= MaxSortSpecifiers)
continue;
while (result.Count <= index) {
result.Add(new KendoSortSpecifier());
}
result[index].Direction = kv.Value;
}
}
}
bindingContext.Model = result.Where(c => !String.IsNullOrEmpty(c.Field)).ToArray();
return true;
}
}
最后你的控制器方法签名:
public IHttpActionResult GetTrades(
[System.Web.Http.ModelBinding.ModelBinder(typeof(KendoSortSpecifierBinder))]
KendoSortSpecifier[] sort,
int page = -1,
int pageSize = -1,
int skip = -1,
int take = -1)
现在你有一个强类型的排序模型(除了Direction
可以用枚举而不是字符串表示),并且可以根据需要使用它来对数据进行排序。
答案 1 :(得分:0)
我建议你重构你的API方法。而不是给它提供路线参数,使用这样的DTO:
public IHttpActionResult GetTrades(GetTradesRequestDTO model)
{
// method body
}
无论如何,这是最佳实践,并且模型绑定问题被最小化。此外,我不确定您为什么要为参数提供 -1 的默认值。而是使用从零开始的索引。这可能是个人偏好,但我不确定这些负面价值会带来什么。最后你的sort参数也需要一个重构器。它可以是字符串列表,也可以是强类型模型的集合,每个模型定义一个排序操作。即List<SortAction> sort;
。您如何使用此信息并实施后端数据访问与此无关。
重构您的操作方法,模型绑定和参数数据类型应该可以解决您的问题。虽然我是根据经验编写的,但实际上并未在我的机器上测试过您的代码。