ASP.NET Core Web API and RESTful Principles

1. Understanding Web API

ASP.NET Core Web API allows developers to create HTTP services that can be consumed by a variety of clients, including browsers, mobile applications, and other services. Web APIs are lightweight, stateless, and can be consumed by any device capable of making HTTP requests.

Key Concepts:

  • Stateless Communication: Each request from a client must contain all the information needed for the server to process the request.
  • JSON/XML Format: ASP.NET Core Web API primarily communicates using JSON, but it can also support other formats like XML.

2. RESTful Architecture

REST (Representational State Transfer) is an architectural style that defines constraints and principles to create web services.

RESTful Principles:

  • Client-Server Architecture: Separation of concerns between the client and server.
  • Statelessness: Every interaction between the client and server is independent.
  • Cacheability: Responses must explicitly indicate whether caching is allowed.
  • Uniform Interface: All requests are made to a single, well-defined interface using standard HTTP methods.
  • Resource Identification: Resources (data) are identified using URIs.

3. RESTful Constraints in Web API

Resources and URIs:

GET /api/products/12345

HTTP Methods in REST:

  • GET: Retrieve data.
  • POST: Create a new resource.
  • PUT: Update an existing resource.
  • DELETE: Remove a resource.

4. Implementing a Simple Web API with REST Principles

Step 1: Create a New ASP.NET Core Web API Project

dotnet new webapi -n ProductApi

Step 2: Define the Product Model

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Description { get; set; }
}

Step 3: Create a ProductsController

[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    private static List<Product> products = new List<Product>
    {
        new Product { Id = 1, Name = "Laptop", Price = 999.99m, Description = "A high-performance laptop" },
        new Product { Id = 2, Name = "Smartphone", Price = 499.99m, Description = "A flagship smartphone" },
    };
 
    // GET: api/products
    [HttpGet]
    public ActionResult<IEnumerable<Product>> GetProducts()
    {
        return products;
    }
 
    // GET: api/products/1
    [HttpGet("{id}")]
    public ActionResult<Product> GetProduct(int id)
    {
        var product = products.FirstOrDefault(p => p.Id == id);
        if (product == null)
            return NotFound();
        return product;
    }
 
    // POST: api/products
    [HttpPost]
    public ActionResult<Product> CreateProduct(Product newProduct)
    {
        newProduct.Id = products.Max(p => p.Id) + 1;
        products.Add(newProduct);
        return CreatedAtAction(nameof(GetProduct), new { id = newProduct.Id }, newProduct);
    }
 
    // PUT: api/products/1
    [HttpPut("{id}")]
    public IActionResult UpdateProduct(int id, Product updatedProduct)
    {
        var product = products.FirstOrDefault(p => p.Id == id);
        if (product == null)
            return NotFound();
 
        product.Name = updatedProduct.Name;
        product.Price = updatedProduct.Price;
        product.Description = updatedProduct.Description;
 
        return NoContent(); // 204 No Content
    }
 
    // DELETE: api/products/1
    [HttpDelete("{id}")]
    public IActionResult DeleteProduct(int id)
    {
        var product = products.FirstOrDefault(p => p.Id == id);
        if (product == null)
            return NotFound();
 
        products.Remove(product);
        return NoContent();
    }
}

5. HTTP Status Codes

Status CodeMeaning
200 OKThe request was successful
201 CreatedA resource was successfully created
204 No ContentSuccessful, but no content to return
400 Bad RequestThe request was malformed or invalid
404 Not FoundThe resource was not found

Web API Controllers

In ASP.NET Core, Web API Controllers serve as the backbone for handling HTTP requests.

1. What is a Web API Controller?

A Web API controller is a class that handles HTTP requests and generates appropriate HTTP responses. It inherits from ControllerBase and uses attributes to define routing, HTTP methods, and input/output handling.

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    // Example action methods
}
  • [ApiController]: Makes it easier to build a Web API by handling automatic model state validation.
  • [Route]: Defines the URI path for the controller.

2. Action Methods in Web API Controllers

Attribute Routing:

[HttpGet("search/{name}")]
public ActionResult<IEnumerable<Product>> SearchProducts(string name)
{
    var matchedProducts = products.Where(p => p.Name.Contains(name, StringComparison.OrdinalIgnoreCase)).ToList();
    if (!matchedProducts.Any())
        return NotFound();
    return Ok(matchedProducts);
}

3. Binding Data to Controllers

ASP.NET Core provides several ways to bind incoming HTTP data:

  • From Route: Bind data from route parameters.
  • From Query: Bind data from query strings.
  • From Body: Bind data from the request body (usually JSON).
[HttpGet("{id}")]
public ActionResult<Product> GetProduct(int id, [FromQuery] string search)
{
    // logic...
}

4. Validation in Web API Controllers

public class Product
{
    public int Id { get; set; }
 
    [Required(ErrorMessage = "Name is required.")]
    [MaxLength(50)]
    public string Name { get; set; }
 
    [Range(0.01, 9999.99, ErrorMessage = "Price must be between 0.01 and 9999.99.")]
    public decimal Price { get; set; }
 
    [StringLength(200)]
    public string Description { get; set; }
}

5. Dependency Injection in Web API Controllers

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;
 
    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }
 
    [HttpGet]
    public ActionResult<IEnumerable<Product>> GetProducts()
    {
        return Ok(_productService.GetProducts());
    }
}

API Controllers vs. MVC Controllers

1. Overview

FeatureAPI ControllersMVC Controllers
Base ClassControllerBaseController (inherits ControllerBase)
Return TypesJSON/XML dataHTML views
View SupportNoYes (Razor views)
[ApiController]YesNo
PurposeRESTful servicesTraditional web apps

2. ControllerBase vs. Controller

  • ControllerBase: For API controllers. Focused on returning data (JSON, XML). No view support.
  • Controller: For MVC controllers. Inherits all ControllerBase features plus view methods.

3. Return Types

In API Controllers:

[HttpGet]
public ActionResult<IEnumerable<Product>> GetProducts()
{
    return Ok(new List<Product>());
}

In MVC Controllers:

public IActionResult Index()
{
    return View(); // Returns an HTML view
}

4. Automatic Model Validation

In API controllers with [ApiController], model validation is automatic. In MVC controllers, you manually check ModelState.IsValid.


Entity Framework Core with Web API

1. Setting Up DbContext

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

2. Configure Connection String

{
    "ConnectionStrings": {
        "DefaultConnection": "Server=localhost;Database=ecommerce_db;Trusted_Connection=True;"
    }
}

3. Register DbContext in Program.cs

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

4. CRUD Operations

Create (POST):

[HttpPost]
public async Task<ActionResult<Product>> CreateProduct([FromBody] Product product)
{
    _context.Products.Add(product);
    await _context.SaveChangesAsync();
    return CreatedAtAction(nameof(GetProductById), new { id = product.Id }, product);
}

Read (GET) All:

[HttpGet]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
{
    var products = await _context.Products.ToListAsync();
    return Ok(products);
}

Read (GET) by ID:

[HttpGet("{id}")]
public async Task<ActionResult<Product>> GetProductById(int id)
{
    var product = await _context.Products.FindAsync(id);
    if (product == null)
        return NotFound();
    return Ok(product);
}

Update (PUT):

[HttpPut("{id}")]
public async Task<IActionResult> UpdateProduct(int id, [FromBody] Product product)
{
    if (id != product.Id)
        return BadRequest();
 
    _context.Entry(product).State = EntityState.Modified;
    await _context.SaveChangesAsync();
 
    return NoContent();
}

Delete (DELETE):

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
    var product = await _context.Products.FindAsync(id);
    if (product == null)
        return NotFound();
 
    _context.Products.Remove(product);
    await _context.SaveChangesAsync();
 
    return NoContent();
}

5. Migration: Creating the Database

dotnet ef migrations add InitialCreate
dotnet ef database update

Different Return Types of Web API Action Methods

Return TypeDescriptionUse Case
VoidReturns nothingRare in Web APIs
Primitive Types (int, string, bool)Basic dataSimple ID, message
IEnumerable<T> / List<T>CollectionsLists of items
Object (T)Single entitySingle resource
Task / Task<T>Async operationsI/O-bound tasks
ActionResult<T>Data + status codesFlexible responses
IActionResultFull control over responseAny HTTP response
FileResultFile downloadsPDFs, images, CSVs
Custom Response WrappersConsistent response formatStructured API responses

ControllerBase

ControllerBase is a foundational class in ASP.NET Core MVC and Web API applications.

Key Features:

  • Action methods for handling HTTP requests
  • Response types for returning various HTTP responses
  • Dependency injection support
  • Model binding and validation

Key Methods:

  • Ok(): Returns 200 OK with optional content.
  • CreatedAtAction(): Returns 201 Created.
  • NotFound(): Returns 404 Not Found.
  • BadRequest(): Returns 400 Bad Request.
  • NoContent(): Returns 204 No Content.

Key Points to Remember

  1. RESTful Principles: Focus on resource-based URIs, stateless communication, and uniform interfaces.
  2. Web API Controllers: Inherit from ControllerBase, handle HTTP requests, return data responses.
  3. API vs MVC Controllers: API controllers handle data without views; MVC controllers manage views.
  4. Entity Framework Core: ORM for database operations with CRUD support.
  5. Return Types: IActionResult provides flexibility; ActionResult<T> combines data and status codes.
  6. ControllerBase: Core class for Web API controllers, focusing on HTTP request handling.