(附完整代码)求助懂 C#的大神, Excel 中显示 DataSet 数据集遇到 System.NullReferenceException 的报错是 NewtonJson Jarray 造成的吗

2019-12-27 09:49:04 +08:00
 elsagong

如题,我想在 Excel 中显示如下 JSON 数据集( Python 写的 API 接口)

{
    "msg": "success",
    "state": 10000,
    "data": {
        "data": [
            {
                "index": 0,
                "test_1": 110,
                "test_2": "000001",
                "test_3": "CN",
                "test_4": "Bank",
                "test_5": 893,
                "test_6": 229
            }
        ],
        "schema": {
            "fields": [
                {
                    "type": "integer",
                    "name": "index"
                },
                {
                    "type": "string",
                    "name": "test_1"
                },
                {
                    "type": "string",
                    "name": "test_2"
                },
                {
                    "type": "number",
                    "name": "test_3"
                },
                {
                    "type": "number",
                    "name": "test_4"
                },
                {
                    "type": "number",
                    "name": "test_5"
                },
                {
                    "type": "string",
                    "name": "test_6"
                }
            ],
            "pandas_version": "0.20.0",
            "primaryKey": [
                "index"
            ]
        }
    }
}

下面是我 C#的数据集代码 TestDataset.cs:

using System;
using System.IO;
using System.Net;
using Newtonsoft.Json.Linq;
using ExcelDna.Integration;
using Excel = Microsoft.Office.Interop.Excel;
namespace Test_Atune
{
    public class Request
    {
        Excel.Application ExcelApp = (Excel.Application)ExcelDnaUtil.Application;
        public object GetDatasetFromUrl(string root, string path, string headval, Excel.Range excelAddress)
        {
            string historicalData= "{}";
            var webConnection = new WebClient();
            webConnection.Headers.Add("Host", headval);
            try
            {
                historicalData = webConnection.DownloadString(root+path);
            }
            catch (WebException ex)
            {
                string error_str = ex.Message;
                if (ex.Status.ToString() == "ConnectFailure" || ex.Status.ToString() == "Timeout")
                {
                    root = Constant.setURL_ROOT_COMMON(root);
                    try
                    {
                        historicalData= webConnection.DownloadString(root + path);
                    }
                    catch (WebException ex2)
                    {
                        return "";
                    }
                }
            }
            finally
            {
                webConnection.Dispose();
            }

            JObject jsonFeed = JObject.Parse(historicalData);
            Excel.Range range = excelAddress;
            JObject B = new JObject();
            JArray data = (JArray)jsonFeed["data"]["data"];
            JArray columns = (JArray)jsonFeed["data"]["schema"]["fields"];
            int rowNum = data.Count;
            int colNum = columns.Count;
            Excel.Range range_head = ExcelApp.Cells[range.Row + 1, range.Column];
            range_head = range_head.get_Resize(1, colNum);
            Excel.Range range_data = ExcelApp.Cells[range.Row + 2, range.Column];
            range_data = range_data.get_Resize(rowNum, colNum);
            // write header
            object[,] headerData = new object[1, colNum];
            for (int iCol = 0; iCol < colNum; iCol++)
            {
                headerData[0, iCol] = columns[iCol]["name"];
            }
            range_head.Value2 = headerData;

            // write data
            object[,] cellData = new object[rowNum, colNum];
            int iRow = 0;
            foreach (JObject jo in data)
            {
                var a = jo["test_code"];
                for (int iCol = 0; iCol < colNum; iCol++)
                {
                    if (columns[iCol]["test_1"].ToString() == "string")
                    {
                        cellData[iRow, iCol] = "'" + jo[columns[iCol]["name"].ToString()];
                    }
                    else
                    {
                        cellData[iRow, iCol] = jo[columns[iCol]["name"].ToString()];
                    }
                }
                iRow += 1;
            }
            range_data.Value2 = cellData;
            return "Total" + rowNum.ToString() + "cells";
        }
    }

}

请求 Python 接口的 C#代码 request.cs

using ExcelDna.Integration;
using Excel = Microsoft.Office.Interop.Excel;
namespace Test_Atune
{
    public class Dataset
    {
        public static string baseurl = Constant.URL_ROOT_COMMON;
        public static string headval = Constant.HEADVAL_COMMON;
        public static Request request = new Request();

        [ExcelFunction(Category = "test", IsMacroType = true, Description = "test dataset")]
        public static object TEST_DATASET(
                    [ExcelArgument(Description = "test_code")] string test_1,
                    [ExcelArgument(Description = "YYYYMMDD")] string test_2,
                    [ExcelArgument(Description = "YYYYMMDD")] string test_3
                    )
        {
            string parstr = @"/test_dataset/?" +
                @"test_1=" + test_1 +
                @"&test_2=" + test_2 +
                @"&test_3=" + test_3;
            ExcelReference caller = (ExcelReference)XlCall.Excel(XlCall.xlfCaller);
            Excel.Range rg = caller.ToPiaRange();
            return ExcelAsyncUtil.Run("TEST_DATASET",
                new object[] { parstr },
                () => request.GetDatasetFromUrl(Constant.URL_ROOT_COMMON, parstr, headval, rg));
        }
    }

}

但在这一行 JArray columns = (JArray)jsonFeed["data"]["schema"]["fields"];

我遇到了如下报错:

System.NullReferenceException HResult=0x80004003  message=Object reference not set to an instance of an object.

Debug 后得到如下结果,是否 NewtonJson Jarray 需要判断下是否为空值?数据集不太会判别,对 C#一窍不通,求大神指点一二,非常感谢 Name: historicalData, Value:"{}"; Name: jsonFeed,Vaule:Null; Name:B,Vaule:{{}}, Name:data, Value:"null"

2550 次点击
所在节点    程序员
17 条回复
noreplay
2019-12-27 10:08:41 +08:00
感觉好像是你没等数据下载完就开始解析了。当你解析的时候,data 还是一个“{}”,里面的所有字段都是空值,所以就报错了。
elsagong
2019-12-27 10:19:49 +08:00
@noreplay 我也觉得应该加个判别 null 的,这样在是 null 的时候就不会报错,但是不知道怎么加😂
minigo
2019-12-27 10:34:07 +08:00
JArray columns = (JArray)jsonFeed["data"]["schema"]["fields"];
======>
JArray columns = (JArray)jsonFeed["data"]?["schema"]?["fields"];
guolaopi
2019-12-27 10:40:16 +08:00
断点看一下 try catch 之后的 historicalData 值就知道了
noreplay
2019-12-27 10:42:37 +08:00
假如只是判断 null 的话,有一个笨方法:
代码大约是这个样子的:
var feedData=(JArray)jsonFeed["data"];
if(feedData!=null){
// balabala
}
不过这样子的代码很丑陋就是了。
crclz
2019-12-27 10:52:58 +08:00
不建议用 JArray JObject 实现。很容易出错。建议定义类来承载数据,再用 JsonConvert.Deserialize<T>(jsonString)解析。
forgottencoast
2019-12-27 11:14:38 +08:00
@noreplay #3 的才是正经写法,你大概不是 C#程序员。
noreplay
2019-12-27 11:15:33 +08:00
@forgottencoast 被看出来了,好尴尬。。。。。
forgottencoast
2019-12-27 11:20:41 +08:00
原因:
从你说的(JArray)jsonFeed["data"]["schema"]["fields"];这样出错,
但是上面一行没有出错,可以推断出是 schema 字段为 null,这个时候你再读取它的属性就会报空引用异常。

处理:
出现空引用异常的时候,你看一下服务端回传的 json 数据,一定是里面个别字段为空。
这次是 schema,下次可能是别的,所以你要和服务端确认哪些可能为空,你如果用到的话,可能都需要额外处理的。
elsagong
2019-12-27 11:25:05 +08:00
@minigo 非常感谢,加```?```似乎真的有用,现在那行没有报错了,不过轮到```int rowNum = data.Count;
int colNum = columns.Count;```了,实在不懂 C#,可以再咨询一下您吗😂万分感谢!!!!
kkkkkrua
2019-12-27 11:28:44 +08:00
JArray data = (JArray)jsonFeed["data"]["data"];
JArray columns = (JArray)jsonFeed["data"]["schema"]["fields"];
-------
JArray data = (JArray)jsonFeed["data"]?["data"] ?? new Jarray();
JArray columns = (JArray)jsonFeed["data"]?["schema"]?["fields"] ?? new JArray();
elsagong
2019-12-27 13:36:36 +08:00
@kkkkkrua 再次感谢,无奈它还是会报错😂这一行``` range_head = range_head.get_Resize(1, colNum);
``` 报出的 System.Runtime.InteropServices.COMException HResult=0x800A03EC Message=异常来自 HRESULT:0x800A03EC,
yefuchao
2019-12-27 13:57:50 +08:00
elsagong
2019-12-27 15:32:11 +08:00
@yefuchao 感谢,我搜到了这个问题,但依然觉得是上面空值的代码问题,并非 Excel 版本的问题
elsagong
2019-12-27 15:46:55 +08:00
@guolaopi 断点看过了,感觉就是空值处理的问题(但是我不知道怎么处理😂),点击 Excel 函数弹窗时才会出现这个问题,如果在 Excel 里直接调用公式就没问题
elsagong
2019-12-27 16:12:43 +08:00
@noreplay 依然感谢你的解答,共同学习,共同进步☕️☕️
elsagong
2019-12-27 16:14:10 +08:00
@crclz 感谢你给到的思路,我去搜索以及摸索一下😂要被这个报错折磨疯了。。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/632774

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX