Getting Started with LSCore

LSCore is a modular .NET 9 framework that provides building blocks for ASP.NET Core applications, including authentication, validation, object mapping, sorting/pagination, repository abstractions, exception handling, and more. Each module is published as a separate NuGet package so you only pull in what you need.


Prerequisites

  • .NET 9 SDK or later
  • An IDE such as Visual Studio, Rider, or VS Code with the C# extension

Available NuGet Packages

All packages share the same version (currently 9.1.4.1) and are published from the LimitlessSoft/LSCore repository.

Core / Infrastructure

Package Description
LSCore.Build Meta-package that references every LSCore library. Install this to pull in the entire framework at once.
LSCore.DependencyInjection Convention-based dependency injection resolution for the LSCore ecosystem. Scans assemblies by prefix and auto-registers services.
LSCore.Exceptions Typed exception classes (LSCoreNotFoundException, etc.) used across the framework.
LSCore.Exceptions.DependencyInjection Exception-handling middleware for ASP.NET Core. Converts LSCore exceptions into appropriate HTTP responses.
LSCore.Logging Logging infrastructure for ASP.NET Core applications.
LSCore.Common.Contracts Shared contracts and interfaces that have not yet been promoted to their own packages.
LSCore.Common.Extensions Shared extension methods that have not yet been promoted to their own packages.

Authentication – API Key

Package Description
LSCore.Auth.Contracts Base authentication contracts (e.g. [LSCoreAuth] attribute) shared by all auth modules.
LSCore.Auth.Key.Contracts Contracts for API-key authentication (LSCoreAuthKeyConfiguration, ILSCoreAuthKeyProvider).
LSCore.Auth.Key.DependencyInjection DI registration and middleware for API-key authentication.

Authentication – Username / Password (JWT)

Package Description
LSCore.Auth.UserPass.Contracts Contracts for username/password auth (ILSCoreAuthUserPassEntity, ILSCoreAuthUserPassManager, configuration).
LSCore.Auth.UserPass.DependencyInjection DI registration and JWT middleware for username/password authentication.
LSCore.Auth.UserPass.Domain Domain logic: LSCoreAuthUserPassManager, password hashing helpers, token generation.

Authentication – Role-Based

Package Description
LSCore.Auth.Role.Contracts Contracts for role-based authorization (ILSCoreAuthRoleEntity, [LSCoreAuthRole] attribute).
LSCore.Auth.Role.DependencyInjection DI registration and middleware for role-based authorization.
LSCore.Auth.Role.Domain Domain logic for role-based authorization.

Authentication – Permission-Based

Package Description
LSCore.Auth.Permission.Contracts Contracts for permission-based authorization (ILSCoreAuthPermissionEntity, [LSCoreAuthPermission] attribute).
LSCore.Auth.Permission.DependencyInjection DI registration and middleware for permission-based authorization.
LSCore.Auth.Permission.Domain Domain logic for permission-based authorization.

Object Mapping

Package Description
LSCore.Mapper.Contracts Mapper contract (ILSCoreMapper<TSource, TDestination>).
LSCore.Mapper.Domain Extension methods (ToMapped, ToMappedList) that resolve mappers through DI.

Validation

Package Description
LSCore.Validation.Contracts Validation contracts and the [LSCoreValidationMessage] attribute for enum-based validation codes.
LSCore.Validation.Domain LSCoreValidatorBase<T> base class and the .Validate() extension method. Built on FluentValidation.

Sorting and Pagination

Package Description
LSCore.SortAndPage.Contracts Contracts: LSCoreSortableAndPageableRequest, LSCoreSortedAndPagedResponse, LSCoreSortRule.
LSCore.SortAndPage.Domain Extension method ToSortedAndPagedResponse for IQueryable<T>.

Repository

Package Description
LSCore.Repository.Contracts Repository contracts and Entity Framework Core abstractions.
LSCore.Repository Repository implementations built on EF Core.

API Client

Package Description
LSCore.ApiClient.Rest REST API client for service-to-service communication.
LSCore.ApiClient.Rest.DependencyInjection DI registration for the REST API client.

Installation

Install packages from NuGet. For example, to add exception handling and API-key authentication:

dotnet add package LSCore.Exceptions.DependencyInjection
dotnet add package LSCore.Auth.Key.Contracts
dotnet add package LSCore.Auth.Key.DependencyInjection

Or, to install the entire framework at once:

dotnet add package LSCore.Build

Quick Start – Minimal API-Key Authenticated App

This example creates an ASP.NET Core API that protects selected endpoints with an API key. It mirrors the Sample.AuthKey.Api sample application.

1. Create the project

dotnet new webapi -n MyApp
cd MyApp
dotnet add package LSCore.Auth.Key.Contracts
dotnet add package LSCore.Auth.Key.DependencyInjection
dotnet add package LSCore.Exceptions.DependencyInjection

2. Configure Program.cs

using LSCore.Auth.Key.Contracts;
using LSCore.Auth.Key.DependencyInjection;
using LSCore.Exceptions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.AddLSCoreAuthKey(
    new LSCoreAuthKeyConfiguration
    {
        ValidKeys = ["my-secret-api-key-1", "my-secret-api-key-2"]
    }
);
var app = builder.Build();
app.UseLSCoreExceptionsHandler();
app.UseLSCoreAuthKey();
app.MapControllers();
app.Run();

3. Create a controller

using LSCore.Auth.Contracts;
using Microsoft.AspNetCore.Mvc;

public class ProductsController : ControllerBase
{
    [HttpGet]
    [Route("/products")]
    public IActionResult Get() => Ok("Public data -- no key required");

    [HttpGet]
    [LSCoreAuth]
    [Route("/products-auth")]
    public IActionResult GetAuth() => Ok("Protected data -- valid API key required");
}

Endpoints without [LSCoreAuth] are publicly accessible. Endpoints decorated with [LSCoreAuth] require a valid API key in the request.

See also: The Sample.AuthKey.Api sample application.


Setting Up Username/Password (JWT) Authentication

For login-based authentication with JWT tokens, use the LSCore.Auth.UserPass packages. This mirrors the Sample.AuthUserPass.Api sample application.

1. Install packages

dotnet add package LSCore.Auth.UserPass.Contracts
dotnet add package LSCore.Auth.UserPass.DependencyInjection
dotnet add package LSCore.Auth.UserPass.Domain
dotnet add package LSCore.Exceptions.DependencyInjection

2. Define a user entity

Your user entity must implement ILSCoreAuthUserPassEntity<TIdentifier>:

using LSCore.Auth.UserPass.Contracts;

public class UserEntity : ILSCoreAuthUserPassEntity<string>
{
    public long Id { get; set; }
    public string Username { get; set; }
    public string Identifier => Username;
    public string? RefreshToken { get; set; }
    public string Password { get; set; }
}

3. Implement the repository

Implement ILSCoreAuthUserPassIdentityEntityRepository<TIdentifier> to look up users and persist refresh tokens:

using LSCore.Auth.UserPass.Contracts;
using LSCore.Auth.UserPass.Domain;
using LSCore.Exceptions;

public class UserRepository : ILSCoreAuthUserPassIdentityEntityRepository<string>
{
    private static List<UserEntity> _users = [];

    public ILSCoreAuthUserPassEntity<string>? GetOrDefault(string identifier) =>
        _users.FirstOrDefault(x => x.Identifier == identifier);

    public void SetRefreshToken(string entityIdentifier, string refreshToken)
    {
        var user = _users.FirstOrDefault(x => x.Identifier == entityIdentifier);
        if (user == null)
            throw new LSCoreNotFoundException();
        user.RefreshToken = refreshToken;
    }
}

4. Create an auth manager

Extend LSCoreAuthUserPassManager<TIdentifier>:

using LSCore.Auth.UserPass.Contracts;
using LSCore.Auth.UserPass.Domain;

public class AuthManager(
    ILSCoreAuthUserPassIdentityEntityRepository<string> userPassIdentityEntityRepository,
    LSCoreAuthUserPassConfiguration configuration
) : LSCoreAuthUserPassManager<string>(userPassIdentityEntityRepository, configuration);

5. Wire up Program.cs

using LSCore.Auth.UserPass.Contracts;
using LSCore.Auth.UserPass.DependencyInjection;
using LSCore.Exceptions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.AddLSCoreAuthUserPass<string, AuthManager, UserRepository>(
    new LSCoreAuthUserPassConfiguration
    {
        SecurityKey = "your-secret-key-at-least-32-characters-long",
        Issuer = "MyApp",
        Audience = "MyApp"
    }
);
var app = builder.Build();
app.UseLSCoreExceptionsHandler();
app.UseLSCoreAuthUserPass<string>();
app.MapControllers();
app.Run();

6. Create a controller with login and protected endpoints

using LSCore.Auth.Contracts;
using LSCore.Auth.UserPass.Contracts;
using Microsoft.AspNetCore.Mvc;

public class UsersController(ILSCoreAuthUserPassManager<string> authPasswordManager)
    : ControllerBase
{
    [HttpPost]
    [Route("/login")]
    public IActionResult Login([FromBody] LoginRequest request) =>
        Ok(authPasswordManager.Authenticate(request.Username, request.Password));

    [HttpGet]
    [Route("/users")]
    public IActionResult Get() => Ok("Public data");

    [HttpGet]
    [LSCoreAuth]
    [Route("/users-auth")]
    public IActionResult GetAuth() => Ok("Protected data -- valid JWT required");
}

See also: The Sample.AuthUserPass.Api sample application.


Adding Role-Based Authorization

Build on top of username/password auth by adding role checks. This mirrors the Sample.AuthRole.Api sample application.

1. Install additional packages

dotnet add package LSCore.Auth.Role.Contracts
dotnet add package LSCore.Auth.Role.DependencyInjection

2. Define a role enum

public enum UserRole
{
    User,
    Administrator
}

3. Extend the user entity

using LSCore.Auth.Role.Contracts;
using LSCore.Auth.UserPass.Contracts;

public class UserEntity : ILSCoreAuthUserPassEntity<string>, ILSCoreAuthRoleEntity<string, UserRole>
{
    public long Id { get; set; }
    public UserRole Role { get; set; } = UserRole.User;
    public string Username { get; set; }
    public string Identifier => Username;
    public string? RefreshToken { get; set; }
    public string Password { get; set; }
}

4. Extend the repository

The repository must also implement ILSCoreAuthRoleIdentityEntityRepository<string, UserRole>:

public class UserRepository
    : ILSCoreAuthUserPassIdentityEntityRepository<string>,
      ILSCoreAuthRoleIdentityEntityRepository<string, UserRole>
{
    // ... existing methods ...

    public ILSCoreAuthRoleEntity<string, UserRole>? GetOrDefault(string identifier) =>
        _users.FirstOrDefault(x => x.Identifier == identifier);
}

5. Register in Program.cs

builder.AddLSCoreAuthUserPass<string, AuthManager, UserRepository>(
    new LSCoreAuthUserPassConfiguration { /* ... */ }
);
builder.AddLSCoreAuthRole<string, UserRole, UserRepository>();

// ...

app.UseLSCoreAuthUserPass<string>();
app.UseLSCoreAuthRole<string, UserRole>();

6. Protect endpoints by role

using LSCore.Auth.Contracts;
using LSCore.Auth.Role.Contracts;

// Any authenticated user
[LSCoreAuth]
[Route("/users-auth-any-role")]
public IActionResult GetAnyRole() => Ok("Any authenticated user can see this");

// Only administrators
[LSCoreAuthRole<UserRole>(UserRole.Administrator)]
[Route("/users-auth-administrator-role")]
public IActionResult GetAdministratorRole() => Ok("Administrators only");

See also: The Sample.AuthRole.Api sample application.


Adding Permission-Based Authorization

Permission-based auth works similarly to roles, but allows assigning multiple granular permissions per user. This mirrors the Sample.AuthPermission.Api sample application.

1. Define a permission enum

public enum UserPermission
{
    Permission_One,
    Permission_Two,
    Permission_Three
}

2. Implement the entity

using LSCore.Auth.Permission.Contracts;
using LSCore.Auth.UserPass.Contracts;

public class UserEntity
    : ILSCoreAuthUserPassEntity<string>,
      ILSCoreAuthPermissionEntity<string, UserPermission>
{
    public long Id { get; set; }
    public ICollection<UserPermission> Permissions { get; set; } = [];
    public string Username { get; set; }
    public string Identifier => Username;
    public string? RefreshToken { get; set; }
    public string Password { get; set; }
}

3. Register in Program.cs

builder.AddLSCoreAuthUserPass<string, AuthManager, UserRepository>(/* ... */);
builder.AddLSCoreAuthPermission<string, UserPermission, UserRepository>();

// ...

app.UseLSCoreAuthUserPass<string>();
app.UseLSCoreAuthPermission<string, UserPermission>();

4. Protect endpoints by permission

using LSCore.Auth.Permission.Contracts;

// Require ALL listed permissions (default behavior)
[LSCoreAuthPermission<UserPermission>(
    UserPermission.Permission_One,
    UserPermission.Permission_Two
)]
[Route("/users-auth-all-permissions")]
public IActionResult GetHasPermissions() =>
    Ok("User must have all of the permissions to see this");

// Require ANY of the listed permissions (pass false as first argument)
[LSCoreAuthPermission<UserPermission>(
    false,
    UserPermission.Permission_One,
    UserPermission.Permission_Two,
    UserPermission.Permission_Three
)]
[Route("/users-auth-any-permission")]
public IActionResult GetAnyPermission() =>
    Ok("User must have any of the permissions to see this");

See also: The Sample.AuthPermission.Api sample application.


Combining Multiple Auth Strategies

You can layer API-key and username/password auth on the same application. Set BreakOnFailedAuth = false on the first strategy so that if it fails, the next strategy gets a chance. This mirrors the Sample.AuthCombined.Api sample application.

using LSCore.Auth.Key.Contracts;
using LSCore.Auth.Key.DependencyInjection;
using LSCore.Auth.UserPass.Contracts;
using LSCore.Auth.UserPass.DependencyInjection;
using LSCore.Exceptions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.AddLSCoreAuthKey(
    new LSCoreAuthKeyConfiguration
    {
        ValidKeys = ["ThisIsFirstValidKey", "ThisIsSecondValidKey"],
        BreakOnFailedAuth = false  // Allow fallthrough to next auth strategy
    }
);
builder.AddLSCoreAuthUserPass<string, AuthManager, UserRepository>(
    new LSCoreAuthUserPassConfiguration
    {
        SecurityKey = "your-secret-key-at-least-32-characters-long",
        Audience = "MyApp",
        Issuer = "MyApp",
    }
);
var app = builder.Build();
app.UseLSCoreExceptionsHandler();
app.MapControllers();
app.UseLSCoreAuthKey();
app.UseLSCoreAuthUserPass<string>();
app.Run();

A request will succeed if it passes either API-key auth or JWT auth.

See also: The Sample.AuthCombined.Api sample application.


Adding Validation

LSCore validation is built on FluentValidation with additional conventions. This mirrors the Sample.Validation.Api sample application.

1. Install packages

dotnet add package LSCore.Validation.Domain
dotnet add package LSCore.Exceptions.DependencyInjection

2. Define a request class

public class UserRegisterRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Use enums with [LSCoreValidationMessage] to keep error messages centralized:

using LSCore.Validation.Contracts;

public enum UsersValidationCodes
{
    [LSCoreValidationMessage("Password must contain only letters and numbers.")]
    UVC_001,

    [LSCoreValidationMessage("Password must contains at least one number and one letter.")]
    UVC_002
}

4. Create a validator

Extend LSCoreValidatorBase<T>:

using System.Text.RegularExpressions;
using FluentValidation;
using LSCore.Validation.Contracts;
using LSCore.Validation.Domain;

public class UserRegisterRequestValidator : LSCoreValidatorBase<UserRegisterRequest>
{
    const int MIN_PASSWORD_LENGTH = 8;
    const string PASSWORD_REGEX_ONLY_LETTERS_AND_NUMBERS = @"^[A-Za-z\d]+$";
    const string PASSWORD_REGEX_AT_LEAST_ONE_LETTER_AND_ONE_NUMBER = @"^(?=.*[A-Za-z])(?=.*\d).+$";
    const int MIN_USERNAME_LENGTH = 5;
    const int MAX_USERNAME_LENGTH = 20;

    public UserRegisterRequestValidator()
    {
        RuleFor(x => x.Username)
            .NotEmpty()
            .MinimumLength(MIN_USERNAME_LENGTH)
            .MaximumLength(MAX_USERNAME_LENGTH);

        RuleFor(x => x.Password)
            .NotEmpty()
            .MinimumLength(MIN_PASSWORD_LENGTH)
            .Must(x => Regex.IsMatch(x, PASSWORD_REGEX_ONLY_LETTERS_AND_NUMBERS))
            .WithMessage(UsersValidationCodes.UVC_001.GetValidationMessage())
            .Must(x => Regex.IsMatch(x, PASSWORD_REGEX_AT_LEAST_ONE_LETTER_AND_ONE_NUMBER))
            .WithMessage(UsersValidationCodes.UVC_002.GetValidationMessage());
    }
}

5. Register with auto-DI and call .Validate()

// Program.cs
using LSCore.DependencyInjection;
using LSCore.Exceptions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.AddLSCoreDependencyInjection("Sample.Validation"); // auto-discovers validators
var app = builder.Build();
app.UseLSCoreDependencyInjection();
app.UseLSCoreExceptionsHandler();
app.MapControllers();
app.Run();

In the controller, call request.Validate() – it throws an exception (handled by the exception middleware) if validation fails:

using LSCore.Validation.Domain;
using Microsoft.AspNetCore.Mvc;

public class UsersController : ControllerBase
{
    [HttpPost]
    [Route("/register")]
    public IActionResult Register([FromBody] UserRegisterRequest request)
    {
        request.Validate();
        return Ok("User successfully registered!");
    }
}

See also: The Sample.Validation.Api and Sample.ValidationWithRepository.Api sample applications.


Validation with Repository Access

If your validator needs to query the database (e.g. to check for duplicate usernames), inject a repository into the validator constructor. This mirrors the Sample.ValidationWithRepository.Api sample application.

using FluentValidation;
using LSCore.Validation.Domain;

public class UserRegisterRequestValidator : LSCoreValidatorBase<UserRegisterRequest>
{
    public UserRegisterRequestValidator(IUserRepository userRepository)
    {
        RuleFor(x => x.Username)
            .Must(username => userRepository.UsernameOccupied(username) == false)
            .WithMessage("User with given username already exists");
    }
}

Note: Validators are typically registered as singleton or transient. If your repository depends on a scoped DbContext, use a factory pattern to create the context inside the validator.


Object Mapping

LSCore provides a lightweight, convention-based mapper that resolves through DI. This mirrors the Sample.Mapper.Api sample application.

1. Install packages

dotnet add package LSCore.Mapper.Domain
dotnet add package LSCore.DependencyInjection

2. Define your entity and DTO

// Entity
public class ProductEntity
{
    public long Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedAt { get; set; }
    public bool IsActive { get; set; }
}

// DTO
public class ProductDto
{
    public long Id { get; set; }
    public string Name { get; set; }
}

3. Create a mapper

Implement ILSCoreMapper<TSource, TDestination>:

using LSCore.Mapper.Contracts;

public class ProductDtoMapper : ILSCoreMapper<ProductEntity, ProductDto>
{
    public ProductDto ToMapped(ProductEntity source) =>
        new() { Id = source.Id, Name = source.Name };
}

4. Use the mapper

The ToMapped and ToMappedList extension methods resolve the mapper through DI automatically:

using LSCore.Mapper.Domain;

public class ProductManager(IProductRepository productRepository) : IProductManager
{
    public ProductDto Get(int id) =>
        productRepository.Get(id).ToMapped<ProductEntity, ProductDto>();

    public List<ProductDto> GetAll() =>
        productRepository.GetAll().ToMappedList<ProductEntity, ProductDto>();
}

5. Register with auto-DI

using LSCore.DependencyInjection;
using LSCore.Exceptions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.AddLSCoreDependencyInjection("Sample.Mapper"); // auto-discovers mappers, repos, managers
var app = builder.Build();
app.UseLSCoreDependencyInjection();
app.UseLSCoreExceptionsHandler();
app.MapControllers();
app.Run();

See also: The Sample.Mapper.Api sample application.


Sorting and Pagination

LSCore provides a convention for sorted, paginated API responses. This mirrors the Sample.SortAndPage.Api sample application.

1. Install packages

dotnet add package LSCore.SortAndPage.Contracts
dotnet add package LSCore.SortAndPage.Domain
dotnet add package LSCore.Mapper.Domain

2. Define sort columns

public enum ProductsSortColumn
{
    Id,
    Name
}

3. Define sort rules

Map each enum value to a property expression on your entity:

using LSCore.SortAndPage.Contracts;

public static class SortColumnRules
{
    public static Dictionary<ProductsSortColumn, LSCoreSortRule<ProductEntity>>
        ProductsSortColumnCodesRules = new()
        {
            { ProductsSortColumn.Id, new LSCoreSortRule<ProductEntity>(x => x.Id) },
            { ProductsSortColumn.Name, new LSCoreSortRule<ProductEntity>(x => x.Name) }
        };
}

4. Create a sortable/pageable request

Extend LSCoreSortableAndPageableRequest<TSortColumn>:

using LSCore.SortAndPage.Contracts;

public class ProductsGetAllRequest : LSCoreSortableAndPageableRequest<ProductsSortColumn>;

5. Apply sorting and pagination

Use ToSortedAndPagedResponse on an IQueryable<T>:

using LSCore.Mapper.Domain;
using LSCore.SortAndPage.Domain;

public class ProductManager(IProductRepository productRepository) : IProductManager
{
    public LSCoreSortedAndPagedResponse<ProductDto> GetAll(ProductsGetAllRequest request) =>
        productRepository
            .GetAll()
            .ToSortedAndPagedResponse<ProductEntity, ProductsSortColumn, ProductDto>(
                request,
                SortColumnRules.ProductsSortColumnCodesRules,
                x => x.ToMapped<ProductEntity, ProductDto>()
            );
}

6. Expose via controller

[HttpGet]
[Route("/products")]
public IActionResult GetAll([FromQuery] ProductsGetAllRequest request) =>
    Ok(productManager.GetAll(request));

See also: The Sample.SortAndPage.Api sample application.


Auto-Discovery with AddLSCoreDependencyInjection

Several sample apps use AddLSCoreDependencyInjection to automatically discover and register:

  • Services (interfaces to implementations)
  • Validators
  • Mappers

Pass your assembly name prefix so LSCore knows which assemblies to scan:

builder.AddLSCoreDependencyInjection("MyApp");

Then activate it on the app:

app.UseLSCoreDependencyInjection();

This removes the need to manually register every IProductRepository -> ProductRepository pair, every ILSCoreMapper<,> implementation, and every LSCoreValidatorBase<> subclass.


Typical Full Program.cs

Here is a realistic Program.cs that combines authentication, validation, mapping, exception handling, and auto-DI:

using LSCore.Auth.UserPass.Contracts;
using LSCore.Auth.UserPass.DependencyInjection;
using LSCore.Auth.Role.DependencyInjection;
using LSCore.DependencyInjection;
using LSCore.Exceptions.DependencyInjection;

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

// Auto-register services, validators, and mappers from assemblies matching the prefix
builder.AddLSCoreDependencyInjection("MyApp");

// Configure JWT authentication
builder.AddLSCoreAuthUserPass<string, AuthManager, UserRepository>(
    new LSCoreAuthUserPassConfiguration
    {
        SecurityKey = builder.Configuration["Auth:SecurityKey"]!,
        Issuer = builder.Configuration["Auth:Issuer"]!,
        Audience = builder.Configuration["Auth:Audience"]!
    }
);

// Configure role-based authorization
builder.AddLSCoreAuthRole<string, UserRole, UserRepository>();

var app = builder.Build();

// Exception handling middleware -- converts LSCore exceptions to HTTP responses
app.UseLSCoreExceptionsHandler();

// Activate auto-DI
app.UseLSCoreDependencyInjection();

// Auth middleware
app.UseLSCoreAuthUserPass<string>();
app.UseLSCoreAuthRole<string, UserRole>();

app.MapControllers();
app.Run();

Custom API-Key Provider

Instead of hardcoding valid keys, you can implement ILSCoreAuthKeyProvider to load keys from a database, configuration, or any other source. This mirrors the Sample.AuthKeyProvider.Api sample application.

using LSCore.Auth.Key.Contracts;

public class MyKeyProvider : ILSCoreAuthKeyProvider
{
    public bool IsValidKey(string key)
    {
        // Inject database, configuration, or any other source to validate keys
        return true;
    }
}

Register it with the generic overload:

builder.AddLSCoreAuthKey<MyKeyProvider>(); // Registered as a scoped service

Next Steps


LSCore is free and open-source.