Cloud Quality Cloud Pricing

Your friendly guide to ASP.NET Web API

1) How to create a Web API in ASP.NET C#?

Short path: dotnet new webapi → edit → run.
 Now the full, practical steps (CLI + Visual Studio), examples for minimal API and controller-based API, and tips.

Quick start (CLI)

bash 

# create project
dotnet new webapi -n MyApi
cd MyApi

# run (development)
dotnet run
# default: https://localhost:5001

The template includes a sample WeatherForecast controller and Swagger out of the box.

csharp 

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();
app.UseSwagger(); app.UseSwaggerUI();

app.MapGet("/", () => "Hello from Minimal API!");
app.MapGet("/api/hello/{name}", (string name) => Results.Ok(new { Message = $"Hello {name}" }));

app.Run();
  • Minimal APIs are great for tiny services or learning.

Controller-based API (more structured)

Create Controllers/TodoController.cs:

csharp 

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class TodoController : ControllerBase
{
    private static readonly List<string> _items = new() { "Sample task" };

    [HttpGet]
    public IActionResult Get() => Ok(_items);

    [HttpPost]
    public IActionResult Create([FromBody] string item)
    {
        _items.Add(item);
        return CreatedAtAction(nameof(Get), item);
    }
}

In Program.cs ensure you have:

csharp 

builder.Services.AddControllers();
app.MapControllers();

Practical tips & best practices

  • Use async actions for I/O (Task<IActionResult>).
  • Use DTOs rather than raw domain models for public APIs.
  • Keep controllers thin — put business logic in services and inject via DI.
  • Add Swagger early for exploration (Swashbuckle.AspNetCore).

2) How to configure Swagger in ASP.NET Core Web API?

Swagger (Swashbuckle) documents your API and provides an interactive UI.

Install

bash 

dotnet add package Swashbuckle.AspNetCore

Basic configuration (Program.cs)

csharp

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "MyApi", Version = "v1" });
    // Optional: include XML comments
    // var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    // c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFile));
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c => {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyApi v1");
        c.RoutePrefix = "docs"; // serve at /docs
    });
}

Enable XML comments (helpful)

  • In project file (.csproj) add:
xml 

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
  • Enable the IncludeXmlComments shown above.

Add JWT auth UI to Swagger

csharp 

c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
    Description = "JWT Auth header: 'Bearer {token}'",
    Name = "Authorization",
    In = ParameterLocation.Header,
    Type = SecuritySchemeType.ApiKey
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
    {
        new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } },
        new string[] {}
    }
});

Customize UI

  • Change RoutePrefix, inject custom CSS/JS by providing an IndexStream, or hide models with DefaultModelsExpandDepth(-1).

3) How to return JSON in ASP.NET Core Web API?

ASP.NET Core returns JSON by default for POCO objects. You control serialization via System.Text.Json or Newtonsoft.Json.

Basic patterns

csharp 

[HttpGet]
public ActionResult<MyDto> Get() => new MyDto { Id = 1, Name = "x" };

[HttpGet("raw")]
public IActionResult Raw() => Ok(new { success = true, data = new[] { 1,2,3 } });
  • Ok(obj) sets status 200 and serializes obj to JSON (default application/json).

Using ActionResult<T>

ActionResult<T> lets you return typed responses and various status codes:

csharp 

public async Task<ActionResult<TodoDto>> Get(int id)
{
    var item = await _repo.FindAsync(id);
    if (item == null) return NotFound();
    return item; // automatically 200 with typed body
}

System.Text.Json customization

In Program.cs:

csharp 

builder.Services.AddControllers()
  .AddJsonOptions(opts => {
      opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
      opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
      opts.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
  });

Use Newtonsoft.Json if needed

bash 

dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson
csharp 

builder.Services.AddControllers().AddNewtonsoftJson(options => {
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});

Dates & timezone caution

  • Prefer ISO 8601; be explicit about UTC conversions.
  • Avoid serializing DateTime without Kind information — use DateTimeOffset if possible.

4) What is ASP.NET Web API?

Short conceptual answer: ASP.NET Web API is a framework for building HTTP services that can be consumed by browsers, mobile apps, and other services. In modern .NET it’s part of ASP.NET Core.

Key features

  • HTTP-first: routes map to HTTP verbs and URIs.
  • Content negotiation: automatically selects JSON/XML formatter based on Accept header.
  • Model binding & validation: bind route/query/body to .NET types and validate with attributes.
  • Filters & middleware: cross-cutting concerns (auth, logging, caching).
  • Extensible: plug in custom formatters, filters, DI services, OpenAPI docs, etc.

Historically “Web API” referred to the separate ASP.NET Web API (pre-Core). Today you build web APIs with ASP.NET Core.

5) How to create Web API in ASP.NET C# with database?

We’ll do an end-to-end example using EF Core, with model → DbContext → DI → controller → migrations.

Step 0 — create project

bash 

dotnet new webapi -n MyApiWithDb
cd MyApiWithDb

Step 1 — add EF Core packages

bash 

dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer       # or Npgsql for Postgres
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet tool install --global dotnet-ef   # if not installed

Step 2 — add model & DbContext

Models/TodoItem.cs

csharp 

public class TodoItem
{
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public bool Done { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

Data/AppDbContext.cs

csharp 

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}
    public DbSet<TodoItem> Todos { get; set; }
}

Step 3 — add connection string & register DbContext

appsettings.json:

json

"ConnectionStrings": {
  "DefaultConnection": "Server=.;Database=MyApiDb;Trusted_Connection=True;"
}

Program.cs:

csharp

builder.Services.AddDbContext<AppDbContext>(options =>
   options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builde.Services.AddControllers();

Step 4 — scaffold controller using DI

Controllers/TodoController.cs

csharp

[ApiController]
[Route("api/[controller]")]
public class TodoController : ControllerBase
{
    private readonly AppDbContext _db;
    public TodoController(AppDbContext db) => _db = db;

    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItem>>> Get() =>
        await _db.Todos.ToListAsync();

    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItem>> Get(int id)
    {
        var item = await _db.Todos.FindAsync(id);
        return item == null ? NotFound() : Ok(item);
    }

    [HttpPost]
    public async Task<ActionResult<TodoItem>> Create(TodoItem input)
    {
        _db.Todos.Add(input);
        await _db.SaveChangesAsync();
        return CreatedAtAction(nameof(Get), new { id = input.Id }, input);
    }
}

Step 5 — migrations & database update

bash 

dotnet ef migrations add InitialCreate
dotnet ef database update

Best practices

  • Use DTOs for public API to avoid exposing internal schema.
  • Use AsNoTracking() for read queries where no change tracking needed.
  • Centralize data access via repository/service layer if complexity grows.
  • Use transactions for multi-step writes.

6) How to send email in ASP.NET Web API?

Use MailKit (modern, secure, async). Avoid System.Net.Mail.SmtpClient for new development.

Install MailKit

bash 

dotnet add package MailKit

Example service

Services/EmailService.cs:

csharp

using MailKit.Net.Smtp;
using MimeKit;

public class EmailService
{
    private readonly IConfiguration _config;
    public EmailService(IConfiguration config) => _config = config;

    public async Task SendEmailAsync(string to, string subject, string bodyHtml)
    {
        var email = new MimeMessage();
        email.From.Add(MailboxAddress.Parse(_config["Email:From"]));
        email.To.Add(MailboxAddress.Parse(to));
        email.Subject = subject;
        email.Body = new TextPart("html") { Text = bodyHtml };

        using var smtp = new SmtpClient();
        await smtp.ConnectAsync(_config["Email:SmtpHost"], int.Parse(_config["Email:SmtpPort"]), MailKit.Security.SecureSocketOptions.StartTls);
        if (!string.IsNullOrEmpty(_config["Email:Username"]))
            await smtp.AuthenticateAsync(_config["Email:Username"], _config["Email:Password"]);
        await smtp.SendAsync(email);
        await smtp.DisconnectAsync(true);
    }
}

Register in DI:

csharp

builder.Services.AddTransient<EmailService>();

Configuration (appsettings.json):

json

"Email": {
  "From": "[email protected]",
  "SmtpHost": "smtp.yourhost.com",
  "SmtpPort": "587",
  "Username": "smtp-user",
  "Password": "smtp-password"
}

Security & production notes

  • Never store SMTP credentials in source control. Use environment variables or Secret Manager (dotnet user-secrets) in development and a secrets store (KeyVault) in production.
  • For Gmail/Workspace use OAuth2 or App Passwords (2FA requirement).
  • Send emails asynchronously (non-blocking) and protect against injection (sanitize inputs if you build subject/body from user input).

7) How to deploy ASP.NET Core Web API in IIS? — step by step

This is a common pain point — follow these steps exactly.

Prerequisites on server

  • Windows Server with IIS installed.
  • Install the .NET Core Hosting Bundle (matching your runtime: .NET 6/7/8). This installs the ASP.NET Core Module (ANCM) that proxies IIS → Kestrel.
  • Create a Windows user for the App Pool (optional but recommended).

Publishing from dev

From command line:

bash 

dotnet publish -c Release -o ./publish

Or in Visual Studio: Publish → Folder Profile → Pick target folder.

Copy files to the server

  • Copy contents of the publish folder to the server path (e.g., C:\inetpub\wwwroot\MyApi).

IIS site configuration

  1. Open IIS Manager → Sites → Add Website.
  2. Site name: MyApi.
  3.  Physical pathC:\inetpub\wwwroot\MyApi.
  4.  Binding: choose hostname / port; for production use HTTPS (bind certificate).
  5. Application Pool:
    • Create a new App Pool or use existing.
    • Managed pipeline mode: Integrated.
    • .NET CLR versionNo Managed Code (Kestrel handles .NET runtime).
    • Set identity to your service account (if you need network resources).
  6. Ensure web.config exists in publish folder (it’s generated by the SDK). This configures the ASP.NET Core Module.
  7. Give the App Pool identity Read/Write access to the folder if logs or uploads are used.

Environment variables & connection strings

  • Set ASPNETCORE_ENVIRONMENT to Production for production behaviour.
  • Configure connection strings and secrets in IIS Configuration Editor or use environment variables. Avoid appsettings with secrets checked into source.

Logs & troubleshooting

  • If the site fails, check:
    • Windows Event Viewer (Application logs) for ANCM errors.
    • stdoutLog (enable temporarily in web.config by setting stdoutLogEnabled=true and stdoutLogFile path).
    • Ensure Hosting Bundle installed and App Pool is set to No Managed Code.

HTTPS & certificates

  • Bind an SSL certificate in IIS (Bindings → Add → Type = https).
  • Use HSTS and redirect HTTP → HTTPS in your app via app.UseHttpsRedirection().

8) How to call Web API POST method from ASP.NET C#?

Use HttpClient. Prefer IHttpClientFactory (built-in) to avoid socket exhaustion and to support DI and resilience policies.

Register IHttpClientFactory

csharp

builder.Services.AddHttpClient("MyApi", c => {
    c.BaseAddress = new Uri("https://api.example.com/");
    c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
});

Usage example (consume POST)

public class MyService
{
    private readonly IHttpClientFactory _httpFactory;
    public MyService(IHttpClientFactory httpFactory) => _httpFactory = httpFactory;

    public async Task<TodoItem?> CreateTodoAsync(TodoCreateDto dto, CancellationToken ct = default)
    {
        var client = _httpFactory.CreateClient("MyApi");
        var response = await client.PostAsJsonAsync("api/todo", dto, ct);
        if (!response.IsSuccessStatusCode)
        {
            // read error, log, throw / return null
            var error = await response.Content.ReadAsStringAsync();
            throw new Exception($"API Error: {response.StatusCode} - {error}");
        }
        return await response.Content.ReadFromJsonAsync<TodoItem>(cancellationToken: ct);
    }
}

Notes

  • Use PostAsJsonAsync and ReadFromJsonAsync (System.Net.Http.Json) for convenience.
  • Include CancellationToken for timeouts.
  • Configure timeouts on HttpClient or use policies (Polly) for retries/backoff.

9) How to integrate Web API in ASP.NET MVC?

Two common integration scenarios:

A — Add Web API endpoints inside an existing ASP.NET MVC project

  • In the same project add API controllers ([ApiController]) and register controllers:
csharp 

builder.Services.AddControllersWithViews(); // supports both MVC & API
app.MapControllerRoute("default","{controller=Home}/{action=Index}/{id?}");
app.MapControllers(); // API endpoints

B — Consume an external Web API from MVC (server-side)

In your MVC controller:

csharp 

public class HomeController : Controller
{
    private readonly IHttpClientFactory _httpFactory;
    public HomeController(IHttpClientFactory httpFactory) => _httpFactory = httpFactory;

    public async Task<IActionResult> Index()
    {
        var client = _httpFactory.CreateClient("MyApi");
        var items = await client.GetFromJsonAsync<List<TodoItem>>("api/todo");
        return View(items);
    }
}
  • Render data in Razor views using model binding.

Best practice

  • Don’t block threads in MVC — use async all the way.
  • Cache API responses where appropriate (MemoryCache / Redis).
  • Handle API failures gracefully when rendering views (fallback UI, friendly messages)

10) How to add migration in ASP.NET Core Web API?

This describes creating EF Core migrations and common gotchas.

Install tools

bash 

dotnet tool install --global dotnet-ef   # if not installed
dotnet add package Microsoft.EntityFrameworkCore.Design

Typical workflow

  1. Create/modify DbContext and models.
  2. Add migration:
bash 

dotnet ef migrations add AddTodos

3. Apply migration:

bash 

dotnet ef database update

Using Package Manager Console (Visual Studio)

ps 

Add-Migration AddTodos
Update-Database

If you get “No executable found” or design-time errors

  • Ensure your startup project is the project that contains Program.cs or set —startupproject:
bash 

dotnet ef migrations add AddTodos --startup-project ../MyApi
  • If EF cannot create your DbContext at design time, implement IDesignTimeDbContextFactory<TContext>:
csharp 

public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
{
    public AppDbContext CreateDbContext(string[] args)
    {
        var options = new DbContextOptionsBuilder<AppDbContext>();
        options.UseSqlServer("Server=.;Database=MyApiDb;Trusted_Connection=True;");
        return new AppDbContext(options.Options);
    }
}

This helps tooling create the context without running your app code.

Best practices

  • Keep migrations small and focused.
  • Test migrations on a staging DB before applying to production.
  • Commit migrations to source control.
  • Use scripted deployments with transactional migration steps where possible.

Genadi Petkov

Genadi Petkov has been an active force in the web hosting industry since 2008. As CTO at FreshRoastedHosting.com for over a decade, and founder of TheHost.BG through his company IT Factory, he combines hands-on technical expertise with strategic insight. Genadi has also collaborated with Wall Street venture capital-backed hosting ventures, bringing innovative solutions to life. Loves breaking down technical challenges into clear, practical insights—and when he's offline, you might find him tinkering with new tech or dreaming up the next big hosting innovation.