ASP.NET Core  

Zero-Cost, Insurance Quote App in .NET 8 with Azure DevOps Zip Deploy

The $0 DevOps Revolution

In 2025, enterprise-grade CI/CD pipelines are no longer the domain of billion-dollar budgets.

What if you could build, test, deploy, and auto-heal a production web application — with real user data, health checks, and persistence — for $0?

This article shows you exactly how to do it.

We’ll build a professional insurance quote form in .NET 8, deploy it via Azure DevOps using Zip Deploy, and run it on Azure App Service (Free Tier) — all with zero cost, zero paid tools, and 100% automation.

No Kudu. No FTP. No CLI. No manual uploads.

Just git push → automated deploy → live app → health check → auto-restart.

This is modern DevOps — and it’s completely free.

Build the Insurance Quote App — .NET 8 MVC (Zero Dependencies)

Tech Stack (All Free & Open Source)

ComponentWhy it matters
.NET 8 ASP.NET Core MVCFast, secure, cross-platform, Microsoft’s flagship web framework
SQLiteFile-based database — no server, no license, no cost
Bootstrap 5 + Font AwesomeProfessional, responsive UI — CDN-hosted, zero install
GitHubFree private/public repos — version control, CI trigger
Azure DevOpsFree 1800 pipeline minutes/month — perfect for small apps

System design (HLD)

hld

Source Code

InsuranceQuoteApp.csproj — Minimal & Clean

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.7" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.7">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>
</Project>

Run dotnet restore to pull in EF Core SQLite.

Models/InsuranceQuote.cs — Data Model with Validation

using System.ComponentModel.DataAnnotations;

namespace InsuranceQuoteApp.Models
{
    public class InsuranceQuote
    {
        [Key]
        public int Id { get; set; }

        [Required(ErrorMessage = "Name is required")]
        [Display(Name = "Full Name")]
        public string Name { get; set; } = string.Empty;

        [Required(ErrorMessage = "Age is required")]
        [Range(18, 120, ErrorMessage = "Age must be between 18 and 120")]
        public int Age { get; set; }

        [Required(ErrorMessage = "Vehicle type is required")]
        [Display(Name = "Vehicle Type")]
        public string VehicleType { get; set; } = string.Empty;

        [Required(ErrorMessage = "Driving experience is required")]
        [Range(0, 60, ErrorMessage = "Experience must be between 0 and 60 years")]
        public int ExperienceYears { get; set; }

        public decimal QuoteAmount { get; set; }
        public DateTime QuoteDate { get; set; } = DateTime.Now;
    }
}

Server-side validation built-in. No JavaScript needed.

Models/QuoteContext.cs — SQLite Database Context

using Microsoft.EntityFrameworkCore;

namespace InsuranceQuoteApp.Models
{
    public class QuoteContext : DbContext
    {
        public QuoteContext(DbContextOptions<QuoteContext> options) : base(options) { }

        public DbSet<InsuranceQuote> InsuranceQuotes { get; set; }
    }
}

SQLite creates insurancequotes.db automatically on first run.

Controllers/QuoteController.cs — Logic & Pricing Engine

using Microsoft.AspNetCore.Mvc;
using InsuranceQuoteApp.Models;

namespace InsuranceQuoteApp.Controllers
{
    public class QuoteController : Controller
    {
        private readonly QuoteContext _context;

        public QuoteController(QuoteContext context)
        {
            _context = context;
        }

        public IActionResult Index() => View();

        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Calculate(InsuranceQuote quote)
        {
            if (!ModelState.IsValid)
                return View("Index", quote);

            // Realistic pricing logic
            decimal basePrice = 500m;
            if (quote.Age < 25) basePrice += 200m;     // Young driver
            if (quote.VehicleType == "Sports Car") basePrice += 300m; // High risk
            if (quote.ExperienceYears > 10) basePrice -= 100m; // Loyalty discount
            if (quote.ExperienceYears == 0) basePrice += 150m; // New driver

            quote.QuoteAmount = basePrice;
            _context.InsuranceQuotes.Add(quote);
            _context.SaveChanges();

            return View("Result", quote);
        }
    }
}

Views/Quote/Index.cshtml — Clean, Professional Form

@model InsuranceQuoteApp.Models.InsuranceQuote

@{
    ViewData["Title"] = "Free Insurance Quote";
}

<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-8 col-lg-6">
            <div class="card shadow-lg">
                <div class="card-header bg-primary text-white text-center">
                    <h2><i class="fas fa-shield-alt"></i> Get Your Free Insurance Quote</h2>
                </div>
                <div class="card-body">
                    <form asp-action="Calculate" method="post">
                        <div asp-validation-summary="All" class="text-danger mb-3"></div>

                        <div class="form-group mb-3">
                            <label asp-for="Name" class="form-label"></label>
                            <input asp-for="Name" class="form-control" placeholder="Enter your full name" />
                            <span asp-validation-for="Name" class="text-danger"></span>
                        </div>

                        <div class="form-group mb-3">
                            <label asp-for="Age" class="form-label"></label>
                            <input asp-for="Age" class="form-control" type="number" min="18" max="120" placeholder="Enter your age" />
                            <span asp-validation-for="Age" class="text-danger"></span>
                        </div>

                        <div class="form-group mb-3">
                            <label asp-for="VehicleType" class="form-label"></label>
                            <select asp-for="VehicleType" class="form-select">
                                <option value="">-- Select Vehicle Type --</option>
                                <option value="Sedan">Sedan</option>
                                <option value="SUV">SUV</option>
                                <option value="Truck">Truck</option>
                                <option value="Sports Car">Sports Car</option>
                            </select>
                            <span asp-validation-for="VehicleType" class="text-danger"></span>
                        </div>

                        <div class="form-group mb-3">
                            <label asp-for="ExperienceYears" class="form-label"></label>
                            <input asp-for="ExperienceYears" class="form-control" type="number" min="0" max="60" placeholder="Years of driving experience" />
                            <span asp-validation-for="ExperienceYears" class="text-danger"></span>
                        </div>

                        <div class="text-center mt-4">
                            <button type="submit" class="btn btn-primary btn-lg w-100">
                                <i class="fas fa-calculator"></i> Get My Free Quote
                            </button>
                        </div>
                    </form>
                </div>
                <div class="card-footer text-center text-muted small">
                    <p><i class="fas fa-lock"></i> No credit card required. Instant quote.</p>
                </div>
            </div>
        </div>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Views/Quote/Result.cshtml — Beautiful Quote Display

@model InsuranceQuoteApp.Models.InsuranceQuote

@{
    ViewData["Title"] = "Your Insurance Quote";
}

<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-8 col-lg-6">
            <div class="card shadow-lg">
                <div class="card-header bg-success text-white text-center">
                    <h2><i class="fas fa-check-circle"></i> Your Insurance Quote</h2>
                </div>
                <div class="card-body">
                    <div class="text-center mb-4">
                        <div class="badge bg-primary fs-5 px-4 py-2 rounded-pill">
                            <strong>Quote Generated</strong>
                        </div>
                    </div>

                    <div class="table-responsive">
                        <table class="table table-bordered table-striped">
                            <tbody>
                                <tr><th scope="row">Name</th><td>@Model.Name</td></tr>
                                <tr><th scope="row">Age</th><td>@Model.Age</td></tr>
                                <tr><th scope="row">Vehicle Type</th><td>@Model.VehicleType</td></tr>
                                <tr><th scope="row">Driving Experience</th><td>@Model.ExperienceYears years</td></tr>
                                <tr class="bg-light">
                                    <th scope="row"><strong>Total Annual Premium</strong></th>
                                    <td class="text-success h4"><strong>[email protected]("F2")</strong></td>
                                </tr>
                            </tbody>
                        </table>
                    </div>

                    <div class="alert alert-info text-center mt-4">
                        <i class="fas fa-info-circle"></i> Your quote is saved. No obligation to purchase.
                    </div>

                    <div class="text-center mt-4">
                        <a href="/Quote" class="btn btn-outline-primary btn-lg">
                            <i class="fas fa-arrow-left"></i> Get Another Quote
                        </a>
                    </div>
                </div>
                <div class="card-footer text-center text-muted small">
                    <p>Generated on: @Model.QuoteDate.ToString("MMMM dd, yyyy 'at' h:mm tt")</p>
                </div>
            </div>
        </div>
    </div>
</div>

Views/Shared/_Layout.cshtml — Unified UI Theme

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Insurance Quote App</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" />
    <link rel="stylesheet" href="~/css/style.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
            <div class="container">
                <a class="navbar-brand" href="/">
                    <i class="fas fa-shield-alt"></i> Insurance Quote App
                </a>
            </div>
        </nav>
    </header>

    <div class="container mt-4">
        @RenderBody()
    </div>

    <footer class="footer bg-light text-center text-muted py-3 mt-5">
        <div class="container">
            <p>&copy; 2025 Insurance Quote App – Free & No Registration Required</p>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

wwwroot/css/style.css — Polished, Responsive Design

.card { border-radius: 12px; overflow: hidden; }
.card-header { font-weight: 600; font-size: 1.5rem; }
.btn-primary { background-color: #0d6efd; border-color: #0d6efd; }
.btn-primary:hover { background-color: #0b5ed7; }
.form-label { font-weight: 600; color: #333; }
.table th, .table td { vertical-align: middle; }
.table-bordered { border: 1px solid #dee2e6; }
.table-striped tbody tr:nth-of-type(odd) { background-color: rgba(0,0,0,0.05); }
.footer { margin-top: 3rem; padding: 1.5rem 0; }
i { margin-right: 8px; }
.text-center { text-align: center !important; }
.bg-light { background-color: #f8f9fa !important; }
.alert { border-radius: 8px; font-weight: 500; }

@media (max-width: 768px) {
    .card { margin: 0 1rem; }
    .btn-lg { font-size: 1rem; padding: 0.75rem 1rem; }
}

appsettings.json — Minimal Config

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Program.cs — The Heart of the App

using Microsoft.EntityFrameworkCore;
using InsuranceQuoteApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<QuoteContext>(options =>
    options.UseSqlite("Data Source=insurancequotes.db"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Quote}/{action=Index}/{id?}");

// Auto-create DB on startup
using (var scope = app.Services.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<QuoteContext>();
    context.Database.EnsureCreated();
}

app.Run();

SQLite database is created automatically on first request — no migration needed.

Zero-Cost Deployment — Azure DevOps + Zip Deploy (CI/CD)

Now that we have a production-ready app, let’s deploy it automatically — with zero human intervention.

We’ll use:

  • GitHub → Code repo

  • Azure DevOps → CI/CD pipeline (free tier)

  • Azure App Service (F1 Free Tier) → Hosting

  • Zip Deploy API → Modern, secure, fast deployment

  • Health Check → Auto-restart if app crashes

Step 1. Create Azure App Service (Free Tier)

  1. Go to https://portal.azure.com

  2. Click Create a resource → Search “Web App”

  3. Fill in:

    • Subscription: Free Trial

    • Resource Group: InsuranceQuoteRG

    • Name: myinsurancequoteapp (must be unique)

    • Publish: Code

    • Runtime stack: .NET 8 (LTS)

    • OS: Windows

    • Plan: Free (F1)CRITICAL

  4. Click Review + CreateCreate

⏳ Wait 3–5 minutes.
Once done, visit: https://myinsurancequoteapp.azurewebsites.net
You’ll see a 404 — that’s normal. We’ll deploy code next.

Step 2. Push Code to GitHub

  1. Go to https://github.com

  2. Create new repo: insurancequoteapp

  3. Initialize with README

  4. In your local project folder:

git init
git add .
git commit -m "Initial commit: Insurance Quote App .NET 8"
git remote add origin https://github.com/yourusername/insurancequoteapp.git
git branch -M main
git push -u origin main

Your code url link should look like(sample link):
👉 https://github.com/yourusername/insurancequoteapp

Step 3. Create Azure DevOps Pipeline (Free)

  1. Go to https://dev.azure.com

  2. Sign in with a Microsoft/GitHub account

  3. Create New Project: InsuranceQuoteProject

  4. Go to PipelinesNew Pipeline

  5. Connect to GitHub → Select insurancequoteapp

  6. Choose “Azure Pipelines YAML”

  7. Replace the default YAML with this exact configuration:

# azure-pipelines.yml
trigger:
- main

pool:
  vmImage: 'windows-latest'

variables:
  buildConfiguration: 'Release'
  zipPackage: '$(Build.ArtifactStagingDirectory)/deploy.zip'

steps:
- task: UseDotNet@2
  inputs:
    packageType: 'sdk'
    version: '8.x'

- script: |
    dotnet restore
    dotnet build --configuration $(buildConfiguration)
    dotnet publish --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)
  displayName: 'dotnet restore, build, publish'

- task: ArchiveFiles@2
  inputs:
    rootFolderOrFile: '$(Build.ArtifactStagingDirectory)'
    includeRootFolder: false
    archiveType: 'zip'
    archiveFile: '$(zipPackage)'
    replaceExistingArchive: true
  displayName: 'Archive files to deploy.zip'

- task: AzureRmWebAppDeployment@4
  inputs:
    ConnectionType: 'AzureRM'
    azureSubscription: 'AzureFreeSubscription'
    Action: 'Deploy Azure App Service'
    AppType: 'webApp'
    WebAppName: 'myinsurancequoteapp'
    Package: '$(zipPackage)'
    UseWebDeploy: false
    EnableCustomDeployment: true
    DeploymentType: 'zipDeploy'
    TakeAppOfflineFlag: true
    RenameFilesFlag: true
    DeploymentStatus: true

Save and Run → It will fail. Why? We haven’t created the Service Connection.

Step 4. Create Azure Service Connection (Critical!)

  1. In Azure DevOps → Go to Project SettingsService Connections

  2. Click New service connectionAzure Resource Manager

  3. Configure:

    • Connection name: AzureFreeSubscription

    • Authentication method: Service Principal (Automatic)

    • Subscription: Your Free Trial

    • Resource group: InsuranceQuoteRG

  4. Click Verify and Save

Success message: Service connection 'AzureFreeSubscription' created successfully

  1. Go back to Pipeline → Click Run

Watch the magic:

  • Build → 45s

  • Publish → 20s

  • Zip → 5s

  • Deploy → 15s

  • DONE.

Open URL similar to : https://myinsurancequoteapp.azurewebsites.net (Sample URL)
Insurance quote form is LIVE!

Step 5. Enable Health Check (Auto-Recovery)

  1. Go to Azure Portal → Resource Group → InsuranceQuoteRG

  2. Click your app → MonitoringHealth Check

  3. Set

    • Status: ON

    • Path: /

    • Interval: 5 minutes

    • Unhealthy threshold: 2

  4. Click Save

Why this matters:
If your app crashes due to SQLite permissions, memory, or config — Azure will auto-restart it every 5 minutes.
No downtime. No alerts. No manual intervention.
This is production-grade resilience — on Free Tier.

Step 6. View & Backup SQLite DB (Kudu Console)

  1. Go to: https://myinsurancequoteapp.scm.azurewebsites.net/DebugConsole

  2. Navigate to: site/wwwroot/

  3. Find: insurancequotes.db

  4. Right-click → Download

Your users’ quotes are stored locally — even on Free Tier.
Use DB Browser for SQLite to inspect data.

Final UI: What Users See

Screen 1

screen1

Screen 2

screen2

Cost Breakdown: $0.00 Total

ComponentCost
.NET 8 SDKFree
SQLite DatabaseFree
Azure App Service (F1)Free (12 months)
Azure DevOps PipelinesFree (1800 mins/month)
GitHubFree
Zip Deploy APIFree
Health CheckFree
Font Awesome + Bootstrap CDNFree
Total$0.00

You just built a production app with enterprise DevOps — for $0.

You built a complete DevOps pipeline:

CodeCommitBuildTestDeployMonitorSelf-Heal

All with zero cost.

Resources

ResourceLink
.NET 8 Downloadhttps://dotnet.microsoft.com/download/dotnet/8.0
Azure Free Accounthttps://azure.microsoft.com/free/
Azure DevOpshttps://dev.azure.com
SQLite Browserhttps://sqlitebrowser.org
Bootstrap 5https://getbootstrap.com
Font Awesomehttps://fontawesome.com

This project is a microcosm of modern software delivery:

  • You automated the boring stuff → so you can focus on solving real problems.

  • You proved that enterprise-grade automation is accessible → even to students, freelancers, and indie devs.

  • You broke the myth → that “good DevOps costs money.”

  • You embraced the Microsoft stack → not because it’s the only option, but because it’s now the best free option.

This is what DevOps looks like in 2025:

One git commit → Global deployment → Zero human touch → Self-healing system