【发布时间】:2018-09-21 03:51:28
【问题描述】:
问题:
我的 Angular JS html 页面中有 Kendo Grid。 Kendo Grid 数据来自我的远程服务 Web API。
当我们进行分页(或第一次加载页面)时,Kendo 网格尝试在浏览器中为每 10 条记录下载 38 MB 的内容,这大约需要 10 分钟。 6 分钟加载数据。
38 MB 下载了什么内容?
我已经通过阅读/学习堆栈溢出的类似支持票来实现:
已实现服务器分页 true(pageSize = 10,总记录 = 大约 56000)
JS 和 CSS 的捆绑
-
我尝试了以下两个选项:
可滚动:{虚拟:真实} 要么 可滚动:{ 无尽:真 }
我在生产中检查了我的存储过程,它在不到 3 秒的时间内执行了大约。 55000 条记录。 (在生产和暂存两台服务器上)。
我检查了我的 Web API 控制器,它在不到 4 秒的时间内将响应返回到 kendo grid,然后 kendo grid 需要太多时间来填充数据。
-
我有以下用于剑道的 JS 和 CSS(已经实现捆绑):
- Kendo.all.min.js
- kendo.bootstrap.min.css
- kendo.common-bootstrap.min.css
- 项目所需的其他 JS 和 CSS 也以捆绑方式加载。
以下是我的实时项目页面:
HTML 页面:
<div id="heatMapGrid" kendo-grid k-options="vm.heatMapGridOptions"></div>
AngularJS 控制器:
var dataSourceHeatMapGrid = new kendo.data.DataSource({
transport: {
read: function (options) {
heatMapService.getHeatMapGrid(options.data, heatMapGridParams)
.then(function (response) {
options.success(response.data);
$rootScope.optioncallback = options;
//$scope.htmapGridCSV = [];
//$scope.htmapGridCSV = response.data.exportData;
}).catch(function (e) {
console.log('Error: ', e);
throw e;
});
},
parameterMap: function (options) {
return JSON.stringify(options);
}
},
schema: {
data: function (response) {
return response.gridData;
},
total: function (response) {
return response.Total;
},
model: {
fields: {
TPID: { type: "number" },
TPName: { type: "string" },
EndCustomerPurchaseAmt: { type: "number" },
PrimaryExpirationMonth: { type: "string" },
AgreementID: { type: "number" },
TotalPurchased: { type: "number" },
TotalAssigned: { type: "number" },
OverUnder: { type: "number" },
VSEntPurchasedUnits: { type: "number" },
VSProMSDNUnits: { type: "number" },
VSTestProMSDNUnits: { type: "number" },
MSDNPlat: { type: "number" },
CloudPurchasedUnits: { type: "number" },
UnbilledOverage: { type: "number" },
AzurePotentialRevenue: { type: "number" }
}
}
},
pageSize: 10,
serverPaging: true
});
vm.heatMapGridOptions = {
columns: [
{ "title": "", template: "<a title='#=TPID#' #=isPinnedAccount==1 ? \"class='terrunpinaccount'\" : \"class='terrpinaccount'\"# ng-click='vm.pinUnpinAccount(\"#=TPID#\")'></a>" },
{ "title": "Account Name", "field": "TPName", template: "<a href='javascript:void(0);' ng-click='vm.tPIDDetails(\"#=TPID#\",\"#=TPName#\")' title='#=TPName#'><div class='DisplayTitleTPName'>#=TPName#<ul><li>AM: #=AM#, OM: #=OperatingModel#, Country: #=Country#</li><li>DevSales Lead: #=SalesLead#, SSP: #=Dev_SSP#, TSP: #=DevTSP#</li></ul></div></a>", headerAttributes: { style: "white-space: normal; overflow: visible;" } },
{
"title": "PERFORMANCE AND ANNIVERSARIES", headerAttributes: { style: "text-align: center;font-weight: bold;" },
columns:
[{
"title": "Renewals and True Ups", headerAttributes: { style: "text-align: center;font-weight: bold;" },
columns: [{ "title": "Total Annualized Expiring", "field": "EndCustomerPurchaseAmt", format: "{0:c0}", headerAttributes: { style: "white-space: normal; overflow: visible;" } },
{ "title": "Primary Anniversary Month", "field": "PrimaryExpirationMonth", headerAttributes: { style: "white-space: normal; overflow: visible;" } },
{ "title": "Agreement Number", "field": "AgreementID", format: "{0:n0}", headerAttributes: { style: "white-space: normal; overflow: visible;" } }]
}]
},
{
"title": "EFFECTIVE LICENSE POSITIONS", headerAttributes: { style: "text-align: center;font-weight: bold;" },
columns:
[{
"title": "Visual Studio Subscriptions", headerAttributes: { style: "text-align: center;font-weight: bold;" },
columns: [{ "title": "Purchased", "field": "TotalPurchased", format: "{0:n0}" },
{ "title": "Assigned", "field": "TotalAssigned", format: "{0:n0}" },
{ "title": "Over Under", "field": "OverUnder", format: "{0:n0}" }]
},
{
"title": "Account Footprint (Active SA Licenses)", headerAttributes: { style: "text-align: center;font-weight: bold;" },
columns: [{ "title": "Enterprise w/ MSDN", "field": "VSEntPurchasedUnits", format: "{0:n0}", headerAttributes: { style: "white-space: normal; overflow: visible;" } },
{ "title": "Pro w/ MSDN", "field": "VSProMSDNUnits", format: "{0:n0}", headerAttributes: { style: "white-space: normal; overflow: visible;" } },
{ "title": "Test Pro w/ MSDN", "field": "VSTestProMSDNUnits", format: "{0:n0}", headerAttributes: { style: "white-space: normal; overflow: visible;" } },
{ "title": "MSDN Platforms", "field": "MSDNPlat", format: "{0:n0}", headerAttributes: { style: "white-space: normal; overflow: visible;" } },
{ "title": "Cloud", "field": "CloudPurchasedUnits", format: "{0:n0}" }]
},
{
"title": "Azure", headerAttributes: { style: "text-align: center;font-weight: bold;" },
columns: [{ "title": "Unbilled Overage", "field": "UnbilledOverage", format: "{0:c0}", headerAttributes: { style: "white-space: normal; overflow: visible;" } },
{ "title": "Potential Revenue", "field": "AzurePotentialRevenue", headerTemplate: '<span title="Potential Revue is based on the delta of activated seats and <br/> developers deploying to Azure multiplied by the annual <br/> value of an Azure attached developer ($15k)">Potential Revenue</span>', format: "{0:c0}", headerAttributes: { style: "white-space: normal; overflow: visible;" } }]
}]
}
],
groupable: false,
sortable: true,
resizable: true,
//pageable: true,
pageable: {
refresh: true,
pageSizes: [10, 20, 50],
},
columnMenu: true,
scrollable: false
//filterable: true
};
$("#heatMapGrid").data("kendoGrid").setDataSource(dataSourceHeatMapGrid);
AngularJS 服务:
services.getHeatMapGrid = function (command, heatMapGridParams) {
var data = {
page: command.page,
pageSize: command.pageSize,
skip: command.skip,
take: command.take,
alias: heatMapGridParams.alias,
hasDevTest: heatMapGridParams.hasDevTest,
hasDevTestLabs: heatMapGridParams.hasDevTestLabs,
hasXamarin: heatMapGridParams.hasXamarin,
devOpsMSShopFlag: heatMapGridParams.devOpsMSShopFlag,
devOpsOSSThirdPartyShopsFlag: heatMapGridParams.devOpsOSSThirdPartyShopsFlag,
intelligentAppsFlag: heatMapGridParams.intelligentAppsFlag,
paaSServicesFlag: heatMapGridParams.paaSServicesFlag,
enterpriseStepUpFlag: heatMapGridParams.enterpriseStepUpFlag,
devsLearningAzureFlag: heatMapGridParams.devsLearningAzureFlag,
devOpsAcceleratorEligibleFlag: heatMapGridParams.devOpsAcceleratorEligibleFlag,
overAssignedFlag: heatMapGridParams.overAssignedFlag,
lowAssignmentsFlag: heatMapGridParams.lowAssignmentsFlag,
hasCloudSubscriptionFlag: heatMapGridParams.hasCloudSubscriptionFlag,
hasUnbilledOverageFlag: heatMapGridParams.hasUnbilledOverageFlag,
hasDevTestOppty: heatMapGridParams.hasDevTestOppty,
areaID: heatMapGridParams.areaID,
countryID: heatMapGridParams.countryID,
segmentID: heatMapGridParams.segmentID,
subsegmentID: heatMapGridParams.subsegmentID,
salesUnitID: heatMapGridParams.salesUnitID,
agreementRenewalOrTrueupID: heatMapGridParams.agreementRenewalOrTrueupID,
aM: heatMapGridParams.aM,
industry: heatMapGridParams.industry,
hasAppServOppty: heatMapGridParams.hasAppServOppty,
hasDotNetDeveloperFlag: heatMapGridParams.hasDotNetDeveloperFlag,
paaSReadyFlag: heatMapGridParams.paaSReadyFlag,
startMonth: heatMapGridParams.startMonth,
endMonth: heatMapGridParams.endMonth
};
return $http({ method: 'GET', url: config.apiUrl + 'Account/HeatMapGrid/', params: data });
};
网络 API:
[HttpGet]
public heatMapGridAndExport HeatMapGrid([FromUri]HeatMapGridModel model)
{
ListView listView = new ListView();
List<getHeatMapDataGlobalFilter_Result> listGridDataForTotalCount = new List<getHeatMapDataGlobalFilter_Result>();
listGridDataForTotalCount = listView.GetListViewGridData(model.alias, model.hasDevTest, model.hasDevTestLabs, model.hasXamarin, model.devOpsMSShopFlag, model.devOpsOSSThirdPartyShopsFlag, model.intelligentAppsFlag, model.paaSServicesFlag, model.enterpriseStepUpFlag, model.devsLearningAzureFlag, model.devOpsAcceleratorEligibleFlag, model.overAssignedFlag, model.lowAssignmentsFlag, model.hasCloudSubscriptionFlag, model.hasUnbilledOverageFlag, model.hasDevTestOppty, model.areaID, model.countryID, model.segmentID, model.subsegmentID, model.salesUnitID, model.agreementRenewalOrTrueupID, model.aM, model.industry, model.hasAppServOppty, model.hasDotNetDeveloperFlag, model.paaSReadyFlag, model.startMonth, model.endMonth);
List<getHeatMapDataGlobalFilter_Result> listGridData = new List<getHeatMapDataGlobalFilter_Result>();
listGridData = listGridDataForTotalCount.Skip(model.skip).Take(model.take).OrderByDescending(c => c.EndCustomerPurchaseAmt).ToList();
//List<heatMapExport> listExportData = new List<heatMapExport>();
//listExportData = listGridDataForTotalCount.Select(c => new heatMapExport()
//{
// TPName = c.TPName,
// TPID = c.TPID,
// OperatingModel = c.OperatingModel,
// Area = c.Area,
// Country = c.Country,
// CreditedRegion = c.CreditedRegion,
// CreditedDistrict = c.CreditedDistrict,
// Segment = c.Segment,
// ATUManager = c.ATUManager,
// Dev_SSP = c.Dev_SSP,
// AM = c.AM,
// Industry = c.Industry,
// ATSName = c.ATSName,
// AssignedPect = string.Format("{0:p0}", c.AssignedPect),
// ActivatedPect = string.Format("{0:p0}", c.ActivatedPect),
// AzureActivated = Convert.ToString(c.AzureActivated),
// EndCustomerPurchaseAmt = string.Format("{0:c0}", c.EndCustomerPurchaseAmt),
// PrimaryExpirationMonth = Convert.ToString(c.PrimaryExpirationMonth),
// AgreementID = Convert.ToString(c.AgreementID),
// TotalPurchased = string.Format("{0:n0}", c.TotalPurchased),
// TotalAssigned = string.Format("{0:n0}", c.TotalAssigned),
// OverUnder = string.Format("{0:n0}", c.OverUnder),
// VSEntPurchasedUnits = string.Format("{0:n0}", c.VSEntPurchasedUnits),
// VSProMSDNUnits = string.Format("{0:n0}", c.VSProMSDNUnits),
// VSTestProMSDNUnits = string.Format("{0:n0}", c.VSTestProMSDNUnits),
// MSDNPlat = string.Format("{0:n0}", c.MSDNPlat),
// CloudPurchasedUnits = string.Format("{0:n0}", c.CloudPurchasedUnits),
// UnbilledOverage = string.Format("{0:c0}", c.UnbilledOverage),
// AzurePotentialRevenue = string.Format("{0:c0}", c.AzurePotentialRevenue)
//}).ToList();
var heatMapData = new heatMapGridAndExport
{
gridData = listGridData,
//exportData = listExportData,
Total = listGridDataForTotalCount.Count()
};
return heatMapData;
}
我的环境:
版本 Telerik Control - Kendo UI v2017.2.621
操作系统开发机器 - Windows 10 Enterprise(8 GB RAM,Intel Core i7 处理器,64 位)(客户端操作系统)
浏览器 - Google Chrome,版本 65.0.3325.181
.NET Framework - 版本 4.6.1
Visual Studio - Enterprise 2015,版本 14.0.25431.01(更新 3)
编码语言 - C#
这是我的生产服务器浏览器屏幕截图:
这是我单击第二页时的另一个屏幕截图,它再次下载 38 mb 的内容,大约需要 38 mb。 6 分钟。 (服务器分页 = true 和 pageSize = 10)
代码调试截图:
我做错了什么?谁能帮帮我。
提前谢谢你。
【问题讨论】:
-
您能否禁用将大约 56K 行导出数据附加到 WebAPI 响应的行并查看其执行情况? (为清楚起见,请在下面回答)。我怀疑这是你的问题
-
@JoeGlover,感谢您的回复。但我已经尝试过评论整个导出功能,但对下载的时间或内容没有影响。即删除导出功能没有任何改善。任何其他帮助表示赞赏。再次感谢。
-
这将有助于准确查看 38Mb 中的内容,方法是在 WebAPI 返回响应之前断点(根据您之前的评论,我猜
heatMapData.gridData因此必须包含整个数据集),或检查在线路上出现的 JSON。您应该能够在 Chrome 开发工具中深入研究,或者使用 Fiddler、Wireshark 等外部工具。 -
要尝试的另一件事是您的 Linq 方法调用的顺序。我正在修改我原来的答案以表明我的意思。
-
@JoeGlover 以前我也有同样的想法,但后来我通过调试代码检查了 WebAPI 响应中的
heatMapData.gridData并检查了提琴手,但在这两次它都只包含 10 条记录而不是完整的数据集(因为我使用了跳过和获取)对于排序,我在跳过/获取之前通过交换排序子句进行了检查,但没有效果,还尝试通过删除排序,但两次都没有运气。任何其他帮助表示赞赏。谢谢
标签: javascript angularjs asp.net-web-api kendo-ui kendo-grid