Building Multi-Tenant Web API in .NET following Clean Architecture
Building a strong multi-tenant architecture is important for scalability, security, and efficiency in the world of Software as a Service (SaaS) apps. This post looks at how .NET Core, EF Core, and Clean Architecture can be used to build a web API that can be used by more than one client. By using the power of .NET Core and taking a clean, modular approach, developers can make apps that are easy to maintain and can grow to meet the needs of multiple tenants. In this post, we'll take a deeper look at the idea of multitenancy, talk about the pros and cons of multi-tenant architectures, and show you step-by-step how to build one in .NET Core.
Understanding Multitenancy
Let's start by looking at what multitenancy means in the context of SaaS apps. Multitenancy means that a single instance of the software can serve multiple clients or renters while keeping their data and settings separate. It lets businesses use the same infrastructure and tools, which saves money and makes it easier to grow. You can read the Wikipedia page on multitenancy to learn more about it.
Benefits and Limitations of Multi-Tenant Architectures
Multi-tenant architectures have many benefits, such as being cost-effective, scalable, having updates and upkeep done in one place, being able to customize and personalise, and making good use of resources.
But it's important to think about the downsides as well, such as data isolation
security, speed issues, complexity, and problems with upgrades and compatibility.
Refer to this blog post that talks about these pros and cons for a full look at them.
The Best Architecture for .NET Core Web APIs
Clean Architecture is considered to be one of the best ways to build .NET Core web APIs. It helps keep things separate, makes things easy to fix, and makes things easy to test. By following the Clean Architecture concepts, developers can make APIs that are modular and scalable. You can look at the idea of Hexagonal Architecture to learn more about "Clean Architecture" and its perks.
Step-by-Step Guide to Building a Multi-Tenant Web API in .NET Core
In this part, we'll show you how to use .NET Core, EF Core, and Clean Architecture to build a multi-tenant web API step by step. This guide is written for people who know the basics of .NET Core and EF Core. Here are the most important steps:
Explain what a "multi-tenant structure" is: In the context of a software application, a multi-tenant structure refers to the architectural design and organization that enables a single instance of the application to serve multiple clients or tenants. Each tenant is a distinct entity with its own data, configurations, and user base, while sharing the same underlying infrastructure and resources.
The multi-tenant structure determines how the application segregates and manages the data and configurations of each tenant. There are several approaches to implementing a multi-tenant structure, such as separate databases, shared databases with data isolation, or shared schema with tenant identifiers.
Set up the project's structure: Create a new .NET Core project and set it up using the Clean Architecture principles, with different layers for presentation, application, domain, and infrastructure.
Implement Tenant identity: Choose a method for identifying tenants, such as URL-based or header-based identity, and set up the middleware or filters needed to get the tenant information.
One Nuget package will be very much helpful here which is finbuckle. Please check this link for Configuration and UsageWe have to select a multitenant strategy. A multitenant strategy is responsible for defining how the tenant is determined. More details are provided here.
Design the Database Schema: When designing the database schema, you should think about things like tenant-specific tables and shared tables so that it can serve multiple tenants. You can do this with either a table-per-tenant or a table-per-schema method with EF Core.
Set up Data Access with EF Core: Use EF Core to set up data access and separate data between renters. You can use methods like dynamic connection strings or different schemas for each tenant.
public class TenantDbContext : EFCoreStoreDbContext<CPTenantInfo> { public TenantDbContext(DbContextOptions<TenantDbContext> options) : base(options) { AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<CPTenantInfo>().ToTable("Tenants", SchemaNames.MultiTenancy); } }
Implement Tenant-Specific Behaviour: Take care of tenant-specific business logic and customizations, such as personalized settings, feature toggles, and branding choices.
Manage Tenant Configuration: Store and control tenant-specific configurations, like connection strings or settings, safely. Consider choices like environment variables, configuration files, or a separate configuration database.
public class CurrentUser : ICurrentUser, ICurrentUserInitializer { private ClaimsPrincipal? _user; public string? Name => _user?.Identity?.Name; private Guid _userId = Guid.Empty; public Guid GetUserId() => IsAuthenticated() ? Guid.Parse(_user?.GetUserId() ?? Guid.Empty.ToString()) : _userId; public string? GetUserEmail() => IsAuthenticated() ? _user!.GetEmail() : string.Empty; public bool IsAuthenticated() => _user?.Identity?.IsAuthenticated is true; public bool IsInRole(string role) => _user?.IsInRole(role) is true; public IEnumerable<Claim>? GetUserClaims() => _user?.Claims; public string? GetTenant() => IsAuthenticated() ? _user?.GetTenant() : MultitenancyConstants.Root.Id; public string? GetUserRoleEnumValue() => IsAuthenticated() ? _user!.GetRoleEnumValue() : string.Empty; public void SetCurrentUser(ClaimsPrincipal user) { if (_user != null) { throw new Exception("Method reserved for in-scope initialization"); } _user = user; } public void SetCurrentUserId(string userId) { if (_userId != Guid.Empty) { throw new Exception("Method reserved for in-scope initialization"); } if (!string.IsNullOrEmpty(userId)) { _userId = Guid.Parse(userId); } } }
Ensure Security and Isolation: Use methods like authentication, permission, and data segregation to protect tenant data.
public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement> { private readonly IUserService _userService; public PermissionAuthorizationHandler(IUserService userService) => _userService = userService; protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) { if (context.User?.GetUserId() is { } userId && await _userService.HasPermissionAsync(userId, requirement.Permission)) { context.Succeed(requirement); } } }
Conclusion
Building a multi-tenant web API in .NET Core using EF Core and Clean Architecture principles offers a scalable, secure, and maintainable solution for SaaS applications. By understanding the concept of multitenancy, leveraging the benefits while mitigating the limitations, and following a step-by-step guide, developers can establish a solid foundation for their multi-tenant applications.
Incorporating .NET Core's features, EF Core's data access capabilities, and adhering to Clean Architecture principles ensure the development of modular, testable, and extensible APIs. With careful planning and implementation, building a multi-tenant web API in .NET Core becomes an efficient and effective process for catering to multiple tenants in a SaaS environment.
For more such articles please visit - https://www.atharvasystem.com/
About Atharva System
Subscribe to my newsletter
Read articles from Tejas Mehta directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Tejas Mehta
Tejas Mehta
Tejas Mehta is a highly accomplished Software Development Manager at Atharva System, bringing extensive expertise in leading and delivering exceptional software solutions. With a proven track record of success, Tejas excels in coordinating cross-functional teams and driving innovation throughout the development lifecycle. Known for his strategic mindset and meticulous attention to detail, he consistently delivers projects on time and within budget, exceeding client expectations. Tejas possesses a deep understanding of industry best practices and leverages cutting-edge technologies to optimize software development processes. His exceptional leadership skills and passion for technology make him an invaluable asset to Atharva System's success. Know more about Atharva System at : https://www.atharvasystem.com/