Giter Site home page Giter Site logo

pub-dev / mellon.multitenant Goto Github PK

View Code? Open in Web Editor NEW
37.0 3.0 3.0 133 KB

A library created to help with multi-tenant applications made in net

Home Page: https://pub-dev.github.io/Mellon.MultiTenant

License: MIT License

C# 100.00%
dotnet multitenant scharp dotnet-core multi-tenant multi-tenant-applications pub-dev pubdev azure-app-configuration configuration-loader hangfire hangfire-dotnet-core hangfire-extension spring-cloud-config-dotnet hangfire-multitenant

mellon.multitenant's Issues

migrate to .net8

Migrate to .net8 and adjust the code to use new C# 12 features

Integrating Mellon.MultiTenant with Hangfire in ASP.NET Core

Hi,
I'm trying to integrate Mellon.MultiTenant into my existing multi-tenant setup with Hangfire. Could you provide guidance or examples on how to properly configure Mellon.MultiTenant with Hangfire? Specifically, I'm looking for help on how to ensure that Hangfire uses the correct connection string for each tenant.
I have 2 connection strings, Web is my default connection string when a tenant is not available, and Tenant stores all connection strings for every tenant, and i store all tenant in database,

Thank you in advance for your assistance!

appsetting:

{ "ConnectionStrings": { "Web": "Server=xxxx", "Tenant": "Server=xxx" } }

TenantModel:

`
```
public class Tenant : BaseEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string? Host { get; set; }
public string SubDomain { get; set; } = null!;
public string ConnectionString { get; set; }
}

`

ITenantService:

` ```
 public interface ITenantService
   {
    Task IdentifyTenant(HttpContext context);
    Task<IEnumerable<Entities.Tenant.Tenant>> GetAllTenantsAsync();
    IEnumerable<Entities.Tenant.Tenant> GetAllTenants();
    Guid? GetTenantId(HttpContext context);
    string? GetTenantIdString(HttpContext context);
    Task<Entities.Tenant.Tenant> CreateTenantAsync(Entities.Tenant.Tenant tenant);
    Task<Entities.Tenant.Tenant> GetTenantByIdAsync(Guid id);
    string GetTenantConnectionString(HttpContext context);
    Task<Entities.Tenant.Tenant> GetCurrentTenantAsync(HttpContext context);
    void SetTenant(Entities.Tenant.Tenant tenant);
    string GetCurrentTenantConnectionString();
    Guid GetCurrentTenantId();
    string GetCurrentTenantIdString();
    Entities.Tenant.Tenant GetCurrentTenant();
    Task<Entities.Tenant.Tenant> GetCurrentTenantAsyncCaching(HttpContext context);
    string GetConnectionStringByTenantId(Guid tenantId);
    string GetDatabaseProvider();
    }

TenantResolutionMiddleware:

app.UseMiddleware<TenantResolutionMiddleware>();

` public class TenantResolutionMiddleware
{
private readonly RequestDelegate _next;

public TenantResolutionMiddleware(RequestDelegate next)
{
    _next = next;
}

public async Task InvokeAsync(HttpContext context, ITenantService tenantService)
{
    try
    {
        await tenantService.IdentifyTenant(context);
        var tenant = await tenantService.GetCurrentTenantAsync(context);
        if (tenant != null)
        {
            context.Items["ConnectionString"] = tenant.ConnectionString;
            context.Items["TenantConnectionString"] = tenant.ConnectionString;
            context.Items["TenantId"] = tenant.Id;
        }
        else
        {
            var defaultConnectionString = context.RequestServices.GetRequiredService<IConfiguration> 
                    ().GetConnectionString("Web");
            context.Items["ConnectionString"] = defaultConnectionString;
            context.Items["TenantConnectionString"] = defaultConnectionString;
        }
    }
    catch (Exception ex)
    {
        context.Response.StatusCode = 500; // Internal Server Error
        await context.Response.WriteAsync("An error occurred while identifying the tenant.");
        return;
    }
    await _next(context);
}

}`

InitializeTenantDatabases Middleware:

app.InitializeTenantDatabase(); app.InitializeTenantDatabases();

`public static class TenantDatabaseInitializer
{
public static void InitializeTenantDatabases(this WebApplication app)
{
using var scope = app.Services.CreateScope();
var tenantService = scope.ServiceProvider.GetRequiredService();

    var tenants = tenantService.GetAllTenants();

    foreach (var tenant in tenants)
    {
        using var tenantScope = app.Services.CreateScope();
        var dbContext = tenantScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

        dbContext.Database.SetConnectionString(tenant.ConnectionString);
        dbContext.Database.Migrate();

        var dataInitializers = tenantScope.ServiceProvider.GetServices<IDataInitializer>();
        foreach (var dataInitializer in dataInitializers)
            dataInitializer.InitializeData();
    }
}

public static IApplicationBuilder InitializeTenantDatabase(this IApplicationBuilder app)
{
    using var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope();
    var dbContext = scope.ServiceProvider.GetService<TenantDbContext>(); // Service locator
    dbContext.Database.Migrate();
    return app;
}

}
`
Tenant Services:

builder.Services.AddTenantServices(builder.Configuration); builder.Services.AddDynamicDbContexts(builder.Configuration);

`public static class ServiceCollectionExtensions
{
public static IServiceCollection AddTenantServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext(options =>
options.UseSqlServer(configuration.GetConnectionString("Tenant")));

    services.AddScoped<ITenantService, TenantService>();
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddMemoryCache();
    services.AddLogging();

    return services;
}

public static IServiceCollection AddDynamicDbContexts(this IServiceCollection services, IConfiguration configuration)
{
    services.AddHttpContextAccessor();
    services.AddDbContext<ApplicationDbContext>((serviceProvider, options) =>
    {
        var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
        var connectionString = httpContextAccessor.HttpContext?.Items["ConnectionString"] as string
                              ?? configuration.GetConnectionString("Web");
        options.UseSqlServer(connectionString);
    });

    return services;
}

}`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.