dhtmlxGantt와 ASP.NET Core 사용하기
이 가이드는 서버 측에서 ASP.NET Core를 사용하여 Gantt 차트를 설정하는 과정을 안내합니다.
다른 서버사이드 플랫폼에 대한 튜토리얼도 제공됩니다:
- 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에서 확인할 수 있습니다.
1단계. 프로젝트 생성
Visual Studio 2022를 시작한 후 Create a new project를 선택하여 새 프로젝트를 만듭니다.

이후 "ASP.NET Core Web App"을 선택하고 프로젝트 이름을 DHX.Gantt로 지정합니다.



프로젝트가 생성되면 Gantt에 필요한 마크업과 스크립트를 추가할 수 있습니다.
2단계. Gantt 마크업 및 JS 추가
wwwroot로 이동하여 index.html이라는 새 파일을 생성합니다.


이 파일에서 간단한 페이지를 작성하여 gantt 차트를 표시합니다.
이 예제에서는 gantt 파일이 CDN에서 로드됩니다. Professional 버전을 사용하는 경우, 직접 gantt 파일을 프로젝트에 추가해야 합니다.
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 차트가 초기화되고 gantt.load()를 통해 바로 데이터 로딩이 시작됩니다. dataProcessor도 설정되어 있어, 차트에서 사용자가 변경한 내용이 서버에 저장됩니다. 아직 백엔드가 준비되지 않았기 때문에 전체 기능은 구현 후 확인할 수 있습니다.
다음으로 Program.cs 파일을 열고 index.html 페이지를 서비스하도록 앱을 구성합니다. 이를 위해 wwwroot 폴더에서 정적 파일 제공을 활성화하려면 app.UseDefaultFiles()를 추가해야 합니다.
자세한 내용은 여기를 참고하세요.
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()도 반드시 추가해야 합니다.
이 단계를 완료하면, 애플리케이션 실행 시 빈 gantt 차트가 표시됩니다. 오른쪽 상단의 "Invalid data" 메시지는 아직 백엔드가 구현되지 않아 gantt.load() 호출에 대한 데이터를 제공하지 못하기 때문입니다. 컨트롤러가 구현되면 gantt 차트에 작업과 링크가 정상적으로 표시됩니다.

기본 구성이 완료되었으므로, 다음 단계는 백엔드 구축입니다. 모델 클래스를 정의한 후 WebAPI 컨트롤러를 생성합니다.
3단계. 모델 및 데이터베이스 생성
먼저 데이터 모델을 정의합니다. 일반적인 Gantt 데이터 모델은 links와 tasks를 포함합니다. dhtmlxGantt는 .NET과 다른 속성명을 사용합니다. 또한 일부 속성은 클라이언트 측이나 백엔드 로직에만 사용되며, 데이터베이스에 저장하지 않아야 합니다.
이를 위해 Data Transfer Object (DTO) 패턴을 적용합니다. 두 가지 모델 타입을 생성합니다:
- EF Core 및 내부 앱에서 사용할 도메인 모델 클래스
- Web API와 통신할 DTO 클래스
이 모델들 간의 매핑도 구현합니다.
모델
프로젝트 디렉터리에 Models라는 새 폴더를 추가합니다. 이 폴더에 모델 클래스와 EF 컨텍스트를 포함시킵니다.
Task 모델
Tasks를 나타내는 클래스를 생성합니다. Models 폴더에서 Task.cs라는 새 파일을 추가합니다.
클래스는 다음과 같습니다:
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 모델
Links를 위한 파일을 추가합니다:
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 설치

또는 패키지 관리자 콘솔을 사용할 수 있습니다:
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
PM> Install-Package Microsoft.EntityFrameworkCore
PM> Install-Package Microsoft.EntityFrameworkCore.Design
이 패키지들은 데이터베이스 상호작용에 필요한 도구를 제공합니다.
Entity Context 생성
다음으로, 데이터 로딩 및 저장을 위한 데이터베이스 세션을 정의하는 컨텍스트 클래스를 생성합니다:
- 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;
}
}
데이터베이스에 첫 레코드 추가
이제 데이터베이스에 초기 레코드를 추가할 차례입니다. 이를 위해 tasks와 links를 삽입하는 데이터베이스 이니셜라이저를 생성합니다.
Models 폴더 내에 GanttSeeder라는 클래스를 정의하고, Seed() 메서드로 tasks와 links를 데이터베이스에 추가합니다.
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();
}
}
}
}