Md Mominul Islam | Software and Data Enginnering | SQL Server, .NET, Power BI, Azure Blog

while(!(succeed=try()));

LinkedIn Portfolio Banner

Latest

Home Top Ad

Responsive Ads Here

Post Top Ad

Responsive Ads Here

Thursday, September 4, 2025

Ultimate ASP.NET Full Course: Module 5 - RESTful APIs, Web Services & Integrations

 

Table of Contents

  1. Module 5: RESTful APIs, Web Services & Integrations

    • 1.1 REST Principles

      • Resources, Verbs, Status Codes

    • 1.2 Web API in ASP.NET Core

      • Controllers vs Minimal APIs

    • 1.3 JSON/XML Serialization

      • System.Text.Json

    • 1.4 Validation

      • Data Annotations, Fluent Validation

    • 1.5 API Documentation

      • Swagger/OpenAPI Integration

    • 1.6 Consuming APIs

      • HttpClient/IHttpClientFactory

    • 1.7 Advanced Services

      • gRPC for High-Performance Communication

      • GraphQL (HotChocolate)

      • OData APIs

    • 1.8 Legacy Services

      • ASMX, WCF → Migration Strategies

    • 1.9 Lab: Build a Product Catalog REST API with Swagger + Postman Tests + Console Consumer

      • Real-Life Example: E-Commerce Product Management

      • Step-by-Step Code Implementation

      • Best Practices, Exception Handling, Pros/Cons, Alternatives


Introduction

Welcome to Module 5 of the Ultimate ASP.NET Full Course (2025 Edition)! This module focuses on building RESTful APIs and web services in ASP.NET Core, essential for powering modern applications like mobile apps, SPAs, and microservices. We'll cover REST principles, creating APIs with controllers and minimal setups, serialization, validation, documentation, consumption, and advanced protocols like gRPC and GraphQL. We'll also discuss migrating legacy services.

Using real-life examples, such as an e-commerce product catalog where clients query and manage inventory, we'll make concepts practical and data-oriented. This guide is step-by-step, code-heavy, and user-friendly, with best practices, exception handling, pros/cons, and alternatives. The lab will have you building a complete REST API with Swagger for docs, Postman for testing, and a console app consumer.

By the end, you'll be proficient in creating scalable, integrable services. Let's start with REST fundamentals and build toward advanced integrations!


1.1 REST Principles

Resources, Verbs, Status Codes

REST (Representational State Transfer) is an architectural style for designing networked applications, emphasizing statelessness, cacheability, and uniform interfaces.

  • Resources: Entities identified by URIs, e.g., /products/123 for a specific product. Resources are nouns, and operations are performed via HTTP methods.

  • Verbs (HTTP Methods):

    • GET: Retrieve resources (idempotent, safe).

    • POST: Create new resources.

    • PUT: Update/replace existing resources (idempotent).

    • PATCH: Partial updates.

    • DELETE: Remove resources (idempotent).

    • OPTIONS/HEAD: Metadata or preflight.

  • Status Codes: HTTP responses indicating outcomes.

    • 2xx: Success (200 OK, 201 Created, 204 No Content).

    • 3xx: Redirection (301 Moved Permanently).

    • 4xx: Client errors (400 Bad Request, 401 Unauthorized, 404 Not Found).

    • 5xx: Server errors (500 Internal Server Error).

Real-Life Analogy: REST is like a library system—resources are books (URIs as shelf numbers), verbs are actions (borrow/return), status codes are checkout responses (success/failure).

Real-Life Example: In an e-commerce API, GET /products lists items, POST /products adds a new one, PUT /products/123 updates price, DELETE removes it. Status 201 for creation, 404 if not found.

Best Practices:

  • Use plural nouns for collections (/products).

  • Version APIs (/v1/products).

  • Support HATEOAS (Hypermedia as the Engine of Application State) for discoverability.

Exception Handling:

  • Return meaningful errors, e.g., ProblemDetails for 4xx/5xx.

    {
      "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
      "title": "Bad Request",
      "status": 400,
      "detail": "Invalid input"
    }

Pros:

  • Stateless, scalable.

  • Standard HTTP leverages existing infrastructure.

Cons:

  • Over-fetching/under-fetching data.

  • Not ideal for real-time.

Alternatives:

  • SOAP: XML-based, more rigid.

  • GraphQL: Query-based, flexible.

Expanding on REST: Resources can be hierarchical, e.g., /orders/456/items. Verbs ensure idempotency (repeatable without side effects). Status codes with custom messages enhance debugging. In .NET 9, ASP.NET supports automatic ProblemDetails. Realistics: Amazon API uses REST for scalability. Pros: Cacheable with ETags; cons: Chatty for complex queries.

For advanced: Implement rate limiting (429 Too Many Requests), pagination for large collections.


1.2 Web API in ASP.NET Core

Controllers vs Minimal APIs

ASP.NET Core provides flexible ways to build APIs: traditional controllers or lightweight minimal APIs.

  • Controllers: Class-based, feature-rich for complex logic.

    • Example: ProductsController.cs

      [ApiController]
      [Route("api/[controller]")]
      public class ProductsController : ControllerBase
      {
          private readonly IProductService _service;
      
          public ProductsController(IProductService service)
          {
              _service = service;
          }
      
          [HttpGet]
          public async Task<ActionResult<IEnumerable<Product>>> GetAll()
          {
              return Ok(await _service.GetAllAsync());
          }
      
          [HttpGet("{id}")]
          public async Task<ActionResult<Product>> Get(int id)
          {
              var product = await _service.GetByIdAsync(id);
              if (product == null) return NotFound();
              return Ok(product);
          }
      }
  • Minimal APIs: Top-level statements for simple endpoints ( .NET 6+).

    • Example: In Program.cs

      app.MapGet("/api/products", async (IProductService service) => await service.GetAllAsync());
      app.MapGet("/api/products/{id}", async (int id, IProductService service) =>
      {
          var product = await service.GetByIdAsync(id);
          return product != null ? Results.Ok(product) : Results.NotFound();
      });

Real-Life Analogy: Controllers are full kitchens with appliances, minimal APIs are food trucks—quick setup.

Real-Life Example: E-commerce uses controllers for product endpoints with auth/filters, minimal for health checks.

Best Practices:

  • Use [ApiController] for auto-validation.

  • DI for services in both.

Exception Handling:

  • Global filters or middleware for unhandled exceptions.

Pros (Controllers):

  • Organized for large apps.

  • Built-in filters/attributes.

Cons:

  • Boilerplate.

Pros (Minimal):

  • Concise, fast prototyping.

Cons:

  • Less structure.

Alternatives:

  • FastAPI (Python): Similar minimal style.

Details: .NET 9 enhances minimal APIs with parameter binding. Hybrid: Use both in one app.


1.3 JSON/XML Serialization

System.Text.Json

Serialization converts objects to JSON/XML for API responses/requests.

  • System.Text.Json: Default in ASP.NET Core, fast and efficient.

    • Configuration: In Program.cs

      builder.Services.AddControllers().AddJsonOptions(options =>
      {
          options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
          options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
      });
    • Example: Custom converter for enums.

      public class EnumStringConverter<T> : JsonConverter<T> where T : struct, Enum
      {
          public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
          {
              return Enum.TryParse(reader.GetString(), true, out T value) ? value : default;
          }
      
          public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
          {
              writer.WriteStringValue(value.ToString().ToLower());
          }
      }
  • XML: Use AddXmlSerializerFormatters() for support.

Real-Life Analogy: Serialization is packing luggage—JSON is compact carry-on, XML structured suitcase.

Real-Life Example: Product API serializes Product objects to JSON for mobile apps.

Best Practices:

  • Use camelCase for interoperability.

  • Ignore cycles with ReferenceHandler.Preserve.

Exception Handling:

  • JsonException for invalid data.

Pros:

  • Built-in, performant.

Cons:

  • Less features than Json.NET (migrate if needed).

Alternatives:

  • Newtonsoft.Json: More customizable.

Expand: .NET 9 adds source generators for faster serialization.


1.4 Validation

Data Annotations, Fluent Validation

Ensure input data integrity.

  • Data Annotations: Attributes on models.

    • Example:

      public class Product
      {
          [Required]
          [StringLength(100)]
          public string Name { get; set; } = string.Empty;
      
          [Range(0.01, double.MaxValue)]
          public decimal Price { get; set; }
      }
  • Fluent Validation: NuGet FluentValidation.AspNetCore, rule-based.

    • Example:

      public class ProductValidator : AbstractValidator<Product>
      {
          public ProductValidator()
          {
              RuleFor(p => p.Name).NotEmpty().MaximumLength(100);
              RuleFor(p => p.Price).GreaterThan(0);
          }
      }
    • Register: builder.Services.AddFluentValidationAutoValidation();

Real-Life Analogy: Validation is airport security—annotations quick scans, fluent detailed checks.

Real-Life Example: Product creation validates name/price to prevent invalid inventory.

Best Practices:

  • Client-side too with jQuery Validation.

  • Custom validators for business rules.

Exception Handling:

  • Return 400 with ModelState errors.

Pros:

  • Built-in model binding.

Cons:

  • Annotations couple validation to models.

Alternatives:

  • Manual checks: In code.


1.5 API Documentation

Swagger/OpenAPI Integration

Document APIs for consumers.

  • Swagger/OpenAPI: NuGet Swashbuckle.AspNetCore.

    • Setup:

      builder.Services.AddSwaggerGen(c =>
      {
          c.SwaggerDoc("v1", new OpenApiInfo { Title = "Product API", Version = "v1" });
      });
      app.UseSwagger();
      app.UseSwaggerUI();
    • Access /swagger.

Real-Life Analogy: Swagger is a menu—describes offerings.

Real-Life Example: E-commerce API docs for third-party integrations.

Best Practices:

  • Add XML comments for descriptions.

  • Secure with auth.

Exception Handling:

  • N/A, but test endpoints.

Pros:

  • Interactive UI.

Cons:

  • Overhead in small APIs.

Alternatives:

  • NSwag: Similar.


1.6 Consuming APIs

HttpClient/IHttpClientFactory

Call external APIs.

  • HttpClient: Basic, but avoid direct instantiation.

  • IHttpClientFactory: Managed lifetimes.

    • Setup: builder.Services.AddHttpClient();

    • Example:

      public class ProductConsumer
      {
          private readonly HttpClient _client;
      
          public ProductConsumer(IHttpClientFactory factory)
          {
              _client = factory.CreateClient();
          }
      
          public async Task<Product?> GetProductAsync(int id)
          {
              var response = await _client.GetAsync($"https://api.example.com/products/{id}");
              if (response.IsSuccessStatusCode)
              {
                  return await response.Content.ReadFromJsonAsync<Product>();
              }
              return null;
          }
      }

Real-Life Analogy: Consuming is ordering takeout—factory manages delivery.

Real-Life Example: Console app consumes product API for reporting.

Best Practices:

  • Typed clients for named APIs.

  • Retry with Polly.

Exception Handling:

  • HttpRequestException.

Pros:

  • Pooled connections.

Cons:

  • DNS issues without factory.

Alternatives:

  • Refit: Interface-based.


1.7 Advanced Services

gRPC for High-Performance Communication

gRPC uses Protocol Buffers for efficient RPC.

  • Setup: NuGet Grpc.AspNetCore, define .proto.

    service ProductService {
      rpc GetProduct (ProductRequest) returns (ProductResponse);
    }
    • Server: Implement service.

    • Client: Generate with tools.

GraphQL (HotChocolate): Query language.

  • NuGet HotChocolate.AspNetCore.

  • Schema: Define types/resolvers.

OData APIs: Queryable endpoints.

  • NuGet Microsoft.AspNetCore.OData.

  • Enable in controllers.

Real-Life Example: Microservices use gRPC for internal comms, GraphQL for flexible queries.

Pros/Cons: gRPC fast but binary; GraphQL flexible but complex.

Alternatives: WebSockets for real-time.


1.8 Legacy Services

ASMX, WCF → Migration Strategies

Migrate old services to modern.

  • ASMX: SOAP web services; migrate to Web API.

  • WCF: Use CoreWCF or rewrite as gRPC/API.

  • Strategies: Strangler pattern, run side-by-side.

Real-Life Example: Legacy inventory WCF to REST API.

Pros: Modernization improves perf.

Cons: Breaking changes.

Alternatives: Keep legacy if stable.


1.9 Lab: Build a Product Catalog REST API with Swagger + Postman Tests + Console Consumer

Real-Life Example: E-Commerce Product Management

Build API for products, document with Swagger, test in Postman, consume in console.

Step-by-Step

  1. Project: dotnet new webapi -n ProductApi

  2. Models/Service/DbContext (use in-memory for simplicity).

  3. Controller with CRUD.

  4. Add Swagger.

  5. Postman: Collections for tests.

  6. Console: .NET app with HttpClient.

Code Example

Product.cs

public class Product
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
}

ProductsController.cs

[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
    private static List<Product> _products = new List<Product> { new Product { Id = 1, Name = "Laptop", Price = 999.99m } };

    [HttpGet]
    public IEnumerable<Product> Get() => _products;

    [HttpGet("{id}")]
    public ActionResult<Product> Get(int id)
    {
        var product = _products.FirstOrDefault(p => p.Id == id);
        return product != null ? Ok(product) : NotFound();
    }

    [HttpPost]
    public ActionResult<Product> Post([FromBody] Product product)
    {
        if (!ModelState.IsValid) return BadRequest(ModelState);
        product.Id = _products.Count + 1;
        _products.Add(product);
        return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
    }

    // Put, Delete similar
}

Program.cs

builder.Services.AddSwaggerGen();
app.UseSwagger();
app.UseSwaggerUI();

Console Consumer Program.cs

using System.Net.Http.Json;

var client = new HttpClient { BaseAddress = new Uri("http://localhost:5000/") };

var products = await client.GetFromJsonAsync<Product[]>("api/products");
Console.WriteLine(string.Join("\n", products?.Select(p => p.Name) ?? Array.Empty<string>()));

How to Run

  • API: dotnet run, /swagger.

  • Postman: Import collection, test endpoints.

  • Console: dotnet run.

Explanation/Best Practices/etc.

  • Detailed as per pattern.

No comments:

Post a Comment

Thanks for your valuable comment...........
Md. Mominul Islam

Post Bottom Ad

Responsive Ads Here