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 + Create β†’ Create

⏳ 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 Pipelines β†’ New 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 Settings β†’ Service Connections

  2. Click New service connection β†’ Azure 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 β†’ Monitoring β†’ Health 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:

Code β†’ Commit β†’ Build β†’ Test β†’ Deploy β†’ Monitor β†’ Self-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