Below is a complete, ready-to-implement source code structure with essential files and sample code for a Real-Time GPS Tracking Dashboard using Angular (frontend) and ASP.NET Core (backend) with SignalR and SQL Server.
The structure is minimal but production-friendly — includes Docker, migrations, and run instructions. Use this as a starter and extend as needed.
Repository root
gps-tracking/
├─ backend/
│ ├─ src/
│ │ ├─ GpsTracking.sln
│ │ ├─ GpsTracking.Api/ # ASP.NET Core Web API + SignalR
│ │ ├─ GpsTracking.Core/ # Domain models / DTOs
│ │ └─ GpsTracking.Infrastructure/ # EF Core DbContext, Migrations
│ ├─ docker-compose.yml
│ └─ README.md
├─ frontend/
│ ├─ gps-dashboard/ # Angular project
│ │ ├─ src/
│ │ │ ├─ app/
│ │ │ │ ├─ components/
│ │ │ │ │ ├─ live-map/
│ │ │ │ │ │ ├─ live-map.component.ts
│ │ │ │ │ │ ├─ live-map.component.html
│ │ │ │ │ │ └─ live-map.component.scss
│ │ │ │ │ └─ device-list/
│ │ │ │ ├─ services/
│ │ │ │ │ ├─ tracking.service.ts
│ │ │ │ │ └─ signalr.service.ts
│ │ │ │ ├─ models/
│ │ │ │ │ └─ location.model.ts
│ │ │ │ ├─ app.module.ts
│ │ │ │ └─ app.component.*
│ │ │ └─ index.html
│ │ ├─ angular.json
│ │ └─ package.json
│ └─ README.md
└─ README.md
Backend — ASP.NET Core (essential files & snippets)
Projects
GpsTracking.Api — ASP.NET Core Web API with SignalR hub and REST endpoints.
GpsTracking.Core — DTOs and domain models.
GpsTracking.Infrastructure — ApplicationDbContext, EF entities, migrations.
GpsTracking.Core (models / DTOs)
GpsTracking.Core/Models/Device.cs
namespace GpsTracking.Core.Models
{
public class Device
{
public string DeviceId { get; set; } = null!;
public string Name { get; set; } = "";
public string? Type { get; set; }
public bool IsActive { get; set; } = true;
}
}
GpsTracking.Core/Models/LocationLog.cs
using System;
namespace GpsTracking.Core.Models
{
public class LocationLog
{
public int LogId { get; set; }
public string DeviceId { get; set; } = null!;
public double Latitude { get; set; }
public double Longitude { get; set; }
public double? Speed { get; set; }
public double? Direction { get; set; }
public DateTime RecordedAt { get; set; } = DateTime.UtcNow;
}
}
GpsTracking.Core/DTOs/LocationDto.cs
public class LocationDto
{
public string DeviceId { get; set; } = null!;
public double Latitude { get; set; }
public double Longitude { get; set; }
public double? Speed { get; set; }
public double? Direction { get; set; }
public DateTime RecordedAt { get; set; } = DateTime.UtcNow;
}
GpsTracking.Infrastructure — DbContext & EF configuration
GpsTracking.Infrastructure/ApplicationDbContext.cs
using Microsoft.EntityFrameworkCore;
using GpsTracking.Core.Models;
namespace GpsTracking.Infrastructure
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> opts) : base(opts) { }
public DbSet<Device> Devices { get; set; }
public DbSet<LocationLog> LocationLogs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Device>().HasKey(d => d.DeviceId);
builder.Entity<LocationLog>().HasKey(l => l.LogId);
builder.Entity<LocationLog>()
.HasIndex(l => new { l.DeviceId, l.RecordedAt });
}
}
}
Add EF Core packages to projects:
dotnet add GpsTracking.Infrastructure package Microsoft.EntityFrameworkCore.SqlServer
dotnet add GpsTracking.Infrastructure package Microsoft.EntityFrameworkCore.Design
dotnet add GpsTracking.Api package Microsoft.EntityFrameworkCore.SqlServer
dotnet tool install --global dotnet-ef
Create migration and update DB (run from solution root):
cd backend/src/GpsTracking.Api
dotnet ef migrations add InitialCreate --project ../GpsTracking.Infrastructure --startup-project ./ -o ../GpsTracking.Infrastructure/Migrations
dotnet ef database update --project ../GpsTracking.Infrastructure --startup-project .
GpsTracking.Api — Program.cs (minimal)
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// DbContext
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// SignalR
builder.Services.AddSignalR();
// CORS (allow frontend)
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().AllowCredentials().WithOrigins("http://localhost:4200");
});
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapHub<TrackingHub>("/gpsHub");
app.Run();
SignalR Hub
GpsTracking.Api/Hubs/TrackingHub.cs
using Microsoft.AspNetCore.SignalR;
using GpsTracking.Core.DTOs;
public class TrackingHub : Hub
{
public async Task BroadcastLocation(LocationDto dto)
{
await Clients.All.SendAsync("locationUpdated", dto);
}
}
Controller: receive device updates and broadcast
GpsTracking.Api/Controllers/TrackingController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using GpsTracking.Core.DTOs;
using GpsTracking.Infrastructure;
[ApiController]
[Route("api/[controller]")]
public class TrackingController : ControllerBase
{
private readonly ApplicationDbContext _db;
private readonly IHubContext<TrackingHub> _hub;
public TrackingController(ApplicationDbContext db, IHubContext<TrackingHub> hub)
{
_db = db;
_hub = hub;
}
[HttpPost("update-location")]
public async Task<IActionResult> UpdateLocation([FromBody] LocationDto dto)
{
// persist
var log = new LocationLog
{
DeviceId = dto.DeviceId,
Latitude = dto.Latitude,
Longitude = dto.Longitude,
Speed = dto.Speed,
Direction = dto.Direction,
RecordedAt = dto.RecordedAt
};
_db.LocationLogs.Add(log);
await _db.SaveChangesAsync();
// broadcast
await _hub.Clients.All.SendAsync("locationUpdated", dto);
return Ok();
}
[HttpGet("history/{deviceId}")]
public IActionResult GetHistory(string deviceId, int limit = 100)
{
var rows = _db.LocationLogs
.Where(l => l.DeviceId == deviceId)
.OrderByDescending(l => l.RecordedAt)
.Take(limit)
.ToList();
return Ok(rows);
}
}
Dockerfile (API)
backend/src/GpsTracking.Api/Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["GpsTracking.Api/GpsTracking.Api.csproj","GpsTracking.Api/"]
COPY ["GpsTracking.Infrastructure/GpsTracking.Infrastructure.csproj","GpsTracking.Infrastructure/"]
COPY ["GpsTracking.Core/GpsTracking.Core.csproj","GpsTracking.Core/"]
RUN dotnet restore "GpsTracking.Api/GpsTracking.Api.csproj"
COPY . .
WORKDIR "/src/GpsTracking.Api"
RUN dotnet publish "GpsTracking.Api.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "GpsTracking.Api.dll"]
docker-compose.yml (backend)
backend/docker-compose.yml
version: '3.8'
services:
mssql:
image: mcr.microsoft.com/mssql/server:2019-latest
environment:
SA_PASSWORD: "Your_password123"
ACCEPT_EULA: "Y"
ports:
- "1433:1433"
healthcheck:
test: ["CMD-SHELL", "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Your_password123 -Q 'select 1'"]
interval: 10s
timeout: 5s
retries: 10
api:
build:
context: ./src
dockerfile: GpsTracking.Api/Dockerfile
depends_on:
- mssql
environment:
- ConnectionStrings__DefaultConnection=Server=mssql,1433;Database=GpsTrackingDb;User=sa;Password=Your_password123;
ports:
- "5000:80"
Frontend — Angular (essential files & snippets)
Create app
ng new gps-dashboard --routing=true --style=scss
cd gps-dashboard
npm install @microsoft/signalr
Models
src/app/models/location.model.ts
export interface LocationDto {
deviceId: string;
latitude: number;
longitude: number;
speed?: number;
direction?: number;
recordedAt?: string;
}
SignalR service
src/app/services/signalr.service.ts
import { Injectable } from '@angular/core';
import * as signalR from '@microsoft/signalr';
import { Subject } from 'rxjs';
import { LocationDto } from '../models/location.model';
@Injectable({ providedIn: 'root' })
export class SignalrService {
private hubConnection!: signalR.HubConnection;
public location$ = new Subject<LocationDto>();
public startConnection(baseUrl: string) {
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${baseUrl}/gpsHub`)
.withAutomaticReconnect()
.build();
this.hubConnection.start()
.then(() => console.log('SignalR connected'))
.catch(err => console.error('SignalR error', err));
this.hubConnection.on('locationUpdated', (data: LocationDto) => {
this.location$.next(data);
});
}
public stop() {
this.hubConnection?.stop();
}
}
Tracking API service
src/app/services/tracking.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { LocationDto } from '../models/location.model';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class TrackingService {
constructor(private http: HttpClient) {}
sendLocation(dto: LocationDto) {
return this.http.post('/api/tracking/update-location', dto);
}
getHistory(deviceId: string, limit = 100): Observable<LocationDto[]> {
return this.http.get<LocationDto[]>(`/api/tracking/history/${deviceId}?limit=${limit}`);
}
}
Map component (Google Maps + SignalR)
src/app/components/live-map/live-map.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { SignalrService } from '../../services/signalr.service';
import { environment } from '../../../environments/environment';
declare const google: any;
@Component({
selector: 'app-live-map',
templateUrl: './live-map.component.html',
styleUrls: ['./live-map.component.scss']
})
export class LiveMapComponent implements OnInit, OnDestroy {
map: any;
markers: Record<string, any> = {};
constructor(private signalr: SignalrService) {}
ngOnInit() {
this.initMap();
this.signalr.startConnection(environment.apiBaseUrl);
this.signalr.location$.subscribe(loc => this.updateMarker(loc));
}
ngOnDestroy() {
this.signalr.stop();
}
initMap() {
const el = document.getElementById('map')!;
this.map = new google.maps.Map(el, {
center: { lat: 19.0760, lng: 72.8777 },
zoom: 12
});
}
updateMarker(loc: any) {
if (!this.markers[loc.deviceId]) {
this.markers[loc.deviceId] = new google.maps.Marker({
position: { lat: loc.latitude, lng: loc.longitude },
map: this.map,
title: loc.deviceId
});
} else {
const pos = new google.maps.LatLng(loc.latitude, loc.longitude);
this.markers[loc.deviceId].setPosition(pos);
}
// Optionally pan/animate map:
// this.map.panTo(new google.maps.LatLng(loc.latitude, loc.longitude));
}
}
src/app/components/live-map/live-map.component.html
<div id="map" class="map-container"></div>
src/app/components/live-map/live-map.component.scss
.map-container { width: 100%; height: 100vh; }
Add Google Maps script in index.html:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_MAPS_KEY&libraries=geometry"></script>
Set environment.apiBaseUrl in src/environments/environment.ts:
export const environment = {
production: false,
apiBaseUrl: 'http://localhost:5000'
};
App module (imports)
app.module.ts must import HttpClientModule and declare components and services.
Build & Run instructions
Local (without Docker)
Backend
Set connection string in appsettings.Development.json:
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=GpsTrackingDb;Trusted_Connection=True;"
}
Apply migrations and run:
cd backend/src/GpsTracking.Api
dotnet ef database update --project ../GpsTracking.Infrastructure --startup-project .
dotnet run
Frontend
Set Google Maps API key in index.html.
Start Angular dev server:
cd frontend/gps-dashboard
npm install
ng serve
Open http://localhost:4200 and the Angular app should connect to API at http://localhost:5000.
Using Docker (recommended for parity)
From backend/ folder
docker-compose up --build
This starts SQL Server and the API. Then run Angular locally or containerise it.
Notes & Next Steps (production hardening)
Use HTTPS and secure SignalR endpoint.
Configure CORS properly for production origin(s).
Use authentication (JWT) for devices and dashboard users.
Use SignalR scale-out (Redis backplane or Azure SignalR Service) for many concurrent connections.
Partition and index LocationLog for performance; consider time-based partitions.
Implement rate limiting and batch writes from devices to protect DB.
Add monitoring (Application Insights / Prometheus) and logging.
Add UI features: clustering, heatmaps, playback, geo-fences, alerts.