dhtmlxGantt mit ASP.NET MVC

Diese Anleitung erklärt, wie man eine Gantt-Diagramm-Anwendung mit ASP.NET und REST API auf der Serverseite erstellt. Die Schritte beinhalten das Einrichten der ASP.NET MVC 5-Webplattform und die Verwendung des Web API 2-Controllers für die REST API. Entity Framework wird die Datenbankkommunikation übernehmen, und Visual Studio wird zum Erstellen der Anwendung verwendet.

Wenn Sie an anderen serverseitigen Integrationen interessiert sind, sehen Sie sich diese Tutorials an:

Der vollständige Quellcode für dieses Tutorial ist auf GitHub verfügbar.

Schritt 1: Erstellen eines Projekts

Einrichten eines neuen Visual Studio-Projekts

Starten Sie Visual Studio 2022 und wählen Sie die Option, ein neues Projekt zu erstellen.

Wählen Sie "ASP.NET Web Application" als Vorlage und benennen Sie das Projekt DHX.Gantt.Web. Wenn diese Vorlage nicht sichtbar ist, lesen Sie den Abschnitt Fehlerbehebung.

Wählen Sie die Leere Vorlage und aktivieren Sie die Optionen MVC und Web API.


Schritt 2: Hinzufügen von Gantt zur Seite

Erstellen eines Controllers

Nachdem das leere Projekt bereit ist, besteht der nächste Schritt darin, das Gantt-Diagramm zu implementieren. Beginnen Sie damit, einen MVC-Controller hinzuzufügen, um die Gantt-Diagrammseite anzuzeigen.

Um den Controller hinzuzufügen, klicken Sie mit der rechten Maustaste auf den Ordner Controllers und wählen Sie Hinzufügen -> Controller. Wählen Sie "MVC 5 Controller - Leere" und benennen Sie ihn "HomeController".

Der HomeController enthält bereits die Methode Index() der ActionResult-Klasse, sodass keine zusätzliche Logik erforderlich ist. Der nächste Schritt besteht darin, eine Ansicht für diese Methode hinzuzufügen.

Controllers/HomeController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace DHX.Gantt.Web.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {
            return View();
        }
    }
}

Erstellen einer Ansicht

Erstellen Sie nun die Index-Seite. Navigieren Sie zu Views/Home und fügen Sie eine leere Ansicht namens Index hinzu.

Öffnen Sie die neu erstellte Ansicht und fügen Sie den folgenden Code hinzu:

Views/Home/Index.cshtml

@{
    Layout = null;
}
 
<!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) {
            // Datumsformat festlegen
            gantt.config.date_format = "%Y-%m-%d %H:%i";
            // Gantt initialisieren
            gantt.init("gantt_here");
 
            // Datenladen initiieren
            gantt.load("/api/data");
            // dataProcessor initialisieren
            var dp = new gantt.dataProcessor("/api/");
            // und an gantt anhängen
            dp.init(gantt);
            // Den REST-Modus für dataProcessor einstellen
            dp.setTransactionMode("REST");
        });
</script> </head> <body> <div id="gantt_here" style="width: 100%; height: 100vh;"></div> </body> </html>

Dieser Code macht Folgendes:

  • Richtet eine grundlegende Seitenstruktur für die Gantt-Anwendung ein.
  • Beinhaltet die dhtmlxGantt JavaScript- und CSS-Dateien über CDN-Links.
  • Initialisiert das Gantt-Diagramm auf der Seite.

Die Datumsformatkonfiguration stellt sicher, dass der Client die Daten vom Server korrekt parsen kann:

Views/Home/Index.cshtml

gantt.config.date_format = "%Y-%m-%d %H:%i";

Das Gantt-Diagramm ist auch so konfiguriert, dass es mit einer RESTful API unter Verwendung von "/api/" als Standardroute funktioniert:

Views/Home/Index.cshtml

gantt.load("/api/data");
// dataProcessor initialisieren
var dp = new gantt.dataProcessor("/api/");
// und an gantt anhängen
dp.init(gantt);
// Den REST-Modus für dataProcessor einstellen
dp.setTransactionMode("REST");

An diesem Punkt können Sie die Anwendung ausführen, um das Gantt-Diagramm auf der Seite anzuzeigen.


Schritt 3: Erstellen von Modellen und Datenbank

Erstellen von Modellen

Das Gantt-Diagramm benötigt ein Datenmodell, das aus Tasks und Links besteht. Das clientseitige Modell folgt einer spezifischen Namenskonvention, die von den Standard-C#-Konventionen abweicht. Einige Eigenschaften im clientseitigen Modell müssen möglicherweise nicht in der Datenbank gespeichert werden, sind jedoch für die Client- oder Backend-Logik nützlich.

Um dies zu handhaben, wird das Data Transfer Object-Muster verwendet. Separate Domänenmodellklassen werden für die Verwendung mit EF und innerhalb der App erstellt, zusammen mit DTO-Klassen für die Kommunikation der Web-API. Die Zuordnung zwischen diesen Modellen wird ebenfalls implementiert.

Task-Modell

Beginnen Sie mit dem Erstellen einer Klasse für Task mit der folgenden Struktur:

Models/Task.cs

using System;
 
namespace DHX.Gantt.Web.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; }
    }
}

Für eine vollständige Liste der verfügbaren Eigenschaften für das Task-Objekt siehe die Dokumentation.

Link-Modell

Erstellen Sie als nächstes die Link-Klasse mit der folgenden Struktur:

Models/Link.cs

namespace DHX.Gantt.Web.Models
{
    public class Link
    {
        public int Id { get; set; }
        public string Type { get; set; }
        public int SourceTaskId { get; set; }
        public int TargetTaskId { get; set; }
    }
}

Konfigurieren der Datenbankverbindung

Installieren von Entity Framework

Um die Datenbank zu verwalten, installieren Sie das Entity Framework, indem Sie diesen Befehl in der Package Manager Console ausführen:

Install-Package EntityFramework

Erstellen des Datenbankkontexts

Erstellen Sie eine GanttContext-Klasse, um eine Sitzung mit der Datenbank darzustellen. Dieser Kontext ermöglicht das Abrufen und Speichern von Daten.

Fügen Sie dem Ordner Models eine neue Klasse namens "GanttContext" mit folgendem Inhalt hinzu:

Models/GanttContext.cs

using System.Data.Entity;
 
namespace DHX.Gantt.Web.Models
{
    public class GanttContext : DbContext
    {
        public DbSet<Task> Tasks { get; set; }
        public DbSet<Link> Links { get; set; }
    }
}

Hinzufügen von Anfangsdaten zur Datenbank

Um die Datenbank mit Anfangsdaten zu füllen, konfigurieren Sie das Entity Framework so, dass es die Datenbank automatisch erstellt und füllt, wenn die Anwendung läuft.

Erstellen Sie einen Datenbankinitialisierer, indem Sie eine neue Klasse im Ordner App_Start hinzufügen. Nennen Sie sie "GanttInitializer" und erben Sie sie von der DropCreateDatabaseIfModelChanges-Klasse. Überschreiben Sie die Seed()-Methode, um die Datenbank mit Testdaten zu füllen.

Hier ist der vollständige Code für die GanttInitializer-Klasse:

App_Start/GanttInitializer.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
 
namespace DHX.Gantt.Web.Models
{
    public class GanttInitializer : DropCreateDatabaseIfModelChanges<GanttContext>
    {
        protected override void Seed(GanttContext context)
        {
            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.SaveChanges();
 
            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.SaveChanges();
        }
    }
}

Öffnen Sie schließlich die Datei Global.asax und fügen Sie den erforderlichen Namespace und die Initialisierer-Einrichtung in der Application_Start()-Methode hinzu:

Global.asax.cs

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Http;
 
using System.Data.Entity;
using DHX.Gantt.Web.Models;
 
namespace DHX.Gantt.Web
{
    public class Global : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            // Code, der beim Start der Anwendung ausgeführt wird
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
 
            Database.SetInitializer(new GanttInitializer());
        }
    }
}

Definieren von DTOs und Mapping

Um loszulegen, müssen Sie DTO-Klassen für die Web-API einrichten. Für das Mapping zwischen dem Modell und dem DTO halten wir es einfach, indem wir einen expliziten Konvertierungsoperator für diese Klassen definieren.

Hier ist, wie die TaskDto-Klasse definiert ist:

Models/TaskDto.cs

using System;
 
namespace DHX.Gantt.Web.Models
{
    public class TaskDto
    {
        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 TaskDto(Task task)
        {
            return new TaskDto
            {
                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(TaskDto task)
        {
            return new Task
            {
                Id = task.id,
                Text = task.text,
                StartDate = DateTime.Parse(
                    task.start_date, 
                    System.Globalization.CultureInfo.InvariantCulture),
                Duration = task.duration,
                ParentId = task.parent,
                Type = task.type,
                Progress = task.progress
            };
        }
    }
}

Als Nächstes folgt die Struktur der LinkDto-Klasse:

Models/LinkDto.cs

namespace DHX.Gantt.Web.Models
{
    public class LinkDto
    {
        public int id { get; set; }
        public string type { get; set; }
        public int source { get; set; }
        public int target { get; set; }
 
        public static explicit operator LinkDto(Link link)
        {
            return new LinkDto
            {
                id = link.Id,
                type = link.Type,
                source = link.SourceTaskId,
                target = link.TargetTaskId
            };
        }
 
        public static explicit operator Link(LinkDto link)
        {
            return new Link
            {
                Id = link.id,
                Type = link.type,
                SourceTaskId = link.source,
                TargetTaskId = link.target
            };
        }
    }
}

Zuletzt folgt das Modell für die Datenquelle:

Models/GanttDto.cs

using System.Collections.Generic;
 
namespace DHX.Gantt.Web.Models
{
    public class GanttDto
    {
        public IEnumerable<TaskDto> data { get; set; }
        public IEnumerable<LinkDto> links { get; set; }
    }
}

Schritt 4: Implementierung der Web-API

Allgemeiner Ansatz zum Laden von Daten über die REST-API

Der nächste Schritt beinhaltet die Implementierung der API. Basierend auf den API-Details benötigen Sie drei Controller: einen für Aufgaben, einen für Links und einen weiteren für die 'Daten laden'-Aktion, um das gemischte Ergebnis zu verarbeiten.

Task-Controller

Um einen neuen Controller zu erstellen:

  • Klicken Sie mit der rechten Maustaste auf den Ordner Controllers und wählen Sie Hinzufügen -> Controller.
  • Wählen Sie die Vorlage Web API 2 Controller -> Leere Vorlage. Benennen Sie den neuen Controller "TaskController".

Hier ist die Implementierung für grundlegende CRUD-Aktionen für Aufgabeneinträge:

Controllers/TaskController.cs

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web.Http;
using System.Web.UI.WebControls;
 
using DHX.Gantt.Web.Models;
 
namespace DHX.Gantt.Web.Controllers
{
    public class TaskController : ApiController
    {
        private GanttContext db = new GanttContext();
 
        // GET api/Task
        public IEnumerable<TaskDto> Get()
        {
            return db.Tasks
                .ToList()
                .Select(t => (TaskDto)t);
        }
 
        // GET api/Task/5
        [System.Web.Http.HttpGet]
        public TaskDto Get(int id)
        {
            return (TaskDto)db
                .Tasks
                .Find(id);
        }
 
        // PUT api/Task/5
        [System.Web.Http.HttpPut]
        public IHttpActionResult EditTask(int id, TaskDto taskDto)
        {
            var updatedTask = (Task)taskDto;
            updatedTask.Id = id;
            db.Entry(updatedTask).State = EntityState.Modified;
            db.SaveChanges();
 
            return Ok(new
            {
                action = "updated"
            });
        }
 
        // POST api/Task
        [System.Web.Http.HttpPost]
        public IHttpActionResult CreateTask(TaskDto taskDto)
        {
            var newTask = (Task)taskDto;
 
            db.Tasks.Add(newTask);
            db.SaveChanges();
 
            return Ok(new
            {
                tid = newTask.Id,
                action = "inserted"
            });
        }
 
        // DELETE api/Task/5
        [System.Web.Http.HttpDelete]
        public IHttpActionResult DeleteTask(int id)
        {
            var task = db.Tasks.Find(id);
            if (task != null)
            {
                db.Tasks.Remove(task);
                db.SaveChanges();
            }
 
            return Ok(new
            {
                action = "deleted"
            });
        }
 
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

Die Logik hier ist ziemlich einfach:

  • Für GET-Aktionen werden Aufgaben aus der Datenbank abgerufen und in ihre DTOs umgewandelt.
  • Für PUT/POST-Aktionen werden DTOs zurück in Aufgabenmodelle umgewandelt und in der Datenbank gespeichert.

Als Nächstes richten Sie den Controller für Links ein.

Link-Controller

Erstellen Sie einen neuen leeren Web API-Controller für Links. So sollte er aussehen:

Controllers/LinkController.cs

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web.Http;
using DHX.Gantt.Web.Models;
 
namespace DHX.Gantt.Web.Controllers
{
    public class LinkController : ApiController
    {
        private GanttContext db = new GanttContext();
 
        // GET api/Link
        [System.Web.Http.HttpGet]
        public IEnumerable<LinkDto> Get()
        {
            return db
                .Links
                .ToList()
                .Select(l => (LinkDto)l);
        }
 
        // GET api/Link/5
        [System.Web.Http.HttpGet]
        public LinkDto Get(int id)
        {
            return (LinkDto)db
                .Links
                .Find(id);
        }
 
        // POST api/Link
        [System.Web.Http.HttpPost]
        public IHttpActionResult CreateLink(LinkDto linkDto)
        {
            var newLink = (Link)linkDto;
            db.Links.Add(newLink);
            db.SaveChanges();
 
            return Ok(new
            {
                tid = newLink.Id,
                action = "inserted"
            });
        }
 
        // PUT api/Link/5
        [System.Web.Http.HttpPut]
        public IHttpActionResult EditLink(int id, LinkDto linkDto)
        {
            var clientLink = (Link)linkDto;
            clientLink.Id = id;
 
            db.Entry(clientLink).State = EntityState.Modified;
            db.SaveChanges();
 
            return Ok(new
            {
                action = "updated"
            });
        }
 
        // DELETE api/Link/5
        [System.Web.Http.HttpDelete]
        public IHttpActionResult DeleteLink(int id)
        {
            var link = db.Links.Find(id);
            if (link != null)
            {
                db.Links.Remove(link);
                db.SaveChanges();
            }
            return Ok(new
            {
                action = "deleted" 
            });
        }
 
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
 
    }
}

Daten-Controller

Fügen Sie schließlich einen Controller hinzu, um die Datenaktion zu bearbeiten:

Controllers/DataController.cs

using System.Web.Http;
 
using DHX.Gantt.Web.Models;
 
namespace DHX.Gantt.Web.Controllers
{
    public class DataController : ApiController
    {
        // GET api/
        [System.Web.Http.HttpGet]
        public GanttDto Get()
        {
            return new GanttDto
            {
                data = new TaskController().Get(),
                links = new LinkController().Get()
            };
        }
    }
}

Sobald alles eingerichtet ist, sollte das Ausführen der Anwendung ein voll funktionsfähiges Gantt-Diagramm anzeigen:

Sehen Sie sich die Demo auf GitHub an.


Fehlerbehandlung

Um Ausnahmen in CRUD-Aktionen zu behandeln und clientlesbare Antworten zurückzugeben, können Sie Exception Filters verwenden.

So können Sie es einrichten:

  1. Erstellen Sie im App_Start-Ordner eine neue Klasse namens GanttAPIExceptionFilterAttribute:

App_Start/GanttAPIExceptionFilterAttribute.cs

using System.Net;
using System.Net.Http;
using System.Web.Http.Filters;
 
namespace DHX.Gantt.Web
{
    public class GanttAPIExceptionFilterAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
 
            context.Response = context.Request.CreateResponse(
                HttpStatusCode.InternalServerError, new
                    {
                        action = "error",
                        message = context.Exception.Message
                    }
            );
        }
    }
}
  1. Fügen Sie diese Klasse allen WebAPI-Controllern hinzu:
  • Daten-Controller:

Controllers/DataController.cs

namespace DHX.Gantt.Web.Controllers
{
    [GanttAPIExceptionFilter]    public class DataController : ApiController
  • Link-Controller:

Controllers/LinkController.cs

namespace DHX.Gantt.Web.Controllers
{
    [GanttAPIExceptionFilter]    public class LinkController : ApiController
  • Task-Controller:

Controllers/TaskController.cs

namespace DHX.Gantt.Web.Controllers
{
    [GanttAPIExceptionFilter]    public class TaskController : ApiController

Dies stellt sicher, dass alle von den Web API-Controllern ausgelösten Ausnahmen zu einer Fehlerantwort führen, die das clientseitige Gantt verarbeiten kann.


Speichern der Reihenfolge von Aufgaben

Das Gantt-Diagramm unterstützt Aufgaben-Neuanordnungen per Drag & Drop. Wenn Sie diese Funktion verwenden, müssen Sie die Reihenfolge in der Datenbank speichern. Hier ist ein allgemeiner Leitfaden, wie Sie dies handhaben können.

Ermöglichen der Aufgaben-Neuanordnung auf dem Client

Um Benutzern die Neuanordnung von Aufgaben in der Benutzeroberfläche zu ermöglichen, sind einige Aktualisierungen erforderlich.

Öffnen Sie die Index-Ansicht und passen Sie die Gantt-Konfiguration an:

Views/Home/Index.cshtml

gantt.config.order_branch = true;gantt.config.order_branch_free = true; 
// Datumsformat festlegen
gantt.config.date_format = "%Y-%m-%d %H:%i";
// Gantt initialisieren
gantt.init("gantt_here");

Hinzufügen der Aufgabenreihenfolge zum Modell

Diese Änderungen müssen auch im Backend widergespiegelt werden.

Um die Reihenfolge zu speichern, wird dem Task-Klasse eine neue Eigenschaft namens SortOrder hinzugefügt:

Models/Task.cs

using System;
using System.ComponentModel.DataAnnotations;
 
namespace DHX.Gantt.Web.Models
{
    public class Task
    {
        public int Id { get; set; }
        [MaxLength(255)]
        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; }
        public int SortOrder { get; set; }    }
}

Der TaskController benötigt ebenfalls einige Updates:

  • Aufgaben sollten sortiert nach ihrem SortOrder-Wert an den Client gesendet werden:

Controllers/TaskController.cs

namespace DHX.Gantt.Web.Controllers
{
    [GanttAPIExceptionFilter]
    public class TaskController : ApiController
    {
        private GanttContext db = new GanttContext();
 
        // GET api/Task
        public IEnumerable<TaskDto> Get()
        {
            return db.Tasks
                .OrderBy(t => t.SortOrder)                 .ToList()
                .Select(t => (TaskDto)t);
        }
  • Neue Aufgaben sollten automatisch einen Standardwert für SortOrder erhalten:

Controllers/TaskController.cs

namespace DHX.Gantt.Web.Controllers
{
    [System.Web.Http.HttpPost]
    public IHttpActionResult CreateTask(TaskDto taskDto)
    {
        var newTask = (Task)taskDto;
 
        newTask.SortOrder = db.Tasks.Max(t => t.SortOrder) + 1; 
        db.Tasks.Add(newTask);
        db.SaveChanges();
 
        return Ok(new
        {
            tid = newTask.Id,
            action = "inserted"
        });
    }
  • Der SortOrder sollte aktualisiert werden, wenn die Aufgabenreihenfolge auf dem Client geändert wird.

Wenn Aufgaben neu angeordnet werden, sendet Gantt eine PUT-Anfrage mit der neuen Position in der ['target'](Serverseitige Integration)-Eigenschaft zusammen mit anderen Aufgabendetails. Um dies zu handhaben, wird der TaskDto-Klasse eine zusätzliche Eigenschaft hinzugefügt:

Models/TaskDto.cs

namespace DHX.Gantt.Web.Models
{
  public class TaskDto
  {
    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 string target { get; set; } 
    ...
  }
}

Schließlich wird die Neuanordnungslogik in der EditTask-Aktion implementiert:

Controllers/TaskController.cs

    // PUT api/Task/5
    [System.Web.Http.HttpPut]
    public IHttpActionResult EditTask(int id, TaskDto taskDto)
    {
      var updatedTask = (Task)taskDto;
      updatedTask.Id = id;
 
      if (!string.IsNullOrEmpty(taskDto.target))
      {
        // Neuanordnung erfolgte
        this._UpdateOrders(updatedTask, taskDto.target);      }
 
      db.Entry(updatedTask).State = EntityState.Modified;
      db.SaveChanges();
 
      return Ok(new
      {
        action = "updated"
      });
    }
 
    private void _UpdateOrders(Task updatedTask, string orderTarget)    {
      int adjacentTaskId;
      var nextSibling = false;
 
      var targetId = orderTarget;
 
      // Die ID der angrenzenden Aufgabe wird entweder als '{id}' oder als 'next:{id}' gesendet, je nachdem, ob es sich um das nächste oder das vorherige Geschwister handelt
      if (targetId.StartsWith("next:"))
      {
        targetId = targetId.Replace("next:", "");
        nextSibling = true;
      }
 
      if (!int.TryParse(targetId, out adjacentTaskId))
      {
        return;
      }
 
      var adjacentTask = db.Tasks.Find(adjacentTaskId);
      var startOrder = adjacentTask.SortOrder;
 
      if (nextSibling)
        startOrder++;
 
      updatedTask.SortOrder = startOrder;
 
      var updateOrders = db.Tasks
       .Where(t => t.Id != updatedTask.Id)
       .Where(t => t.SortOrder >= startOrder)
       .OrderBy(t => t.SortOrder);
 
       var taskList = updateOrders.ToList();
 
       taskList.ForEach(t => t.SortOrder++);
    }

Bekannte Probleme

HTTP PUT- und DELETE-Anfragen können 405- oder 401-Fehler zurückgeben, wenn die App auf IIS ausgeführt wird. Dies kann aufgrund eines Konflikts mit dem WebDAV-Modul auftreten. Um dies zu beheben, deaktivieren Sie das Modul in der web.config-Datei. Weitere Details finden Sie hier.

Anwendungssicherheit

Gantt enthält keinen integrierten Schutz gegen Bedrohungen wie SQL-Injection, XSS oder CSRF-Angriffe. Die Sicherstellung der Anwendungssicherheit liegt in der Verantwortung der Entwickler, die am Backend arbeiten. Weitere Informationen finden Sie in diesem Artikel.

Fehlerbehebung

Fehlende ASP.NET-Webanwendungsvorlage

Wenn die Projektvorlage "ASP.NET Web Application" in Visual Studio 2022 nicht verfügbar ist, führen Sie die folgenden Schritte aus:

  1. Schließen Sie Visual Studio 2022.
  2. Öffnen Sie den Visual Studio Installer über das Startmenü.
  3. Suchen Sie Visual Studio Community 2022 und klicken Sie auf Ändern.

  4. Gehen Sie im Installer zu Individuelle Komponenten, aktivieren Sie die Option ".NET Framework Project and item templates" und klicken Sie auf Ändern.

Danach sollten Sie Visual Studio 2022 erneut öffnen und die Vorlage sollte verfügbar sein.

Datenbankinitialisierungsfehler

Wenn es ein Problem mit dem DropCreateDatabaseIfModelChanges-Initializer gibt, der keine neue Datenbank erstellt, aktualisieren Sie GanttInitializer.cs, um stattdessen DropCreateDatabaseAlways zu verwenden:

App_Start/GanttInitializer.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
 
namespace DHX.Gantt.Web.Models
{
    public class GanttInitializer : DropCreateDatabaseAlways<GanttContext>     {
        ...
    }
}

Starten Sie dann die Anwendung neu.

Renderingprobleme für Aufgaben und Links

Wenn Aufgaben und Links nach Abschluss der Schritte nicht auf der Seite angezeigt werden, lesen Sie den Fehlerbehebungsleitfaden im Artikel Fehlerbehebung bei Backend-Integrationsproblemen für Tipps zur Problemerkennung.

Was kommt als Nächstes

Ihr Gantt ist jetzt voll funktionsfähig. Der vollständige Code ist auf GitHub verfügbar, wo Sie ihn für Ihre Projekte klonen oder herunterladen können.

Für weitere Funktionen und Anleitungen schauen Sie sich die Feature-Dokumentation oder Tutorials zur Integration von Gantt mit anderen Backend-Frameworks an.

Zurück nach oben