A full-stack integration system: Quartz Job → WCF → GitHub Private Repo → ASP.NET Core API → Angular (Kendo Grid)
┌─────────────────────────────────────────────────────────────────┐
│ Angular Frontend (:4200) │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ Live Commits Grid │ │ Scheduled Commits │ 🌙/☀️ │
│ │ [Refresh Live Data] │ │ LastSyncTime: ... │ Theme │
│ └──────────┬───────────┘ └──────────┬───────────┘ │
│ │ GET /api/github/live │ GET /api/github/scheduled│
└────────────┼─────────────────────────┼──────────────────────────┘
│ │
┌────────────┴─────────────────────────┴──────────────────────────┐
│ ASP.NET Core Web API (:5000) — Serilog Logging │
│ GitHubController + GlobalExceptionHandler + Swagger │
│ │ WCF Client (ChannelFactory) │
└────────────┼────────────────────────────────────────────────────┘
│
┌────────────┴────────────────────────────────────────────────────┐
│ WCF Service + Quartz Scheduler (:5010) — CoreWCF │
│ ┌────────────────────┐ ┌─────────────────────────────────┐ │
│ │ GetLiveCommits() │──│ GitHub API (Bearer Token) │ │
│ │ GetScheduledCommits│ └─────────────────────────────────┘ │
│ └────────────────────┘ │
│ ┌────────────────────┐ ┌─────────────────────────────────┐ │
│ │ Quartz Job (60s) │──│ In-Memory Cache + LastSyncTime │ │
│ └────────────────────┘ └─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
| Project | Tech | Port | Purpose |
|---|---|---|---|
AsapJobTaskAssignment.Shared |
.NET 8 Class Library | — | Shared DTOs |
AsapJobTaskAssignment.WcfService |
CoreWCF + Quartz.NET | 5010 | WCF endpoints + Scheduled job |
AsapJobTaskAssignment.WebApi |
ASP.NET Core 8 + Serilog | 5000 | REST API + Swagger |
AsapJobTaskAssignment.Angular |
Angular 17 + Kendo UI | 4200 | Frontend with dark/light theme |
AsapJobTaskAssignment.E2E |
Playwright + MSTest | — | End-to-end browser tests |
- .NET 8 SDK
- Node.js 18+ & npm
- GitHub Personal Access Token (read-only for the private repo)
Edit src/AsapJobTaskAssignment.WcfService/appsettings.json:
{
"GitHub": {
"Token": "YOUR_GITHUB_TOKEN_HERE",
"RepoApiUrl": "https://api.github.com/repos/company/integration-task-private-repo/commits"
}
}cd src/AsapJobTaskAssignment.WcfService
dotnet runThis starts:
- WCF endpoint at
http://localhost:5010/CommitService.svc - Quartz job fetching commits every 60 seconds
cd src/AsapJobTaskAssignment.WebApi
dotnet run- API at
http://localhost:5000 - Swagger UI at
http://localhost:5000/swagger
cd src/AsapJobTaskAssignment.Angular
npm install
ng serveOpen http://localhost:4200
# Install Playwright browsers (first time only)
pwsh tests/AsapJobTaskAssignment.E2E/bin/Debug/net8.0/playwright.ps1 install
# Run tests
cd tests/AsapJobTaskAssignment.E2E
dotnet test- The GitHub API token is stored in
appsettings.jsonunderGitHub:Token - It is passed via the
Authorization: Bearer {TOKEN}header - The
User-Agent: IntegrationTaskAppheader is included as required by GitHub API - 401 Unauthorized errors are caught and returned as structured error responses
Both the WCF Service and WebApi use Serilog with:
- Console sink — structured log output for development
- File sink — rolling daily log files in
logs/folder - Request logging — HTTP request/response logging in WebApi
- Enrichers — MachineName, ThreadId, CorrelationId
- Live Commits: Real-time fetch from GitHub API via WCF
- Scheduled Commits: Cached data from Quartz job (every 60 seconds)
- Dark / Light Theme: Toggle with localStorage persistence
- Kendo Grid: Sortable, resizable columns (Message, Author, Date, SHA, Source)
- Error Handling: Kendo Dialog for errors, unified
{ success, message, data }API responses - Playwright E2E Tests: Automated browser tests for all features
- Used CoreWCF (a modern .NET 8 port) instead of .NET Framework 4.8 WCF for compatibility
- WCF + Quartz are hosted in a single process for simplicity
- The GitHub token is a placeholder — replace before running
- Kendo UI requires a license or free trial
- The Quartz job runs immediately on startup then every 60 seconds
- In-memory cache is used (data is lost on restart)