ApiHotelProject is a hotel management system built on ASP.NET Core: a layered Web API backend, an ASP.NET Core MVC front end with a public site and an admin dashboard, and SQL Server for storage.
Live demo: https://hotel-demo-453942543225.europe-west1.run.app
Demo account: demo / Demo.2026!
The demo runs on free tiers. The database is Azure SQL serverless and pauses when idle, so the very first request after a quiet period can take 30-60 seconds. After that it is fast. Files uploaded through the admin panel are not persisted, because the container filesystem is ephemeral.
-
ApiConsume: the backend.
- Entity Layer: entity models representing the core domain objects (
AppUser,Booking,Room,Staff,Testimonial,Service, ...) and the relationships between them. - Data Access Layer: database access through Entity Framework Core. Holds
Context, the migrations, and the repository implementations. - DTO Layer: data transfer objects used between layers, so entities are not exposed directly at the API boundary.
- Business Layer: service classes that orchestrate business operations and keep the rules out of the controllers.
- Web API: RESTful endpoints for every resource. Documented with Swagger.
- Entity Layer: entity models representing the core domain objects (
-
Frontend:
- Web UI: the ASP.NET Core MVC application. The "Default" part is the public hotel site (rooms, services, team, testimonials, booking and contact forms); the "Admin" part is the dashboard for managing users, bookings, rooms, staff and messages.
Requires the .NET 10 SDK and a SQL Server instance.
-
Point the app at a database. Copy
.env.exampleto.envand fill in your connection string, or export it in your shell:export HOTELDB_CONNECTION="Server=tcp:YOUR-SERVER.database.windows.net,1433;Initial Catalog=ApiDb;User ID=YOUR-USER;Password=YOUR-PASSWORD;Encrypt=True;Connection Timeout=60;"
The schema and a set of demo records (rooms, staff, services, testimonials, bookings and the
demoadmin account) are created automatically the first time the Web UI starts. -
Start both projects. In VS Code press F5 and pick Run everything (API + Web UI), or use two terminals:
# Terminal 1 - Web API cd ApiConsume/HotelProject.WebApi ASPNETCORE_ENVIRONMENT=Development ASPNETCORE_URLS=http://localhost:11888 dotnet run # Terminal 2 - Web UI cd Frontend/HotelProject.WebUI ASPNETCORE_ENVIRONMENT=Development ASPNETCORE_URLS=http://localhost:5050 dotnet run
The site runs on 5050 rather than the usual 5000 because macOS gives port 5000 to the AirPlay Receiver.
-
Open the app:
URL What you get http://localhost:5050/ Public hotel site http://localhost:5050/Login/Index Admin login ( demo/Demo.2026!)http://localhost:5050/Dashboard/Index Admin dashboard http://localhost:11888/swagger API documentation
SQL Server has no native Apple Silicon build, but the official image runs under Rosetta:
docker run -d --platform linux/amd64 --name hotel-sql \
-e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=LocalDev.2026!" -e "MSSQL_PID=Developer" \
-p 1433:1433 mcr.microsoft.com/mssql/server:2022-latestThen use Server=localhost,1433;Initial Catalog=ApiDb;User ID=sa;Password=LocalDev.2026!;Encrypt=True;TrustServerCertificate=True;
Both applications ship in a single image. The Web API binds to loopback inside the container and is
never exposed publicly; the MVC front end talks to it over 127.0.0.1 and is the only thing
listening on the public port.
docker build -t hotel-demo .
docker run -p 8080:8080 -e "HOTELDB_CONNECTION=..." hotel-demogcloud run deploy hotel-demo \
--source . \
--region europe-west1 \
--allow-unauthenticated \
--memory 1Gi --cpu 1 \
--min-instances 0 --max-instances 1 \
--timeout 120 \
--set-secrets "HOTELDB_CONNECTION=hoteldb-connection:latest"ApiSettings__BaseUrl and ASPNETCORE_ENVIRONMENT already have production defaults baked into the
image. The connection string is read from Secret Manager and never stored in the repository.
| Setting | Where | Purpose |
|---|---|---|
HOTELDB_CONNECTION |
environment variable | SQL Server connection string. Required. |
ApiSettings:BaseUrl |
appsettings.json / ApiSettings__BaseUrl |
Base address of the Web API. Defaults to http://localhost:11888/. |
EmailConfig:Email, EmailConfig:Password |
user secrets / environment | SMTP credentials for the admin mail page. Optional; the page explains itself when they are missing. |
- .NET 10 (LTS) - runtime and SDK for every project
- ASP.NET Core Web API - the backend
- ASP.NET Core MVC - the front end, with view components for reusable sections
- Entity Framework Core 10 - data access, migrations and automatic schema creation
- MS SQL Server / Azure SQL Database - storage
- ASP.NET Core Identity - authentication, roles and role assignment
- AutoMapper - entity/DTO mapping
- FluentValidation - input validation
- Swagger (Swashbuckle) - API documentation
- MailKit - SMTP mail
- Docker + Google Cloud Run - containerised deployment
- Bootstrap 5 - styling
- The solution follows an N-tier architecture; the DTO layer keeps entities away from the API surface.
- The front end never talks to the database for domain data. Every read and write goes through the Web API using a named
HttpClientwhose base address comes from configuration. - Public pages degrade gracefully: if the API is unavailable the sections render empty instead of returning an error page.
- Data Protection keys are stored in the database, so login sessions survive container restarts.
RapidApiandJwtProject, two scratch projects used for experimenting with third-party APIs and JWT, were removed from this repository; they were unrelated to the hotel application.