.NET C#中Kendo动态网格导出Excel空引用异常解决求助
动态Kendo网格导出Excel触发空引用异常的解决方案
在.NET C#环境中使用动态列配置的Kendo网格时,导出Excel操作触发空引用异常,以下是相关代码、错误信息及解决方案:
相关代码
.cshtml 前端触发代码
$(".download").click(function () { var grid = $("#Grid").data("kendoGrid"); var options = { format: $(this).data("format"), title: 'Testreport' } var parsedInput = GetInputDataTransfer(); var ChkBoxvalues = parsedInput.InputChkBoxValues; $("#export-data").val(encodeURIComponent(JSON.stringify(options))); $("#export-model").val(encodeURIComponent(JSON.stringify(grid.columns))); $("#export-chkbox").val(ChkBoxvalues); $("#export-tabId").val(currentTabId); });
Controller 后端导出方法
public FileStreamResult ExportServer(string model, string data, string selectedInputChkBoxValues, string tabId) { try { string projnumber = (string)Session[$"projectSelection_{tabId}"]; GetProjectDetails(projnumber); UserInfo uInfo = ApplicationData.GetUserInfoFromSession(); ProjectDetails CurrentProject = uInfo.CurrentProject; string ProjectNo = Convert.ToString(CurrentProject); DataSet dataSet = PLDeliveryViewBL.Display(ProjectNo, selectedInputChkBoxValues); var dcolumns = JsonConvert.DeserializeObject<IList<ExportColumnSettings>>(HttpUtility.UrlDecode(model)); var columnsData = dcolumns.ToList(); List<dynamic> dlist = new List<dynamic>(); if (dataSet.Tables.Count > 0 && dcolumns != null) { for (var rowCount = 0; rowCount < dataSet.Tables[1].Rows.Count; rowCount++) { dynamic obj = new ExpandoObject(); var objDict = (IDictionary<string, object>)obj; foreach (var column in dcolumns) { string columnName = column.Field; objDict[columnName] = dataSet.Tables[1].Rows[rowCount][columnName]; } dlist.Add(obj); } } dynamic options = JsonConvert.DeserializeObject(HttpUtility.UrlDecode(data)); string title = options["title"].ToString(); string format = options["format"].ToString(); Stream exportStream = null; try { exportStream = dlist.ToXlsxStream(columnsData, title); } catch (Exception ex) { throw; } SpreadDocumentFormat exportFormat = SpreadDocumentFormat.Xlsx; string fileName = $"{title}.{format}"; string mimeType = Helpers.GetMimeType(exportFormat); var fileStreamResult = new FileStreamResult(exportStream, mimeType) { FileDownloadName = fileName }; fileStreamResult.FileStream.Seek(0, SeekOrigin.Begin); return fileStreamResult; } catch (Exception ex) { throw; } }
Kendo导出扩展类
using System; using System.Collections; using System.Collections.Generic; using System.IO; using Telerik.Documents.SpreadsheetStreaming; namespace Kendo.Mvc.Export { public static class ExportExtensions { public static Stream ToXlsxStream(this IEnumerable instance, IList<ExportColumnSettings> model, string title = "Sheet", Action<ExportColumnStyle> columnStyleAction = null, Action<ExportRowStyle> rowStyleAction = null, Action<ExportCellStyle> cellStyleAction = null) { return Helpers.CollectionToStream(SpreadDocumentFormat.Xlsx, instance, model, title, columnStyleAction, rowStyleAction, cellStyleAction); } public static Stream ToCsvStream(this IEnumerable instance, IList<ExportColumnSettings> model) { return Helpers.CollectionToStream(SpreadDocumentFormat.Csv, instance, model); } } }
错误信息
System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object. Source=Kendo.Mvc.Export StackTrace: at Kendo.Mvc.Export.Helpers.ExtractItemValue(Object dataItem, String propertyName) at Kendo.Mvc.Export.Helpers.CollectionToStream(SpreadDocumentFormat format, IEnumerable data, IList`1 model, String title, Action`1 columnStyleAction, Action`1 rowStyleAction, Action`1 cellStyleAction) at Kendo.Mvc.Export.ExportExtensions.ToXlsxStream(IEnumerable instance, IList`1 model, String title, Action`1 columnStyleAction, Action`1 rowStyleAction, Action`1 cellStyleAction) at DSWeb2._0.Controllers.DelPLController.ExportServer(String model, String data, String selectedInputChkBoxValues, String tabId) in C:\DSWEB\RegressionTesting_Solution_12thAug2024\RegressionTesting_Solution_6thAug2024\DSWeb2.0\Controllers\DelPLController.cs:line 205
解决方案
1. 修复导出Helper的属性提取逻辑
错误根源是ExtractItemValue方法无法正确处理ExpandoObject(动态字典结构),反射无法直接获取其属性值。修改该方法增加字典类型支持:
public static object ExtractItemValue(Object dataItem, String propertyName) { // 优先处理字典/ExpandoObject类型 if(dataItem is IDictionary<string, object> dict) { dict.TryGetValue(propertyName, out object value); return value ?? DBNull.Value; } // 原有反射逻辑 var prop = dataItem.GetType().GetProperty(propertyName); return prop == null ? DBNull.Value : prop.GetValue(dataItem) ?? DBNull.Value; }
2. 替换动态列表为结构化数据源
跳过ExpandoObject构建步骤,直接使用DataTable或强类型字典列表作为导出数据源:
// 直接使用DataTable导出(需确认导出Helper支持) DataTable exportTable = dataSet.Tables[1]; exportStream = exportTable.ToXlsxStream(columnsData, title); // 或转换为字典列表 List<Dictionary<string, object>> dataList = new List<Dictionary<string, object>>(); foreach(DataRow row in exportTable.Rows) { var rowDict = new Dictionary<string, object>(); foreach(DataColumn col in exportTable.Columns) { rowDict[col.ColumnName] = row[col] ?? DBNull.Value; } dataList.Add(rowDict); } exportStream = dataList.ToXlsxStream(columnsData, title);
3. 增加列名匹配校验
在构建动态对象时,校验列名是否存在于DataTable中,避免无效字段访问:
foreach (var column in dcolumns) { string columnName = column.Field; if (!string.IsNullOrEmpty(columnName) && dataSet.Tables[1].Columns.Contains(columnName)) { objDict[columnName] = dataSet.Tables[1].Rows[rowCount][columnName] ?? DBNull.Value; } }
内容的提问来源于stack exchange,提问作者akshaya parimaladevi
相关产品推荐
相关产品推荐

