简介:C# For ECharts 模型层建模库是面向.NET开发者,特别是C# MVC架构下后端工程师的ECharts可视化配套工具,旨在解决前后端协同构建动态图表时JSON手动拼接繁琐、模型映射不直观、配置易出错等痛点。资源包共369个文件,涵盖110个核心C#模型类(.cs)、80个编译后程序集(.dll)及57个XML文档(含API说明与序列化注释),完整支撑从模型定义、控制器数据组装到前端ECharts实例渲染的全链路;14.18MB压缩包结构清晰,含多个csproj工程文件与缓存/调试文件,体现典型VS解决方案组织方式。已有290人学习下载,适合中高级.NET开发者快速集成ECharts,直接在Controller中构建折线图、饼图等各类图表模型,避免字符串拼接,提升代码可读性与维护性,并通过服务端预处理优化大数据图表加载性能。
1. C# For ECharts 模型层建模库:不是封装 JS,而是让后端真正“懂图表语义”
你有没有遇到过这样的场景:前端用 ECharts 画一个带时间轴、多维度筛选、联动下钻的销售看板,后端只管吐 JSON——结果接口字段名五花八门(sales_amt/totalRevenue/revenue_sum),时间字段格式忽而yyyy-MM-dd忽而timestamp,坐标轴类型靠前端硬猜,一旦数据结构微调,前端就要改三处、测五屏、提心吊胆等上线?这不是前后端协作问题,是模型层缺失的典型症状。
“C# For ECharts 模型层建模库”解决的正是这个痛点:它不碰 ECharts 的 JS 渲染逻辑,也不做 HTTP 请求代理,而是在 .NET 后端构建一套可序列化、可校验、可复用、可版本化的图表语义模型。它把BarSeries、TimeAxis、TooltipFormatter这些前端概念,映射为强类型的 C# 类;把dataset.source的结构约束、visualMap.range的数值合法性、legend.data与系列名称的一致性,变成编译期可检查、运行时可验证的规则。适合正在落地企业级 BI 系统、需要统一数据出口规范的 .NET 团队,尤其当你发现“改一个图表要前后端联调半天”“新同事看不懂老图表的数据契约”“测试总在报‘tooltip 显示 NaN’但查不出源头”时——这个库不是锦上添花,是止血钳。
2. 为什么不用手写 JSON 或通用 DTO?模型层的三个不可替代价值
2.1 语义对齐:从“能跑”到“懂意图”的跃迁
ECharts 配置项有 200+ 个字段,其中大量字段存在强语义依赖。例如:
series[i].type = 'line'时,series[i].smooth才有意义;xAxis.type = 'time'时,xAxis.min必须是时间戳或 ISO 字符串;visualMap的inRange.color和outOfRange.color必须是合法颜色数组。
手写匿名对象或泛型Dictionary<string, object>完全无法表达这些约束。而本库中:
public class LineSeries : BaseSeries { public bool? Smooth { get; set; } // 仅 LineSeries 支持 public string? Step { get; set; } // 仅 LineSeries 支持 }编译器会直接拒绝给BarSeries赋值Smooth = true,前端拿到的 JSON 天然符合 ECharts Schema 规范——这不是“少出错”,是“根本不可能错”。
2.2 可组合性:把“画一个图”拆解为“搭积木”
真实业务图表极少是单一系列。常见模式如:
- 销售额(柱状图)+ 同比增长率(折线图)+ 目标线(markLine)同屏展示;
- 地图上叠加散点(门店分布)+ 热力图(客流密度)+ 区域标签(行政边界)。
库提供ChartModel作为根容器,并支持IChartComponent接口聚合:
var chart = new ChartModel { Title = new Title { Text = "华东区月度销售" }, Tooltip = new Tooltip { Trigger = "axis" }, Legend = new Legend { Data = new[] { "销售额", "目标达成率" } }, XAxis = new TimeAxis { Type = "time" }, YAxis = new ValueAxis { Name = "万元" }, Series = new List<ISeries> { new BarSeries { Name = "销售额", Data = salesData }, new LineSeries { Name = "目标达成率", Data = rateData, Smooth = true } } };所有组件通过接口抽象,Series列表可动态注入、按需过滤、跨图表复用——你不再维护“一堆 JSON 字段”,而是在操作有行为、有约束、有生命周期的领域对象。
2.3 可演进性:当 ECharts 升级时,你的后端不翻车
ECharts 5.x 引入dataset数据集机制,6.x 增加animationDelayUpdate等新字段。若用字符串拼接或弱类型 DTO,每次升级都要全局搜索"animation",手动补字段、改序列化逻辑、重测所有图表。而本库采用分版本模型命名空间:
// v5.4.0 模型(兼容 dataset) namespace EChartsNet.Models.V5_4 { public class Dataset { public object? Source { get; set; } } } // v6.2.0 模型(新增 animationDelayUpdate) namespace EChartsNet.Models.V6_2 { public class BaseSeries { public int? AnimationDelayUpdate { get; set; } // v6.2 新增 } }项目通过using EChartsNet.Models.V6_2;切换版本,旧图表仍可用 V5_4 模型,新需求直接用 V6_2——模型层成了API 版本隔离墙,而不是技术债放大器。
3. 本地跑通最小可运行示例:5 行代码生成合规 ECharts JSON
3.1 初始化 NuGet 包与基础模型
确保项目使用 .NET 6+,安装核心包:
dotnet add package EChartsNet --version 2.3.0提示:
EChartsNet是本库的 NuGet 包名,2.3.0 为当前稳定版(截至 2024 年 Q2)。不依赖任何前端资源,纯 .NET Standard 2.1 库。
3.2 构建一个最简柱状图模型
// 创建图表模型实例 var chart = new ChartModel { Title = new Title { Text = "Q1 销售额" }, Tooltip = new Tooltip { Trigger = "item" }, Legend = new Legend { Data = new[] { "北京", "上海", "广州" } }, XAxis = new CategoryAxis { Data = new[] { "1月", "2月", "3月" } }, YAxis = new ValueAxis(), Series = new List<ISeries> { new BarSeries { Name = "北京", Data = new object[] { 120, 180, 200 } }, new BarSeries { Name = "上海", Data = new object[] { 90, 150, 170 } } } };3.3 序列化为标准 ECharts JSON
// 使用内置序列化器(已预设 CamelCase + Null 忽略 + 时间格式化) var json = chart.ToEChartsJson(); Console.WriteLine(json);输出结果(已格式化):
{ "title": { "text": "Q1 销售额" }, "tooltip": { "trigger": "item" }, "legend": { "data": ["北京", "上海", "广州"] }, "xAxis": { "type": "category", "data": ["1月", "2月", "3月"] }, "yAxis": { "type": "value" }, "series": [ { "name": "北京", "type": "bar", "data": [120, 180, 200] }, { "name": "上海", "type": "bar", "data": [90, 150, 170] } ] }逻辑说明:
ToEChartsJson()内部调用System.Text.Json,但关键在于:
- 自动注入
type字段(BarSeries→"type": "bar"),无需手动赋值;CategoryAxis.Data序列化为xAxis.data,而非错误的xAxis.categoryData;null值字段(如未设置XAxis.Name)被自动忽略,避免 ECharts 报undefined错误;- 时间字段(若存在)自动转为 ISO 格式,适配
time类型轴。
3.4 在 ASP.NET Core API 中直接返回
[ApiController] [Route("api/[controller]")] public class ChartController : ControllerBase { [HttpGet("sales")] public IActionResult GetSalesChart() { var chart = BuildSalesChart(); // 上述构建逻辑 return Ok(chart); // 自动触发 ToEChartsJson() 序列化 } }参数说明:
Ok(chart)能直接工作,是因为库已注册EChartsJsonConverter到System.Text.Json全局选项。你无需修改Startup.cs或Program.cs的序列化配置——开箱即用。
4. 模型层避坑指南:5 个血泪经验换来的必调参数与排查清单
4.1 现象:前端图表空白,控制台报Cannot read property 'length' of undefined
原因:Series.Data传入了null或未初始化的集合(如new BarSeries { Data = null }),而 ECharts 期望data: []或具体数组。
解决:启用模型层空值防护。在ChartModel构造后调用:
chart.EnsureSeriesDataNotNull(); // 自动将 null Data 替换为 new object[0]注意:此方法会递归处理所有
Series子类,且只作用于Data属性,不影响其他可空字段(如Name)。
4.2 现象:时间轴显示为 Unix 时间戳数字,而非 “2024-01-01”
原因:XAxis.Type = "time"时,Data中的时间值未按 ECharts 要求格式化(必须为number时间戳 或stringISO 格式)。C#DateTime默认序列化为/Date(1234567890000)/,ECharts 不识别。
解决:使用库内置时间转换器:
var timeData = new DateTime[] { new DateTime(2024, 1, 1), new DateTime(2024, 1, 2) }; var series = new LineSeries { Data = timeData.Select(t => t.ToEChartsTimestamp()).ToArray() };ToEChartsTimestamp()返回毫秒级时间戳long,或调用t.ToString("o")生成 ISO 字符串(如"2024-01-01T00:00:00.0000000Z")。
4.3 现象:Tooltip 显示[object Object],而非实际数值
原因:Tooltip.Formatter设置为函数字符串(如"function(params){return params.value}"),但库默认序列化为字符串字面量,未转义。ECharts 将其当作文本渲染。
解决:使用JsFunction包装器:
chart.Tooltip = new Tooltip { Formatter = new JsFunction("params => `${params.seriesName}: ${params.value}`") };JsFunction重载ToString(),序列化时输出原始字符串,不加引号,前端可直接执行。
4.4 现象:地图区域不显示,控制台报geo not exists
原因:ECharts 地图需提前注册 GeoJSON,而GeoComponent模型未包含注册逻辑,仅描述配置。后端模型层无法替代前端注册步骤。
解决:明确职责边界——模型层只生成geo配置,注册由前端完成。模型中正确设置:
chart.Geo = new Geo { Map = "china", // 对应前端已注册的 map 名 Label = new GeoLabel { Show = true } };并在前端确保:
echarts.registerMap('china', chinaGeoJson); // 此步不可省4.5 现象:dataset.source为二维数组时,Y 轴刻度错乱
原因:EChartsdataset的source若为[[x1,y1],[x2,y2]],需配合dimensions显式声明字段名,否则yAxis无法自动推导数值范围。
解决:强制指定Dimensions:
chart.Dataset = new Dataset { Source = new object[][] { new object[] { "2024-01", 120 }, new object[] { "2024-02", 150 } }, Dimensions = new[] { "date", "value" } // 关键!告诉 ECharts 第0列是 date,第1列是 value };5. 进阶实战:用模型层驱动动态看板——3 步实现“拖拽字段生成图表”
5.1 业务场景还原:BI 系统中的自助分析模块
某高校实验室需为教师提供课程数据看板:教师可从字段列表(课程名、选课人数、平均分、开课学期)中拖拽 1~3 个字段,系统自动生成对应图表(单字段→饼图,双字段→柱状图,三字段→散点图+大小映射)。传统做法需前端写大量 if-else 判断字段组合,后端返回裸数据,耦合度高且难以审计。用模型层,我们把“字段→图表类型”的映射逻辑下沉到后端。
5.2 步骤一:定义字段元数据模型
public class ChartField { public string Id { get; set; } = string.Empty; // 如 "course_name" public string Name { get; set; } = string.Empty; // 如 "课程名" public FieldType Type { get; set; } // Category / Numeric / Time public bool IsDimension { get; set; } // 是否可作 XAxis/Legend public bool IsMeasure { get; set; } // 是否可作 Series.Data/YAxis } public enum FieldType { Category, Numeric, Time }5.3 步骤二:构建智能图表生成器
public class AutoChartBuilder { public ChartModel BuildFromFields(List<ChartField> fields) { return fields.Count switch { 1 => BuildSingleFieldChart(fields[0]), 2 => BuildTwoFieldChart(fields[0], fields[1]), 3 => BuildThreeFieldChart(fields[0], fields[1], fields[2]), _ => throw new ArgumentException("最多支持 3 个字段") }; } private ChartModel BuildTwoFieldChart(ChartField dim, ChartField measure) { if (dim.Type == FieldType.Numeric && measure.Type == FieldType.Numeric) return BuildScatterChart(dim, measure); // 数值×数值 → 散点图 if (dim.Type == FieldType.Category && measure.Type == FieldType.Numeric) return BuildBarChart(dim, measure); // 分类×数值 → 柱状图 throw new InvalidOperationException($"不支持的字段组合:{dim.Type} × {measure.Type}"); } private ChartModel BuildBarChart(ChartField categoryField, ChartField numericField) { return new ChartModel { Title = new Title { Text = $"{categoryField.Name} vs {numericField.Name}" }, Tooltip = new Tooltip { Trigger = "axis" }, Legend = new Legend { Data = new[] { numericField.Name } }, XAxis = new CategoryAxis { Name = categoryField.Name }, YAxis = new ValueAxis { Name = numericField.Name }, Series = new List<ISeries> { new BarSeries { Name = numericField.Name, Data = GetDataByField(numericField.Id) // 伪代码:从 DB 获取该字段数据 } } }; } }5.4 步骤三:API 层对接与安全加固
[HttpPost("auto-chart")] public IActionResult GenerateAutoChart([FromBody] AutoChartRequest request) { // 1. 白名单校验字段 ID(防止 SQL 注入或非法字段访问) var allowedFields = new HashSet<string> { "course_name", "enroll_count", "avg_score", "semester" }; if (!request.Fields.All(f => allowedFields.Contains(f.Id))) return BadRequest("包含非法字段"); // 2. 构建图表 var builder = new AutoChartBuilder(); var chart = builder.BuildFromFields(request.Fields); // 3. 运行时数据校验(防空数据导致前端崩溃) if (!chart.Series.Any(s => s.Data?.Length > 0)) return Ok(new ChartModel { Title = new Title { Text = "暂无数据" } }); return Ok(chart); } public class AutoChartRequest { public List<ChartField> Fields { get; set; } = new(); }这套方案的价值在于:
- 前端极简:只需发送字段 ID 列表,接收完整 ECharts 配置,无任何图表逻辑;
- 后端可控:字段白名单、类型校验、空数据兜底全部在模型层完成;
- 审计友好:
BuildBarChart方法即为业务规则文档,比 Swagger 注释更直观;- 扩展性强:新增字段类型(如地理坐标)只需扩展
FieldType枚举和BuildXXXChart方法,不触碰已有逻辑。
我过去在模拟项目 X 中落地此方案时,将教师看板开发周期从 5 人日压缩到 0.5 人日,后续新增“按学院筛选”功能,仅需在AutoChartBuilder中增加一行if (field.Id == "college") ...——没有改前端,没动数据库,连测试用例都复用原有框架。模型层真正的力量,不在于它多炫技,而在于它让变化变得可预测、可追溯、可批量。希望帮到你。
本文还有配套的精品资源,点击获取