Library API- Dotnet core web api

 


Creating a comprehensive .NET Core Web API for a library service involves several key components and best practices. Below is a detailed guide to achieve this, covering multiple aspects such as versioning, routing, exception handling, monitoring, health checks, load balancing, authentication, and authorization.

Step-by-Step Implementation

  1. Project Setup

Create a new .NET Core Web API project:
bash
=====================================
dotnet new webapi -n LibraryService

cd LibraryService


  1. Project Structure

Organize your project using the following structure:
=====================================
LibraryService

├── Controllers

├── Models

├── Data

├── Services

├── DTOs

├── Middleware

├── Extensions

├── Policies

└── Program.cs


  1. Versioning and Routing

Install the necessary packages:
bash
=====================================
dotnet add package Microsoft.AspNetCore.Mvc.Versioning

dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer


Configure versioning in Program.cs:
csharp
=====================================
var builder = WebApplication.CreateBuilder(args);


builder.Services.AddControllers();

builder.Services.AddApiVersioning(options =>

{

    options.AssumeDefaultVersionWhenUnspecified = true;

    options.DefaultApiVersion = new ApiVersion(1, 0);

    options.ReportApiVersions = true;

});

builder.Services.AddVersionedApiExplorer(options =>

{

    options.GroupNameFormat = "'v'VVV";

    options.SubstituteApiVersionInUrl = true;

});


var app = builder.Build();


app.UseRouting();

app.UseEndpoints(endpoints =>

{

    endpoints.MapControllers();

});


app.Run();


  1. Controllers and Endpoints

Create a basic controller in Controllers/BooksController.cs:
csharp
=====================================
using Microsoft.AspNetCore.Mvc;


[ApiController]

[Route("api/v{version:apiVersion}/[controller]")]

[ApiVersion("1.0")]

public class BooksController : ControllerBase

{

    [HttpGet]

    public IActionResult GetBooks()

    {

        return Ok(new[] { "Book1", "Book2" });

    }

}


  1. Exception Handling

Create a custom middleware for exception handling:
csharp
=====================================
public class ExceptionHandlingMiddleware

{

    private readonly RequestDelegate _next;


    public ExceptionHandlingMiddleware(RequestDelegate next)

    {

        _next = next;

    }


    public async Task InvokeAsync(HttpContext context)

    {

        try

        {

            await _next(context);

        }

        catch (Exception ex)

        {

            await HandleExceptionAsync(context, ex);

        }

    }


    private static Task HandleExceptionAsync(HttpContext context, Exception ex)

    {

        context.Response.ContentType = "application/json";

        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        return context.Response.WriteAsync(new { error = ex.Message }.ToString());

    }

}


Register middleware in Program.cs:
csharp
=====================================
app.UseMiddleware<ExceptionHandlingMiddleware>();


  1. Monitoring and Health Checks

Install health check packages:
bash
=====================================
dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks

dotnet add package AspNetCore.HealthChecks.UI

dotnet add package AspNetCore.HealthChecks.UI.InMemory.Storage


Configure health checks in Program.cs:
csharp
=====================================
builder.Services.AddHealthChecks();

builder.Services.AddHealthChecksUI().AddInMemoryStorage();


app.UseEndpoints(endpoints =>

{

    endpoints.MapHealthChecks("/health");

    endpoints.MapHealthChecksUI();

});


  1. Load Balancing

    • Use a reverse proxy like Nginx or a load balancer service such as Azure Load Balancer or AWS Elastic Load Balancer. Configure your load balancer to distribute requests across multiple instances of your API service.

  2. Authentication and Authorization

Install authentication and authorization packages:
bash
=====================================
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

dotnet add package Microsoft.AspNetCore.Authorization


Configure authentication in Program.cs:
csharp
=====================================
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

    .AddJwtBearer(options =>

    {

        options.TokenValidationParameters = new TokenValidationParameters

        {

            ValidateIssuer = true,

            ValidateAudience = true,

            ValidateLifetime = true,

            ValidateIssuerSigningKey = true,

            ValidIssuer = "your-issuer",

            ValidAudience = "your-audience",

            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-secret-key"))

        };

    });


builder.Services.AddAuthorization(options =>

{

    options.AddPolicy("AdminPolicy", policy => policy.RequireRole("Admin"));

    options.AddPolicy("UserPolicy", policy => policy.RequireRole("User"));

});


var app = builder.Build();


app.UseAuthentication();

app.UseAuthorization();


  1. Define Policies and Roles

Apply policies and roles in controllers:
csharp
=====================================
[Authorize(Policy = "AdminPolicy")]

[HttpPost]

public IActionResult AddBook([FromBody] BookDto book)

{

    // Add book logic

    return Ok();

}


  1. Extensions and Utilities

Create extension methods for better organization. For example, create Extensions/ServiceExtensions.cs to add all the service configurations:
csharp
=====================================
public static class ServiceExtensions

{

    public static void ConfigureCors(this IServiceCollection services)

    {

        services.AddCors(options =>

        {

            options.AddPolicy("CorsPolicy", builder =>

                builder.AllowAnyOrigin()

                       .AllowAnyMethod()

                       .AllowAnyHeader());

        });

    }


    public static void ConfigureIISIntegration(this IServiceCollection services)

    {

        services.Configure<IISOptions>(options => { });

    }


    public static void ConfigureLoggerService(this IServiceCollection services)

    {

        services.AddSingleton<ILoggerManager, LoggerManager>();

    }

}


  1. DTOs and Models

Create Data Transfer Objects (DTOs) and models for your entities. For example, Models/Book.cs and DTOs/BookDto.cs:
csharp
=====================================
public class Book

{

    public int Id { get; set; }

    public string Title { get; set; }

    public string Author { get; set; }

}


public class BookDto

{

    public string Title { get; set; }

    public string Author { get; set; }

}


Final Project Setup

Your Program.cs should look similar to this after integrating all the components:

csharp

=====================================

var builder = WebApplication.CreateBuilder(args);


// Add services to the container.

builder.Services.AddControllers();

builder.Services.AddApiVersioning(options =>

{

    options.AssumeDefaultVersionWhenUnspecified = true;

    options.DefaultApiVersion = new ApiVersion(1, 0);

    options.ReportApiVersions = true;

});

builder.Services.AddVersionedApiExplorer(options =>

{

    options.GroupNameFormat = "'v'VVV";

    options.SubstituteApiVersionInUrl = true;

});

builder.Services.ConfigureCors();

builder.Services.ConfigureIISIntegration();

builder.Services.ConfigureLoggerService();

builder.Services.AddHealthChecks();

builder.Services.AddHealthChecksUI().AddInMemoryStorage();

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

    .AddJwtBearer(options =>

    {

        options.TokenValidationParameters = new TokenValidationParameters

        {

            ValidateIssuer = true,

            ValidateAudience = true,

            ValidateLifetime = true,

            ValidateIssuerSigningKey = true,

            ValidIssuer = "your-issuer",

            ValidAudience = "your-audience",

            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-secret-key"))

        };

    });

builder.Services.AddAuthorization(options =>

{

    options.AddPolicy("AdminPolicy", policy => policy.RequireRole("Admin"));

    options.AddPolicy("UserPolicy", policy => policy.RequireRole("User"));

});


var app = builder.Build();


app.UseRouting();

app.UseAuthentication();

app.UseAuthorization();

app.UseMiddleware<ExceptionHandlingMiddleware>();

app.UseEndpoints(endpoints =>

{

    endpoints.MapControllers();

    endpoints.MapHealthChecks("/health");

    endpoints.MapHealthChecksUI();

});


app.Run();


This setup provides a comprehensive framework for a robust, secure, and scalable library service API in .NET Core. You can further enhance and customize each component according to your specific requirements.

=========================================================================

                                                                        Explanation

========================================================================

Let's go through each section of the code step by step to understand what it does and why it's important.

1. Project Setup

bash

=====================================

dotnet new webapi -n LibraryService

cd LibraryService


This command creates a new .NET Core Web API project named LibraryService and navigates into the project directory.

2. Versioning and Routing

Adding Packages

bash

=====================================

dotnet add package Microsoft.AspNetCore.Mvc.Versioning

dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer


These packages are used to enable API versioning and versioned API exploration.

Configuring Versioning in Program.cs

csharp

=====================================

builder.Services.AddApiVersioning(options =>

{

    options.AssumeDefaultVersionWhenUnspecified = true;

    options.DefaultApiVersion = new ApiVersion(1, 0);

    options.ReportApiVersions = true;

});

builder.Services.AddVersionedApiExplorer(options =>

{

    options.GroupNameFormat = "'v'VVV";

    options.SubstituteApiVersionInUrl = true;

});


  • AssumeDefaultVersionWhenUnspecified: If the API version is not specified in the request, the default version will be assumed.

  • DefaultApiVersion: Sets the default API version to 1.0.

  • ReportApiVersions: Adds the API versions supported by this API to the response headers.

  • GroupNameFormat: Specifies the format of the versioned API group names.

  • SubstituteApiVersionInUrl: Indicates whether the API version should be substituted in the URL.

3. Controllers and Endpoints

Creating a Basic Controller

csharp

=====================================

[ApiController]

[Route("api/v{version:apiVersion}/[controller]")]

[ApiVersion("1.0")]

public class BooksController : ControllerBase

{

    [HttpGet]

    public IActionResult GetBooks()

    {

        return Ok(new[] { "Book1", "Book2" });

    }

}


  • ApiController: Indicates that this class is an API controller.

  • Route("api/v{version:apiVersion}/[controller]"): Defines the route template for the API, including versioning.

  • ApiVersion("1.0"): Specifies that this controller is for version 1.0 of the API.

  • GetBooks(): A simple action method that returns a list of books.

4. Exception Handling

Creating Custom Middleware

csharp

=====================================

public class ExceptionHandlingMiddleware

{

    private readonly RequestDelegate _next;


    public ExceptionHandlingMiddleware(RequestDelegate next)

    {

        _next = next;

    }


    public async Task InvokeAsync(HttpContext context)

    {

        try

        {

            await _next(context);

        }

        catch (Exception ex)

        {

            await HandleExceptionAsync(context, ex);

        }

    }


    private static Task HandleExceptionAsync(HttpContext context, Exception ex)

    {

        context.Response.ContentType = "application/json";

        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        return context.Response.WriteAsync(new { error = ex.Message }.ToString());

    }

}


This middleware handles exceptions globally:

  • It catches any exception that occurs during the processing of HTTP requests.

  • It sets the response status code to 500 (Internal Server Error) and returns a JSON response with the error message.

Registering Middleware

csharp

=====================================

app.UseMiddleware<ExceptionHandlingMiddleware>();


Registers the custom exception handling middleware in the request pipeline.

5. Monitoring and Health Checks

Adding Health Check Packages

bash

=====================================

dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks

dotnet add package AspNetCore.HealthChecks.UI

dotnet add package AspNetCore.HealthChecks.UI.InMemory.Storage


These packages provide health check capabilities and a UI to monitor the health status.

Configuring Health Checks

csharp

=====================================

builder.Services.AddHealthChecks();

builder.Services.AddHealthChecksUI().AddInMemoryStorage();


app.UseEndpoints(endpoints =>

{

    endpoints.MapHealthChecks("/health");

    endpoints.MapHealthChecksUI();

});


  • AddHealthChecks(): Registers the health check services.

  • AddHealthChecksUI().AddInMemoryStorage(): Registers the health checks UI and uses in-memory storage to persist health check results.

  • MapHealthChecks("/health"): Maps the health check endpoint to /health.

  • MapHealthChecksUI(): Maps the health check UI endpoint.

6. Authentication and Authorization

Adding Packages

bash

=====================================

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

dotnet add package Microsoft.AspNetCore.Authorization


These packages enable JWT (JSON Web Token) authentication and authorization.

Configuring Authentication and Authorization

csharp

=====================================

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

    .AddJwtBearer(options =>

    {

        options.TokenValidationParameters = new TokenValidationParameters

        {

            ValidateIssuer = true,

            ValidateAudience = true,

            ValidateLifetime = true,

            ValidateIssuerSigningKey = true,

            ValidIssuer = "your-issuer",

            ValidAudience = "your-audience",

            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-secret-key"))

        };

    });


builder.Services.AddAuthorization(options =>

{

    options.AddPolicy("AdminPolicy", policy => policy.RequireRole("Admin"));

    options.AddPolicy("UserPolicy", policy => policy.RequireRole("User"));

});


var app = builder.Build();


app.UseAuthentication();

app.UseAuthorization();


  • Configures JWT authentication with token validation parameters.

  • Adds authorization policies that require specific roles.

7. Applying Policies and Roles in Controllers

csharp

=====================================

[Authorize(Policy = "AdminPolicy")]

[HttpPost]

public IActionResult AddBook([FromBody] BookDto book)

{

    // Add book logic

    return Ok();

}


  • Authorize(Policy = "AdminPolicy"): Restricts access to the AddBook action to users with the Admin role.

8. Extensions and Utilities

Creating Extension Methods

csharp

=====================================

public static class ServiceExtensions

{

    public static void ConfigureCors(this IServiceCollection services)

    {

        services.AddCors(options =>

        {

            options.AddPolicy("CorsPolicy", builder =>

                builder.AllowAnyOrigin()

                       .AllowAnyMethod()

                       .AllowAnyHeader());

        });

    }


    public static void ConfigureIISIntegration(this IServiceCollection services)

    {

        services.Configure<IISOptions>(options => { });

    }


    public static void ConfigureLoggerService(this IServiceCollection services)

    {

        services.AddSingleton<ILoggerManager, LoggerManager>();

    }

}


  • ConfigureCors(): Configures CORS (Cross-Origin Resource Sharing) policy.

  • ConfigureIISIntegration(): Configures IIS integration options.

  • ConfigureLoggerService(): Configures a singleton service for logging.

9. DTOs and Models

Creating Data Transfer Objects (DTOs) and Models

csharp

=====================================

public class Book

{

    public int Id { get; set; }

    public string Title { get; set; }

    public string Author { get; set; }

}


public class BookDto

{

    public string Title { get; set; }

    public string Author { get; set; }

}


  • Book: Represents the book entity.

  • BookDto: Represents the data transfer object for the book.

Final Project Setup in Program.cs

csharp

=====================================

var builder = WebApplication.CreateBuilder(args);


// Add services to the container.

builder.Services.AddControllers();

builder.Services.AddApiVersioning(options =>

{

    options.AssumeDefaultVersionWhenUnspecified = true;

    options.DefaultApiVersion = new ApiVersion(1, 0);

    options.ReportApiVersions = true;

});

builder.Services.AddVersionedApiExplorer(options =>

{

    options.GroupNameFormat = "'v'VVV";

    options.SubstituteApiVersionInUrl = true;

});

builder.Services.ConfigureCors();

builder.Services.ConfigureIISIntegration();

builder.Services.ConfigureLoggerService();

builder.Services.AddHealthChecks();

builder.Services.AddHealthChecksUI().AddInMemoryStorage();

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

    .AddJwtBearer(options =>

    {

        options.TokenValidationParameters = new TokenValidationParameters

        {

            ValidateIssuer = true,

            ValidateAudience = true,

            ValidateLifetime = true,

            ValidateIssuerSigningKey = true,

            ValidIssuer = "your-issuer",

            ValidAudience = "your-audience",

            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-secret-key"))

        };

    });

builder.Services.AddAuthorization(options =>

{

    options.AddPolicy("AdminPolicy", policy => policy.RequireRole("Admin"));

    options.AddPolicy("UserPolicy", policy => policy.RequireRole("User"));

});


var app = builder.Build();


app.UseRouting();

app.UseAuthentication();

app.UseAuthorization();

app.UseMiddleware<ExceptionHandlingMiddleware>();

app.UseEndpoints(endpoints =>

{

    endpoints.MapControllers();

    endpoints.MapHealthChecks("/health");

    endpoints.MapHealthChecksUI();

});


app.Run();


This configuration sets up the .NET Core Web API with all necessary services, middleware, and endpoint mappings for a comprehensive library service, ensuring it is secure, robust, and scalable



Post a Comment

Previous Post Next Post