Multi-Tenant Applications with ASP.NET Core 2.2 - Getting Started
Tags: dotnet, dotnetcore, multitenant, aspnet
Published: 2019-08-17 19:01:45

---
title: Multi-Tenant Applications with ASP.NET Core 2.2 - Getting Started
published: true
description: Setting the foundation for Multi-Tenant Applications with ASP.NET Core 2.2
tags: dotnet, dotnet core, multi-tenant, aspnet
series: Multi-Tenant Applications with ASP.NET Core 2.2
---

As software as a service has been more ubiquitous, multi-tenancy has become a basic requirement of most web applications. This series will outline how I accomplish this in a .NET Core Web Application.

While this post is mostly a self-documentation exercise so I don't forget this next time, hopefully it helps someone else with similar needs. I'll be focusing on the latest stable version of .NET Core, currently 2.2 and hopefully updating for .NET Core 3 once it moves to GA.

I've started off with Visual Studio 2019 and used the ASP.NET Core Web Application template configured with Razor Pages and Individual User Accounts. While I like what ASP.NET Identity brings in terms of functionality, I don't like that they still use `GUID` for the primary keys. 

First things first, I change the `IdentityUser` to use `int` or `long` as a primary key. You can [follow this blog entry](https://adrientorris.github.io/aspnet-core/identity/extend-user-model.html) on extending the `IdentityUser` but add in your preferred data type.

So instead of 

```csharp
public class ApplicationUser : IdentityUser
{
    ...
}
```

use this

```csharp
public class ApplicationUser : IdentityUser<long>
{
    ...
}
```

And everywhere you override `IdentityUser` insert `IdentityUser<long>` instead.

Now, while you can use any method you prefer to identity tenants in your application, I prefer to use sub-domains. The first thing we will do is inject the current sub-domain into our `HttpContext`.

Create a new class using Add => New Item by right clicking in the solution explorer. Find the Middleware Class entry and name it TenantInjector or whatever you prefer.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/jnfs83leg6j5grssggkm.JPG)

This gives us a basic Middleware class we can extend. Notice the `Invoke` method:

```csharp
public Task Invoke(HttpContext httpContext)
{
	return _next(httpContext);
}
```

We will do two things here. First, make it `async`. Second, add some logic to make the current sub-domain available as `CurrentTenant` property in the `HttpContext`.

```csharp
public async Task Invoke(HttpContext httpContext)
{
	var tenant = string.Empty;

	if (httpContext.Request.Host.Host.Contains("."))
	{
		tenant = httpContext.Request.Host.Host.Split('.')[0].ToLowerInvariant();
		httpContext.Items.Add("CURRENT_TENANT", tenant);
	}
	else
	{
		httpContext.Items.Add("CURRENT_TENANT", httpContext.Request.Host.Host);
	}
	
	await _next(httpContext);
}
```

Notice how we use `async Task` instead of just `Task` and replaced `return` with `await`.

In the rest of our logic, we extract the sub-domain if it exists or just use the TLD if no sub-domain is present.

So:
```
demo.domain.com    => tenant of "demo".
domain.com         => tenant of "domain".
localhost:4433     => tenant of "localhost".
```

To make development easier I add some entries to my HOST file:
```
127.0.0.1	demo.domain.com
127.0.0.1	demo2.domain.com
```

Now we can go over to our `Startup.cs` and add the following line to the `Configure` method:

```csharp
app.UseTenantInjector();
```
So now we can access the current tenant in any of our controllers by using `HttpContext.Items["CURRENT_TENANT"].ToString()`.

I do like dependency injection myself, so let's go ahead and refactor this to use a service.

Lets add a new interface `ITenantResolver` and class `TenantResolver`. They should look something like this:

```csharp
public interface ITenantResolver
{
	string CurrentTenant();
}

public class TenantResolver : ITenantResolver
{
	private readonly IHttpContextAccessor _httpContextAccessor;

	public TenantResolver(IHttpContextAccessor httpContextAccessor)
	{
		_httpContextAccessor = httpContextAccessor;
	}

	private string Current_Tenant { get; set; }

	public void SetTenant()
	{
		_httpContextAccessor.HttpContext.Items.TryGetValue(Const.CURRENT_TENANT, out object currentTenant);
		if (currentTenant != null)
		{
			Current_Tenant = currentTenant.ToString();
		}
	}

	public string CurrentTenant()
	{
		if (string.IsNullOrEmpty(Current_Tenant))
		{
			SetTenant();
		}
		return Current_Tenant;
	}
}

```

Wire it up to the DI Container:

```csharp
services.AddScoped<ITenantResolver, TenantResolver>();
```

Now we can simply inject our `TenantResolver` wherever we need it.

```html
@inject  ITenantResolver tenantResolver
<p>Current Tenant = @tenantResolver.CurrentTenant()</p>
```

In the next post we will modify our `Login` method to ensure the current user has access to the current domain by using `Claims`.