Multi-tenant ASP.NET Core 1 - Implementing tenant provider

gpeipman
1,020 views

Open Source Your Knowledge, Become a Contributor

Technology knowledge has to be shared and made accessible for free. Join the movement.

Create Content

Implementing tenant provider

Multi-tenant web applications need the way how to find out the current tenant. This example shows how to implement and apply simple tenant provider to filter out current tenant enitites in database context.

As there can be multiple implementations of tenant providers we start with defining interface for tenant providers.

public interface ITenantProvider
{
    Guid GetTenantId();
}

For demo purposes we need also some example entity. Let it be Person entity with tenant ID field.

public class Person
{
    [Key]
    public Guid Id { get; set; }
    public Guid TenantId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

We also need database context that uses tenant provider. Here is sample context that keeps known tenant ID-a for demo purposes. Notice how tenant provider is injected to context through constructor and how Entity Framework Core 2 global query filters are used to filter out people by current tenant.

public class MultitenantDbContext : DbContext
{
    public static Guid Tenant1Id = Guid.Parse("51aab199-1482-4f0d-8ff1-5ca0e7bc525a");
    public static Guid Tenant2Id = Guid.Parse("ae4e21fa-57cb-4733-b971-fdd14c4c667e");

    public DbSet<Person> People { get; set; }

    private ITenantProvider _tenantProvider;

    public MultitenantDbContext(DbContextOptions<MultitenantDbContext> options,
                                ITenantProvider tenantProvider) : base(options)
    {
        _tenantProvider = tenantProvider;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Person>().HasQueryFilter(p => p.TenantId == _tenantProvider.GetTenantId());
    }

    public void AddSampleData()
    {
        People.Add(new Person {
            Id = Guid.Parse("79865406-e01b-422f-bd09-92e116a0664a"),
            TenantId = Tenant1Id,
            FirstName = "Gunnar",
            LastName = "Peipman"
        });

        People.Add(new Person
        {
            Id = Guid.Parse("d5674750-7f6b-43b9-b91b-d27b7ac13572"),
            TenantId = Tenant2Id,
            FirstName = "John",
            LastName = "Doe"
        });

        People.Add(new Person
        {
            Id = Guid.Parse("e41446f9-c779-4ff6-b3e5-752a3dad97bb"),
            TenantId = Tenant1Id,
            FirstName = "Mary",
            LastName = "Jones"
        });

        SaveChanges();
    }
}

Before going to demo we need also implementation for tenant provider. Here I give dummy tenant provider that always returns same tenant ID.

public class DummyTenantProvider : ITenantProvider
{
    public Guid GetTenantId()
    {
        return MultitenantDbContext.Tenant1Id;
    }
}

Demo

Click to run the .NET Core Web app.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using MultitenantAspNetCore.Models;
namespace MultitenantAspNetCore.Controllers
{
public class HomeController : Controller
{
private readonly MultitenantDbContext _context;
public HomeController(MultitenantDbContext context)
{
_context = context;
_context.AddSampleData();
}
public IActionResult Index()
{
var model = _context.People.ToList();
return View(model);
}
public IActionResult Error()
{
return View();
}
}
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

References

Open Source Your Knowledge: become a Contributor and help others learn. Create New Content