You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 19:14:54