Backend & integrations/.NET Core
.NET
This example runs from source. Open the repository to clone, build, and run it locally.
Open on GitHubBackend & integrations
.NET Core
ASP.NET Core backend that serves Gantt tasks and links over a REST API backed by Entity Framework Core.
- readme.md
- TaskController.cs
- LinkController.cs
- GanttContext.cs
- index.html
readme.md View on GitHub
# dhtmlxGantt with ASP.NET Core
ASP.NET Core backend for dhtmlxGantt.
### Requirements
- MS VisualStudio 2022
- .NET 8.0 SDK or later
### How to run
#### Using Visual Studio 2022:
Requires MS Visual Studio 2022. The version of the MS Visual Studio should support .NET 8.0.
1. Clone the demo repository
2. Run the application pressing `ctrl + f5`, or clicking on the Run button on the top in the panel interface
#### Using Visual Studio Code:
Alternatively, install the dotnet runtime manually: https://learn.microsoft.com/en-us/dotnet/core/install/
To check if .NET is installed, open terminal and run:
```bash
dotnet --version
```
**Steps to run:**
1. Open the project folder in VS Code
2. Open the terminal (Ctrl+` or View → Terminal)
3. Navigate to the project folder and run:
```bash
cd DHX.Gantt
dotnet restore
dotnet run # or use 'dotnet watch' for hot reload
```
Using `dotnet watch` enables automatic code reloading when you modify C# files.
4. Open the browser at https://localhost:7296 (or http://localhost:5296)
### Related resources
[Complete tutorial](https://docs.dhtmlx.com/gantt/integrations/dotnet/howtostart-dotnet-core/)
[DHTMLX Gantt product page](https://dhtmlx.com/docs/products/dhtmlxGantt/)
[Documentation](https://docs.dhtmlx.com/gantt/)
[Blog](https://dhtmlx.com/blog/)
[Forum](https://forum.dhtmlx.com/)
DHX.Gantt/Controllers/TaskController.cs View on GitHub
using Microsoft.AspNetCore.Mvc;
using DHX.Gantt.Models;
using Microsoft.EntityFrameworkCore;
namespace DHX.Gantt.Controllers
{
[Produces("application/json")]
[Route("api/task")]
public class TaskController : ControllerBase
{
private readonly GanttContext _context;
public TaskController(GanttContext context)
{
_context = context;
}
// GET api/task
[HttpGet]
public async Task<IEnumerable<WebApiTask>> Get()
{
return await _context.Tasks
.Select(t => (WebApiTask)t)
.ToListAsync();
}
// GET api/task/5
[HttpGet("{id}")]
public async Task<ActionResult<Models.Task>> Get(int id)
{
var task = await _context.Tasks.FindAsync(id);
if (task == null)
return NotFound();
return Ok(task);
}
// POST api/task
[HttpPost]
public async Task<IActionResult> Post(WebApiTask apiTask)
{
var newTask = (Models.Task)apiTask;
newTask.SortOrder = await _context.Tasks.MaxAsync(t => t.SortOrder) + 1;
await _context.Tasks.AddAsync(newTask);
await _context.SaveChangesAsync();
return Ok(new
{
tid = newTask.Id,
action = "inserted"
});
}
// PUT api/task/5
[HttpPut("{id}")]
public async Task<IActionResult?> Put(int id, WebApiTask apiTask)
{
var updatedTask = (Models.Task)apiTask;
var dbTask = await _context.Tasks.FindAsync(id);
if (dbTask == null)
{
return NotFound();
}
dbTask.Text = updatedTask.Text;
dbTask.StartDate = updatedTask.StartDate;
dbTask.Duration = updatedTask.Duration;
dbTask.ParentId = updatedTask.ParentId;
dbTask.Progress = updatedTask.Progress;
dbTask.Type = updatedTask.Type;
if (!string.IsNullOrEmpty(apiTask.target))
{
// reordering occurred
await this.UpdateOrdersAsync(dbTask, apiTask.target);
}
await _context.SaveChangesAsync();
return Ok(new
{
action = "updated"
});
}
// DELETE api/task/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTask(int id)
{
var task = await _context.Tasks.FindAsync(id);
if (task != null)
{
_context.Tasks.Remove(task);
await _context.SaveChangesAsync();
}
return Ok(new
{
action = "deleted"
});
}
private async Task<IActionResult> UpdateOrdersAsync(Models.Task updatedTask, string orderTarget)
{
int adjacentTaskId;
var nextSibling = false;
var targetId = orderTarget;
// adjacent task id is sent either as '{id}' or as 'next:{id}' depending
// on whether it's the next or the previous sibling
if (targetId.StartsWith("next:"))
{
targetId = targetId.Replace("next:", "");
nextSibling = true;
}
if (!int.TryParse(targetId, out adjacentTaskId))
{
return NotFound();
}
var adjacentTask = await _context.Tasks.FindAsync(adjacentTaskId);
if (adjacentTask == null)
{
return NotFound();
}
var startOrder = adjacentTask.SortOrder;
if (nextSibling)
startOrder++;
updatedTask.SortOrder = startOrder;
var updateOrders = await _context.Tasks
.Where(t => t.Id != updatedTask.Id)
.Where(t => t.SortOrder >= startOrder)
.OrderBy(t => t.SortOrder)
.ToListAsync();
var taskList = updateOrders.ToList();
taskList.ForEach(t => t.SortOrder++);
return Ok(new
{
action = "updated"
});
}
}
}
DHX.Gantt/Controllers/LinkController.cs View on GitHub
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc;
using DHX.Gantt.Models;
namespace DHX.Gantt.Controllers
{
[Produces("application/json")]
[Route("api/link")]
public class LinkController : ControllerBase
{
private readonly GanttContext _context;
public LinkController(GanttContext context)
{
_context = context;
}
// GET api/Link
[HttpGet]
public async Task<IEnumerable<WebApiLink>> Get()
{
return await _context.Links
.Select(t => (WebApiLink)t)
.ToListAsync();
}
// GET api/Link/5
[HttpGet("{id}")]
public async Task<ActionResult<Link>> Get(int id)
{
var link = await _context.Links.FindAsync(id);
if (link == null)
return NotFound();
return Ok(link);
}
// POST api/Link
[HttpPost]
public async Task<IActionResult> Post(WebApiLink apiLink)
{
var newLink = (Link)apiLink;
_context.Links.Add(newLink);
await _context.SaveChangesAsync();
return Ok(new
{
tid = newLink.Id,
action = "inserted"
});
}
// PUT api/Link/5
[HttpPut("{id}")]
public async Task<IActionResult> Put(int id, WebApiLink apiLink)
{
var updatedLink = (Link)apiLink;
updatedLink.Id = id;
_context.Entry(updatedLink).State = EntityState.Modified;
await _context.SaveChangesAsync();
return Ok(new
{
action = "updated"
});
}
// DELETE api/Link/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteLink(int id)
{
var link = await _context.Links.FindAsync(id);
if (link != null)
{
_context.Links.Remove(link);
await _context.SaveChangesAsync();
}
return Ok(new
{
action = "deleted"
});
}
}
}
DHX.Gantt/Models/GanttContext.cs View on GitHub
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!;
}
}
DHX.Gantt/wwwroot/index.html View on GitHub
<!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" />
<link href="css/site.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
gantt.config.order_branch = true;
gantt.config.order_branch_free = true;
// 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');
// creating and configuring dataProcessor
const dp = gantt.createDataProcessor({
url: '/api/',
mode: 'REST',
});
});
</script>
</head>
<body>
<div id="gantt_here" style="width: 100vw; height: 100vh"></div>
</body>
</html>