dhtmlxGantt 与 ASP.NET Core 集成指南
本指南将带您逐步完成在服务端使用 ASP.NET Core 搭建甘特图的过程。
同时,我们还为其他服务端平台提供了教程:
- dhtmlxGantt와 ASP.NET MVC
- dhtmlxGantt와 Node.js 연동하기
- dhtmlxGantt와 Python
- dhtmlxGantt와 PHP: Laravel 연동
- dhtmlxGantt와 PHP:Slim 연동하기
- dhtmlxGantt와 Salesforce LWC 연동하기
- dhtmlxGantt와 Ruby on Rails 연동하기
数据库交互部分采用了 Entity Framework Core。项目开发工具为 Visual Studio 2022。
完整源代码可在 GitHub 查看。
第一步:创建项目
启动 Visual Studio 2022,选择 Create a new project 新建项目。

选择 "ASP.NET Core Web App",项目名称设置为 DHX.Gantt。



项目创建完成后,即可添加甘特图所需的标记和脚本。
第二步:添加甘特图标记和 JS
进入 wwwroot 目录,新建名为 index.html 的文件。


在该文件中,构建一个简单页面用于展示甘特图。
请注意,本例中甘特图文件是从 CDN 加载的。如果您拥有 Professional 版本,需要 手动将甘特图文件添加到项目中。
index.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width="device-width"" />
<title>Index</title>
<link href="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.css"
rel="stylesheet" type="text/css" />
<script src="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
// specifying the date format
gantt.config.date_format = "%Y-%m-%d %H:%i";
// initializing gantt
gantt.init("gantt_here");
// initiating data loading
gantt.load("/api/data");
// initializing dataProcessor
var dp = new gantt.dataProcessor("/api/");
// and attaching it to gantt
dp.init(gantt);
// setting the REST mode for dataProcessor
dp.setTransactionMode("REST");
});
</script>
</head>
<body>
<div id="gantt_here" style={{width: '100%', height: '100vh'}}></div>
</body>
</html>
页面加载后,甘特图会被初始化,并通过 gantt.load() 立即开始加载数据。同时 dataProcessor 也被配置好,用户在图表上的修改会自动保存到服务器。由于后端尚未搭建,完整功能将在后续实现后体现。
接下来,打开 Program.cs,配置应用以便能够访问 index.html 页面。需要通过添加 app.UseDefaultFiles() 启用从 wwwroot 文件夹提供静态文件。
更多信息请参考 这里。
Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days.
// You may want to change this for production scenarios,
// see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles(); /*!*/
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
app.UseDefaultFiles() 方法会查找 wwwroot 目录下的默认文件:
- index.html
- index.htm
- default.html
- default.htm
您可以使用上述任意文件名,本教程采用 "index.html"。
请注意,UseDefaultFiles() 仅重写 URL,并不会实际提供文件。要真正提供静态文件,还需添加 UseStaticFiles()。
完成上述步骤后,运行应用将显示一个空的甘特图。右上角会出现 "Invalid data" 提示,因为 gantt.load() 被调用但后端尚未提供数据。待控制器实现后,甘特图会正确显示任务和链接。

基础环境搭建完毕,接下来构建后端。首先定义模型类,然后创建 WebAPI 控制器。
第三步:创建模型与数据库
首先定义数据模型。典型的甘特图数据模型包括 links 和 tasks。 dhtmlxGantt 使用的属性名与 .NET 习惯不同,且部分属性仅用于客户端或后端逻辑,不应存入数据库。
为处理此问题,将采用 数据传输对象(DTO) 模式。将创建两类模型:
- 供 EF Core 和内部应用使用的领域模型类
- 用于与 Web API 通信的 DTO 类
还需要实现这两类模型之间的映射。
模型
在项目目录下新建 Models 文件夹。此文件夹用于存放模型类与 EF 上下文。
Task 模型
创建任务类。在 Models 文件夹下新建 Task.cs 文件(右键文件夹选择 Add->Class)。
类定义如下:
DHX.Gantt/Models/Task.cs
namespace DHX.Gantt.Models
{
public class Task
{
public int Id { get; set; }
public string? Text { get; set; }
public DateTime StartDate { get; set; }
public int Duration { get; set; }
public decimal Progress { get; set; }
public int? ParentId { get; set; }
public string? Type { get; set; }
}
}
完整的 Task 对象属性列表参见 这里。
Link 模型
为 Link 新建文件:
DHX.Gantt/Models/Link.cs
namespace DHX.Gantt.Models
{
public class Link
{
public int Id { get; set; }
public string? Type { get; set; }
public int SourceTaskId { get; set; }
public int TargetTaskId { get; set; }
}
}
模型准备就绪后,下一步配置数据库连接。
配置数据库连接
按照以下步骤配置数据库连接:
安装 Entity Framework Core
Entity Framework Core 用于数据库通信。安装方法如下:
- 在项目树中,找到 DHTMLX.Gantt 下的 Dependencies
- 右键选择 Manage NuGet packages
- 切换到 Browse 标签,安装 Microsoft.EntityFrameworkCore.SqlServer、Microsoft.EntityFrameworkCore 和 Microsoft.EntityFrameworkCore.Design

也可使用 Package Manager Console:
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
PM> Install-Package Microsoft.EntityFrameworkCore
PM> Install-Package Microsoft.EntityFrameworkCore.Design
这些包将为数据库交互提供所需工具。
创建实体上下文
接下来,定义与数据库的会话以实现数据加载和保存。新建上下文类:
- 在 Models 文件夹下新建 GanttContext.cs 文件
- 在其中定义 GanttContext 类
DHX.Gantt/Models/GanttContext.cs
using Microsoft.EntityFrameworkCore;
namespace DHX.Gantt.Models
{
public class GanttContext : DbContext
{
public GanttContext(DbContextOptions<GanttContext> options)
: base(options)
{
}
public DbSet<Task> Tasks { get; set; } = null;
public DbSet<Link> Links { get; set; } = null;
}
}
向数据库添加初始记录
现在可以为数据库添加一些初始记录。为此需创建数据库初始化器,实现插入任务和链接的功能。 在 Models 文件夹下定义 GanttSeeder 类。该类包含一个 Seed() 方法,用于向数据库添加任务和链接。
DHX.Gantt/Models/GanttSeeder.cs
using Microsoft.EntityFrameworkCore;
namespace DHX.Gantt.Models
{
public static class GanttSeeder
{
public static void Seed(GanttContext context)
{
if (context.Tasks.Any())
{
return; // DB has been seeded
}
using (var transaction = context.Database.BeginTransaction())
{
List<Task> tasks = new List<Task>()
{
new Task()
{
Id = 1,
Text = "Project #2",
StartDate = DateTime.Today.AddDays(-3),
Duration = 18,
Progress = 0.4m,
ParentId = null
},
new Task()
{
Id = 2,
Text = "Task #1",
StartDate = DateTime.Today.AddDays(-2),
Duration = 8,
Progress = 0.6m,
ParentId = 1
},
new Task()
{
Id = 3,
Text = "Task #2",
StartDate = DateTime.Today.AddDays(-1),
Duration = 8,
Progress = 0.6m,
ParentId = 1
}
};
tasks.ForEach(s => context.Tasks.Add(s));
context.Database.ExecuteSqlRaw("SET IDENTITY_INSERT Tasks ON;");
context.SaveChanges();
context.Database.ExecuteSqlRaw("SET IDENTITY_INSERT Tasks OFF;");
List<Link> links = new List<Link>()
{
new Link() {Id = 1, SourceTaskId = 1, TargetTaskId = 2, Type = "1"},
new Link() {Id = 2, SourceTaskId = 2, TargetTaskId = 3, Type = "0"}
};
links.ForEach(s => context.Links.Add(s));
context.Database.ExecuteSqlRaw("SET IDENTITY_INSERT Links ON;");
context.SaveChanges();
context.Database.ExecuteSqlRaw("SET IDENTITY_INSERT Links OFF;");
transaction.Commit();
}
}
}
}
注册数据库
接下来,需要在 Program.cs 文件中注册数据库。在此之前,需要准备一个连接字符串。 该连接字符串将会被存储在应用程序设置的 JSON 文件中。 创建 appsettings.json 文件(如果已经存在则直接打开),并添加数据库的连接字符串:
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server="(localdb)mssqllocaldb;"
Database=GanttDatabase;Trusted_Connection=True;"
}
}
数据库上下文将通过 依赖注入" 的方式进行注册。
在 Program.cs 文件中添加以下命名空间:
Program.cs
using Microsoft.EntityFrameworkCore;
using DHX.Gantt.Models;
注册的代码如下所示:
Program.cs
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<GanttContext>(
options => options.UseSqlServer(connectionString));
为了启用控制器,需要添加 services.AddControllers() 方法:
Program.cs
builder.Services.AddControllers();
并通过调用 app.MapControllers() 注册控制器路由:
Program.cs
app.MapControllers();
以下是 Program.cs 文件的完整内容:
Program.cs
using Microsoft.EntityFrameworkCore;
using DHX.Gantt.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<GanttContext>(
options => options.UseSqlServer(connectionString));
builder.Services.AddControllers();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days.
// You may want to change this for production scenarios,
// see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.Run();
最后,当应用启动时应该初始化并填充数据库。虽然通常会使用迁移(migrations)来实现,但本例为简化起见未使用迁移。
首先,在 Models 文件夹下创建一个类用于初始化。添加 GanttInitializerExtension.cs 文件:
Models/GanttInitializerExtension.cs
namespace DHX.Gantt.Models
{
public static class GanttInitializerExtension
{
public static IHost InitializeDatabase(this IHost webHost)
{
var serviceScopeFactory =
(IServiceScopeFactory?)webHost.Services.GetService(typeof(IServiceScopeFactory));
using (var scope = serviceScopeFactory!.CreateScope())
{
var services = scope.ServiceProvider;
var dbContext = services.GetRequiredService<GanttContext>();
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
GanttSeeder.Seed(dbContext);
}
return webHost;
}
}
}
然后像下面这样调用 InitializeDatabase() 方法:
Program.cs
app.InitializeDatabase();
如前所述,本教程未使用迁移,而是通过 EnsureCreated 和数据填充(seeding)来实现。
到此为止,本部分内容已经完成。接下来,将继续处理甘特图相关工作。
定义 DTO 和映射
现在需要为 Web API 创建将要使用的 DTO 类。 首先为任务(Task)创建 DTO 类。在 Models 文件夹下新建文件并定义 WebApiTask.cs 类:
Models/WebApiTask.cs
namespace DHX.Gantt.Models
{
public class WebApiTask
{
public int id { get; set; }
public string? text { get; set; }
public string? start_date { get; set; }
public int duration { get; set; }
public decimal progress { get; set; }
public int? parent { get; set; }
public string? type { get; set; }
public bool open
{
get { return true; }
set { }
}
public static explicit operator WebApiTask(Task task)
{
return new WebApiTask
{
id = task.Id,
text = task.Text,
start_date = task.StartDate.ToString("yyyy-MM-dd HH:mm"),
duration = task.Duration,
parent = task.ParentId,
type = task.Type,
progress = task.Progress
};
}
public static explicit operator Task(WebApiTask task)
{
return new Task
{
Id = task.id,
Text = task.text,
StartDate = task.start_date != null ? DateTime.Parse(task.start_date,
System.Globalization.CultureInfo.InvariantCulture) : new DateTime(),
Duration = task.duration,
ParentId = task.parent,
Type = task.type,
Progress = task.progress
};
}
}
}
接下来是 Link 的 DTO 类,在 Models 文件夹下的 WebApiLink.cs 文件中定义:
Models/WebApiLink.cs
namespace DHX.Gantt.Models
{
public class WebApiLink
{
public int id { get; set; }
public string? type { get; set; }
public int source { get; set; }
public int target { get; set; }
public static explicit operator WebApiLink(Link link)
{
return new WebApiLink
{
id = link.Id,
type = link.Type,
source = link.SourceTaskId,
target = link.TargetTaskId
};
}
public static explicit operator Link(WebApiLink link)
{
return new Link
{
Id = link.id,
Type = link.type,
SourceTaskId = link.source,
TargetTaskId = link.target
};
}
}
}
完成上述步骤后,文件夹结构应如下所示:

此时建议运行应用程序以验证一切是否设置正确。如果没有出现运行时错误,说明设置成功。
Step 4. 实现 Web API
现在是实现 REST API 的时候了。