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

Wednesday, August 20, 2025

ASP.NET Core Complete Course: Module 13 – Exploring the Latest Features in ASP.NET Core for Modern Web Development



Welcome to Module 13 of our ASP.NET Core Complete Course: Beginner to Advanced Guide for Modern Web Development. In this module, we dive into the latest features in ASP.NET Core, focusing on .NET 7/8 new features, Minimal APIs vs. Full MVC, Blazor Server vs. Blazor WebAssembly, gRPC in ASP.NET Core, and Microservices with Dapper. This comprehensive, SEO-friendly guide is packed with detailed explanations, practical examples, pros and cons, alternatives, and best practices for security, performance, and error handling. We’ll also build a real-life e-commerce platform to demonstrate these concepts in action.

Whether you're a beginner or an advanced developer, this blog post will equip you with the knowledge to leverage the latest ASP.NET Core features for building modern, scalable web applications. Let’s explore the cutting-edge advancements in ASP.NET Core and how they can transform your development workflow!


Table of Contents

  1. Introduction to the Latest Features in ASP.NET Core

  2. .NET 7/8 New Features Overview

    • What’s New in .NET 7 and 8?

    • Pros, Cons, and Alternatives

    • Example: Using New Features in .NET 8

  3. Minimal APIs vs. Full MVC

    • Understanding Minimal APIs and Full MVC

    • Pros, Cons, and Alternatives

    • Example: Building APIs with Minimal APIs and MVC

  4. Blazor Server vs. Blazor WebAssembly

    • Understanding Blazor Hosting Models

    • Pros, Cons, and Alternatives

    • Example: Building a Blazor App with Server and WebAssembly

  5. gRPC in ASP.NET Core

    • What is gRPC?

    • Pros, Cons, and Alternatives

    • Example: Implementing a gRPC Service

  6. Microservices with Dapper

    • What is Dapper?

    • Pros, Cons, and Alternatives

    • Example: Building a Microservice with Dapper

  7. Best Practices for ASP.NET Core Development

    • Security Best Practices

    • Performance Best Practices

    • Error Handling Best Practices

  8. Real-Life Example: Building an E-Commerce Platform

  9. Conclusion

  10. FAQs


Introduction to the Latest Features in ASP.NET Core

ASP.NET Core continues to evolve as a leading framework for building modern, high-performance web applications. With the release of .NET 7 and .NET 8, Microsoft introduced groundbreaking features that enhance performance, developer productivity, and flexibility. This module explores these advancements, including Minimal APIs, Blazor enhancements, gRPC, and Dapper for microservices, providing you with the tools to build scalable, efficient, and interactive web applications.

In Module 13, we’ll cover:

  • .NET 7/8 New Features: Key enhancements for performance and developer experience.

  • Minimal APIs vs. Full MVC: Comparing lightweight and traditional API development.

  • Blazor Server vs. Blazor WebAssembly: Choosing the right hosting model for interactive UIs.

  • gRPC in ASP.NET Core: Building high-performance RPC services.

  • Microservices with Dapper: Simplifying data access in microservices.

This blog post includes detailed explanations, practical examples, pros and cons, alternatives, and best practices for security, performance, and error handling. We’ll also implement a real-life e-commerce platform to demonstrate these features. Let’s dive in!


.NET 7/8 New Features Overview

What’s New in .NET 7 and 8?

.NET 7 (released November 2022) and .NET 8 (released November 2023) introduced significant improvements to ASP.NET Core, focusing on performance, cloud-native development, and developer productivity. Key features include:

.NET 7 Highlights

  • Native AOT (Ahead-of-Time Compilation): Compiles apps to native code, reducing startup time and memory usage.

  • Minimal APIs Enhancements: Simplified endpoint definitions and improved form binding.

  • Blazor Improvements: Enhanced prerendering and integration with MVC/Razor Pages.

  • Rate Limiting: Built-in middleware for controlling request rates.

  • Performance: Up to 20% faster than .NET 6 on benchmarks like TechEmpower.

.NET 8 Highlights

  • Blazor Web App Template: Unified template for Server and WebAssembly with static server-side rendering (SSR), streaming rendering, and per-component interactivity.

  • Jiterpreter: Partial JIT compilation for Blazor WebAssembly, improving runtime performance.

  • Webcil Packaging: Web-friendly .NET assembly format for Blazor WebAssembly, avoiding .dll issues.

  • Anti-Forgery Middleware: Unified token validation across Blazor, Minimal APIs, and MVC.

  • SignalR Stateful Reconnect: Reduces downtime during network interruptions.

  • Keyed DI Services: Supports dependency injection with named services.

  • Performance: 18% faster on TechEmpower JSON benchmark and 24% faster on Fortunes benchmark compared to .NET 7.

Pros, Cons, and Alternatives for .NET 7/8

Pros

  • Performance: Significant improvements in request processing and memory usage.

  • Cross-Platform: Runs on Windows, macOS, and Linux, ideal for cloud and containers.

  • Blazor Enhancements: Unified model simplifies full-stack development.

  • Native AOT: Reduces app size and startup time for cloud-native apps.

  • Developer Productivity: Minimal APIs and improved tooling reduce boilerplate code.

Cons

  • Learning Curve: New features like Native AOT and Blazor Web App require adaptation.

  • Limited AOT Support: Minimal APIs have partial support for features like form file uploads.

  • Breaking Changes: Upgrading from .NET 7 to 8 may require code changes.

  • Dependency Management: Blazor WebAssembly requires careful dependency trimming.

  • Vendor Lock-In: Some features are tightly coupled to Azure.

Alternatives

  • Node.js with Express: Lightweight, JavaScript-based framework for APIs.

  • Spring Boot (Java): Robust framework for enterprise applications.

  • Django (Python): High-level framework with rapid development features.

  • Go with Gin: Ultra-fast, minimal framework for APIs and microservices.

Example: Using New Features in .NET 8

Let’s create a simple ASP.NET Core app using .NET 8 features like Minimal APIs, rate limiting, and anti-forgery middleware.

Step 1: Create a New Project

dotnet new webapi -o Net8Demo
cd Net8Demo

Step 2: Add Rate LimitingUpdate Program.cs:

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;

var builder = WebApplication.CreateBuilder(args);

// Add rate limiting
builder.Services.AddRateLimiting(options =>
{
    options.AddFixedWindowLimiter("ApiLimiter", opt =>
    {
        opt.PermitLimit = 100;
        opt.Window = TimeSpan.FromMinutes(1);
        opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        opt.QueueLimit = 10;
    });
});

var app = builder.Build();

// Apply rate limiting
app.UseRateLimiter();

app.MapGet("/api/hello", () => "Hello, .NET 8!")
   .RequireRateLimiting("ApiLimiter");

app.Run();

Step 3: Add Anti-Forgery MiddlewareUpdate Program.cs to include anti-forgery token validation:

using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;

var builder = WebApplication.CreateBuilder(args);

// Add anti-forgery services
builder.Services.AddAntiforgery();

builder.Services.AddRateLimiting(options =>
{
    options.AddFixedWindowLimiter("ApiLimiter", opt =>
    {
        opt.PermitLimit = 100;
        opt.Window = TimeSpan.FromMinutes(1);
        opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        opt.QueueLimit = 10;
    });
});

var app = builder.Build();

app.UseRateLimiter();
app.UseAntiforgery();

app.MapPost("/api/submit", (HttpContext context, IAntiforgery antiforgery) =>
{
    antiforgery.ValidateRequestAsync(context);
    return Results.Ok("Form submitted successfully!");
});

app.MapGet("/api/hello", () => "Hello, .NET 8!")
   .RequireRateLimiting("ApiLimiter");

app.Run();

Step 4: TestRun the app:

dotnet run

Test the /api/hello endpoint to verify rate limiting (limit to 100 requests per minute). Test the /api/submit endpoint with a valid anti-forgery token to ensure secure form submission.

This example demonstrates .NET 8’s rate limiting and anti-forgery middleware, showcasing improved security and performance.


Minimal APIs vs. Full MVC

Understanding Minimal APIs and Full MVC

Minimal APIs (introduced in .NET 6, enhanced in .NET 7/8) provide a lightweight way to build APIs with minimal boilerplate code, ideal for microservices and simple endpoints. Full MVC (Model-View-Controller) is a robust framework for building complex web applications with structured controllers, views, and models.

Key Features

  • Minimal APIs:

    • Simplified syntax in Program.cs.

    • Supports route handlers, form binding, and dependency injection.

    • Ideal for microservices and lightweight APIs.

  • Full MVC:

    • Structured architecture with controllers, views, and models.

    • Supports filters, model validation, and Razor views.

    • Suited for complex applications with UI and server-side logic.

Pros, Cons, and Alternatives for Minimal APIs and MVC

Pros

  • Minimal APIs:

    • Simplicity: Less code for simple APIs.

    • Performance: Lower overhead due to minimal middleware.

    • Flexibility: Easy to integrate with other frameworks.

    • Cloud-Native: Ideal for microservices and containers.

  • Full MVC:

    • Structure: Clear separation of concerns.

    • Features: Supports filters, validation, and Razor views.

    • Scalability: Handles complex applications with ease.

    • Community: Mature ecosystem with extensive documentation.

Cons

  • Minimal APIs:

    • Limited Features: Lacks advanced features like filters.

    • Scalability: Less suited for large, complex apps.

    • Learning Curve: New syntax may confuse MVC developers.

  • Full MVC:

    • Boilerplate: More code for simple APIs.

    • Overhead: Higher resource usage for small apps.

    • Complexity: Steeper learning curve for beginners.

Alternatives

  • FastAPI (Python): Lightweight API framework with async support.

  • Express.js (Node.js): Minimal framework for JavaScript-based APIs.

  • Spring WebFlux (Java): Reactive framework for high-performance APIs.

  • Go with Echo: Fast, minimal framework for Go-based APIs.

Example: Building APIs with Minimal APIs and MVC

Let’s build a product API using both Minimal APIs and Full MVC.

Minimal APIs

Create MinimalApiDemo:

dotnet new webapi -o MinimalApiDemo
cd MinimalApiDemo

Update Program.cs:

using Microsoft.AspNetCore.Antiforgery;
using System.ComponentModel.DataAnnotations;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

app.MapGet("/api/products", () => new[]
{
    new Product { Id = 1, Name = "Laptop", Price = 999.99m },
    new Product { Id = 2, Name = "Phone", Price = 499.99m }
});

app.MapPost("/api/products", async (HttpContext context, IAntiforgery antiforgery, [FromBody] Product product) =>
{
    try
    {
        await antiforgery.ValidateRequestAsync(context);
        // Simulate saving to database
        return Results.Created("/api/products/1", product);
    }
    catch (AntiforgeryValidationException ex)
    {
        return Results.BadRequest("Invalid anti-forgery token.");
    }
    catch (Exception ex)
    {
        return Results.Problem("An error occurred while creating the product.");
    }
});

app.Run();

public class Product
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Range(0.01, 10000)]
    public decimal Price { get; set; }
}

Full MVC

Create MvcDemo:

dotnet new mvc -o MvcDemo
cd MvcDemo

Create Models/Product.cs:

using System.ComponentModel.DataAnnotations;

namespace MvcDemo.Models
{
    public class Product
    {
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        [Range(0.01, 10000)]
        public decimal Price { get; set; }
    }
}

Create Controllers/ProductsController.cs:

using Microsoft.AspNetCore.Mvc;
using MvcDemo.Models;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.Extensions.Logging;

namespace MvcDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        private readonly IAntiforgery _antiforgery;
        private readonly ILogger<ProductsController> _logger;

        public ProductsController(IAntiforgery antiforgery, ILogger<ProductsController> logger)
        {
            _antiforgery = antiforgery;
            _logger = logger;
        }

        [HttpGet]
        public IActionResult Get()
        {
            try
            {
                var products = new[]
                {
                    new Product { Id = 1, Name = "Laptop", Price = 999.99m },
                    new Product { Id = 2, Name = "Phone", Price = 499.99m }
                };
                return Ok(products);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching products");
                return StatusCode(500, "An error occurred while fetching products.");
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Post([FromBody] Product product)
        {
            try
            {
                await _antiforgery.ValidateRequestAsync(HttpContext);
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
                // Simulate saving to database
                return CreatedAtAction(nameof(Get), new { id = 1 }, product);
            }
            catch (AntiforgeryValidationException ex)
            {
                _logger.LogError(ex, "Invalid anti-forgery token");
                return BadRequest("Invalid anti-forgery token.");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error creating product");
                return StatusCode(500, "An error occurred while creating the product.");
            }
        }
    }
}

Update Program.cs to include anti-forgery services:

using Microsoft.AspNetCore.Antiforgery;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddAntiforgery();

var app = builder.Build();

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

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

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

app.Run();

Step 5: Test

  • Minimal APIs: Run MinimalApiDemo and test /api/products (GET) and POST with an anti-forgery token.

  • MVC: Run MvcDemo and test /api/products (GET/POST) with similar functionality.

This example highlights Minimal APIs’ simplicity for small projects and MVC’s robustness for complex applications.


Blazor Server vs. Blazor WebAssembly

Understanding Blazor Hosting Models

Blazor is a framework for building interactive web UIs using C# instead of JavaScript. It supports two hosting models: Blazor Server and Blazor WebAssembly.

Blazor Server

  • Runs on the server, using SignalR for real-time communication.

  • UI updates and events are handled over a WebSocket connection.

  • Smaller client-side footprint, faster initial load.

Blazor WebAssembly

  • Runs client-side in the browser using WebAssembly.

  • Downloads the .NET runtime and app code to the client.

  • Supports offline scenarios and Progressive Web Apps (PWAs).

.NET 8 Enhancements

  • Blazor Web App Template: Combines Server and WebAssembly with static SSR, streaming rendering, and per-component interactivity.

  • Interactive Auto Rendering: Switches from server to client rendering at runtime for faster startup.

  • Jiterpreter: Improves WebAssembly performance.

Pros, Cons, and Alternatives for Blazor

Pros

  • Blazor Server:

    • Fast Load Time: Minimal client-side download.

    • Server Capabilities: Access to full .NET APIs.

    • Thin Clients: Works on low-resource devices.

    • Secure: Code remains on the server.

  • Blazor WebAssembly:

    • Offline Support: Runs as a PWA.

    • Client-Side: Reduces server load.

    • Full Browser Access: Interacts with JavaScript and browser APIs.

    • Performance: Improved with Jiterpreter and AOT in .NET 8.

Cons

  • Blazor Server:

    • Latency: Network hops for each interaction.

    • No Offline Support: Requires constant connection.

    • Scalability: Server resources needed for multiple clients.

  • Blazor WebAssembly:

    • Download Size: Larger initial payload.

    • Performance: Slower startup compared to Server.

    • Security: Code runs on client, requiring careful protection.

Alternatives

  • React/Vue.js: JavaScript frameworks for client-side UIs.

  • Angular: Robust framework for enterprise SPAs.

  • Svelte: Lightweight, compiler-based framework.

  • ASP.NET Core MVC: Traditional server-side rendering with Razor.

Example: Building a Blazor App with Server and WebAssembly

Let’s build a product catalog using both Blazor Server and WebAssembly.

Blazor Server

Create BlazorServerDemo:

dotnet new blazorserver -o BlazorServerDemo
cd BlazorServerDemo

Create Models/Product.cs:

namespace BlazorServerDemo.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

Update Pages/Index.razor:

@page "/"
@using BlazorServerDemo.Models
@inject HttpClient Http
@rendermode InteractiveServer

<h1>Product Catalog</h1>

@if (products == null)
{
    <p>Loading...</p>
}
else
{
    <ul>
        @foreach (var product in products)
        {
            <li>@product.Name - $@product.Price</li>
        }
    </ul>
}

@code {
    private Product[]? products;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            products = await Http.GetFromJsonAsync<Product[]>("api/products");
        }
        catch (Exception ex)
        {
            // Log error to server-side logging
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

Create Controllers/ProductsController.cs:

using Microsoft.AspNetCore.Mvc;
using BlazorServerDemo.Models;

namespace BlazorServerDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        [HttpGet]
        public IActionResult Get()
        {
            var products = new[]
            {
                new Product { Id = 1, Name = "Laptop", Price = 999.99m },
                new Product { Id = 2, Name = "Phone", Price = 499.99m }
            };
            return Ok(products);
        }
    }
}

Blazor WebAssembly

Create BlazorWasmDemo:

dotnet new blazorwasm -o BlazorWasmDemo
cd BlazorWasmDemo

Update Pages/Index.razor (similar to Blazor Server):

@page "/"
@using BlazorWasmDemo.Models
@inject HttpClient Http
@rendermode InteractiveWebAssembly

<h1>Product Catalog</h1>

@if (products == null)
{
    <p>Loading...</p>
}
else
{
    <ul>
        @foreach (var product in products)
        {
            <li>@product.Name - $@product.Price</li>
        }
    </ul>
}

@code {
    private Product[]? products;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            products = await Http.GetFromJsonAsync<Product[]>("https://api.example.com/products");
        }
        catch (Exception ex)
        {
            // Log error to console
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

Create a separate API project for WebAssembly:

dotnet new webapi -o WasmApi
cd WasmApi

Add Controllers/ProductsController.cs (same as Blazor Server).

Step 5: Test

  • Blazor Server: Run BlazorServerDemo and verify the product list loads via SignalR.

  • Blazor WebAssembly: Run WasmApi and BlazorWasmDemo, ensuring the client fetches data from the API.

This example demonstrates Blazor Server’s server-side rendering and WebAssembly’s client-side capabilities.


gRPC in ASP.NET Core

What is gRPC?

gRPC is a high-performance, open-source RPC framework that uses HTTP/2 and Protocol Buffers for efficient communication. In ASP.NET Core, gRPC is ideal for microservices and real-time applications.

Key Features

  • High Performance: HTTP/2-based, low-latency communication.

  • Streaming: Supports unary, server, client, and bidirectional streaming.

  • Strong Typing: Uses Protocol Buffers for strict contracts.

  • Cross-Platform: Works with multiple languages and platforms.

Pros, Cons, and Alternatives for gRPC

Pros

  • Performance: Faster than REST due to HTTP/2 and binary serialization.

  • Streaming: Ideal for real-time apps like chat or IoT.

  • Type Safety: Protocol Buffers ensure robust contracts.

  • Scalability: Suited for microservices architectures.

Cons

  • Complexity: Steeper learning curve than REST.

  • Browser Support: Limited native support in browsers (requires gRPC-Web).

  • Tooling: Less mature than REST ecosystems.

  • Debugging: Harder to inspect binary payloads.

Alternatives

  • REST APIs: Simpler, widely supported, but slower.

  • GraphQL: Flexible querying, but complex for real-time.

  • SignalR: Real-time communication for ASP.NET Core apps.

  • WebSockets: Low-level protocol for real-time apps.

Example: Implementing a gRPC Service

Let’s create a gRPC service for product management.

Step 1: Create a gRPC Project

dotnet new grpc -o GrpcDemo
cd GrpcDemo

Step 2: Define Proto FileUpdate Protos/greet.proto to product.proto:

syntax = "proto3";

option csharp_namespace = "GrpcDemo";

service ProductService {
  rpc GetProduct (ProductRequest) returns (ProductResponse);
}

message ProductRequest {
  int32 id = 1;
}

message ProductResponse {
  int32 id = 1;
  string name = 2;
  double price = 3;
}

Step 3: Implement ServiceUpdate Services/ProductService.cs:

using Grpc.Core;
using Microsoft.Extensions.Logging;

namespace GrpcDemo.Services
{
    public class ProductService : ProductService.ProductServiceBase
    {
        private readonly ILogger<ProductService> _logger;

        public ProductService(ILogger<ProductService> logger)
        {
            _logger = logger;
        }

        public override Task<ProductResponse> GetProduct(ProductRequest request, ServerCallContext context)
        {
            try
            {
                _logger.LogInformation("Fetching product with ID {Id}", request.Id);
                var product = new ProductResponse
                {
                    Id = request.Id,
                    Name = "Laptop",
                    Price = 999.99
                };
                return Task.FromResult(product);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching product with ID {Id}", request.Id);
                throw new RpcException(new Status(StatusCode.Internal, "Error fetching product"));
            }
        }
    }
}

Step 4: Create a ClientCreate GrpcClient:

dotnet new console -o GrpcClient
cd GrpcClient
dotnet add package Grpc.Net.Client
dotnet add package Google.Protobuf
dotnet add package Grpc.Tools

Copy product.proto to GrpcClient/Protos and update GrpcClient.csproj:

<ItemGroup>
  <Protobuf Include="Protos\product.proto" GrpcServices="Client" />
</ItemGroup>

Create Program.cs:

using Grpc.Net.Client;
using GrpcDemo;

using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new ProductService.ProductServiceClient(channel);

try
{
    var response = await client.GetProductAsync(new ProductRequest { Id = 1 });
    Console.WriteLine($"Product: {response.Name}, Price: ${response.Price}");
}
catch (RpcException ex)
{
    Console.WriteLine($"gRPC Error: {ex.Status.Detail}");
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}

Step 5: TestRun GrpcDemo and GrpcClient. The client retrieves product details via gRPC.

This example demonstrates gRPC’s efficiency for microservices communication.


Microservices with Dapper

What is Dapper?

Dapper is a lightweight, high-performance ORM (Object-Relational Mapper) for .NET, ideal for microservices due to its simplicity and speed.

Key Features

  • Performance: Faster than EF Core for simple queries.

  • Lightweight: Minimal overhead, no complex configuration.

  • Flexibility: Supports raw SQL queries with object mapping.

  • Cross-Database: Works with SQL Server, PostgreSQL, MySQL, etc.

Pros, Cons, and Alternatives for Dapper

Pros

  • Speed: Near-native SQL performance.

  • Simplicity: Easy to integrate into microservices.

  • Flexibility: Custom SQL for complex queries.

  • Lightweight: Minimal dependencies.

Cons

  • Manual SQL: Requires writing SQL queries, increasing risk of errors.

  • Limited Features: Lacks advanced ORM features like change tracking.

  • Maintenance: SQL queries can become hard to manage in large apps.

  • Security: Risk of SQL injection if not handled properly.

Alternatives

  • Entity Framework Core: Full-featured ORM with LINQ support.

  • NHibernate: Robust ORM for complex applications.

  • ADO.NET: Low-level data access for maximum control.

  • SqlKata: Query builder with ORM-like features.

Example: Building a Microservice with Dapper

Let’s build a product microservice using Dapper.

Step 1: Create a Microservice

dotnet new webapi -o ProductMicroservice
cd ProductMicroservice
dotnet add package Dapper
dotnet add package Microsoft.Data.SqlClient

Step 2: Set Up DatabaseCreate a SQL Server database ProductDb with a Products table:

CREATE TABLE Products (
    Id INT PRIMARY KEY IDENTITY,
    Name NVARCHAR(100) NOT NULL,
    Price DECIMAL(18,2) NOT NULL
);
INSERT INTO Products (Name, Price) VALUES ('Laptop', 999.99), ('Phone', 499.99);

Update appsettings.json:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=ProductDb;Trusted_Connection=True;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Step 3: Create ModelCreate Models/Product.cs:

namespace ProductMicroservice.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

Step 4: Create ControllerCreate Controllers/ProductsController.cs:

using Dapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using ProductMicroservice.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ProductMicroservice.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly ILogger<ProductsController> _logger;

        public ProductsController(IConfiguration configuration, ILogger<ProductsController> logger)
        {
            _configuration = configuration;
            _logger = logger;
        }

        [HttpGet]
        public async Task<IActionResult> Get()
        {
            try
            {
                using var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection"));
                var products = await connection.QueryAsync<Product>("SELECT * FROM Products");
                _logger.LogInformation("Fetched products successfully");
                return Ok(products);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching products");
                return StatusCode(500, "An error occurred while fetching products.");
            }
        }

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] Product product)
        {
            try
            {
                if (string.IsNullOrEmpty(product.Name) || product.Price <= 0)
                {
                    return BadRequest("Invalid product data.");
                }

                using var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection"));
                var sql = "INSERT INTO Products (Name, Price) VALUES (@Name, @Price); SELECT SCOPE_IDENTITY();";
                var id = await connection.ExecuteScalarAsync<int>(sql, product);
                _logger.LogInformation("Created product with ID {Id}", id);
                product.Id = id;
                return CreatedAtAction(nameof(Get), new { id }, product);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error creating product");
                return StatusCode(500, "An error occurred while creating the product.");
            }
        }
    }
}

Step 5: TestRun the microservice and test /api/products (GET/POST). Verify data is retrieved and stored in the database.

This example demonstrates Dapper’s simplicity and performance for microservices.


Best Practices for ASP.NET Core Development

Security Best Practices

  • Anti-Forgery Tokens: Use in Minimal APIs and MVC to prevent CSRF attacks.

  • HTTPS: Enforce HTTPS and HSTS for secure communication.

  • Secrets Management: Use Azure Key Vault or environment variables.

  • Input Validation: Validate all inputs to prevent injection attacks.

  • Authentication/Authorization: Use ASP.NET Core Identity or OIDC.

Performance Best Practices

  • AOT Compilation: Use Native AOT for cloud-native apps.

  • Caching: Implement output caching for Minimal APIs and MVC.

  • Trimming: Reduce Blazor WebAssembly payload with IL trimming.

  • Async Programming: Use async/await for I/O-bound operations.

  • Load Balancing: Deploy with Azure or Kubernetes for scalability.

Error Handling Best Practices

  • Centralized Logging: Use ILogger with Application Insights.

  • Exception Middleware: Handle errors globally in ASP.NET Core.

  • gRPC Error Handling: Use RpcException for structured errors.

  • Validation: Use data annotations and custom validation logic.

  • Fallbacks: Provide fallback responses for failed operations.


Real-Life Example: Building an E-Commerce Platform

Let’s build an e-commerce platform combining Minimal APIs, Blazor Web App, gRPC, and Dapper.

Step 1: Set Up Solution

dotnet new sln -n ECommercePlatform
dotnet new blazor -o ECommerce.Web
dotnet new webapi -o ECommerce.Api
dotnet new grpc -o ECommerce.Grpc
dotnet sln add ECommerce.Web ECommerce.Api ECommerce.Grpc

Step 2: Configure DatabaseCreate a Products table as shown in the Dapper example.

Step 3: Implement API with DapperIn ECommerce.Api, reuse the ProductsController from the Dapper example.

Step 4: Implement gRPC ServiceIn ECommerce.Grpc, reuse the ProductService from the gRPC example.

Step 5: Create Blazor Web AppUpdate ECommerce.Web/Pages/Index.razor:

@page "/"
@using ECommerce.Web.Models
@inject HttpClient Http
@rendermode InteractiveAuto

<h1>E-Commerce Platform</h1>

@if (products == null)
{
    <p>Loading...</p>
}
else
{
    <ul>
        @foreach (var product in products)
        {
            <li>@product.Name - $@product.Price</li>
        }
    </ul>
}

@code {
    private Product[]? products;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            products = await Http.GetFromJsonAsync<Product[]>("http://localhost:5000/api/products");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

Create Models/Product.cs:

namespace ECommerce.Web.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

Step 6: Add gRPC ClientCreate ECommerce.Client:

dotnet new console -o ECommerce.Client
cd ECommerce.Client
dotnet add package Grpc.Net.Client
dotnet add package Google.Protobuf
dotnet add package Grpc.Tools

Copy product.proto and implement Program.cs as shown in the gRPC example.

Step 7: Test

  • Run ECommerce.Api (port 5000), ECommerce.Grpc (port 5001), and ECommerce.Web.

  • Verify the Blazor app displays products from the API.

  • Test the gRPC client to fetch product details.

  • Monitor performance with Application Insights (configured as in Module 12).

Real-Life Scenario: This platform demonstrates:

  • Minimal APIs: Fast product API with Dapper.

  • Blazor Web App: Interactive UI with Auto rendering.

  • gRPC: High-performance product service.

  • Dapper: Efficient data access for microservices.

  • Security: Anti-forgery tokens and HTTPS.

  • Performance: AOT and caching for scalability.


Conclusion

In Module 13 of our ASP.NET Core Complete Course, we explored the latest features in ASP.NET Core, including .NET 7/8 advancements, Minimal APIs vs. Full MVC, Blazor Server vs. WebAssembly, gRPC, and Microservices with Dapper. Through practical examples and a real-life e-commerce platform, you’ve learned how to leverage these features for modern web development. With best practices for security, performance, and error handling, you’re equipped to build scalable, efficient applications. Stay tuned for more in our ASP.NET Core journey!


FAQs

Q1: What are the key performance improvements in .NET 8?

  • .NET 8 offers 18% faster JSON benchmarks and 24% faster Fortunes benchmarks, plus Jiterpreter for Blazor WebAssembly.

Q2: When should I use Minimal APIs over MVC?

  • Use Minimal APIs for lightweight, microservice-style APIs; use MVC for complex applications with UI and structured logic.

Q3: Why choose Blazor Server over WebAssembly?

  • Blazor Server offers faster load times and server-side security, while WebAssembly supports offline scenarios and reduces server load.

Q4: How does gRPC improve microservices?

  • gRPC provides high-performance, type-safe communication with HTTP/2 and Protocol Buffers.

Q5: Why use Dapper in microservices?

  • Dapper’s lightweight, high-performance nature makes it ideal for simple, fast data access in microservices.

No comments:

Post a Comment

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