gpt4 book ai didi

rest - 如何根据客户端调用实现具有多个数据库的Web API

转载 作者:行者123 更新时间:2023-12-04 03:10:54 25 4
gpt4 key购买 nike

我必须为一个系统创建一个 RESTful Web API(我正在使用 ASP.NET Core 1.1),这可能有点不寻常,因为每个使用该系统的客户端都有自己的数据库。 (客户就像一家公司,里面有很多用户)。所以有一个主数据库,它为每个客户端指定它必须连接到哪个数据库。所有客户的数据库都是相同的(当然数据除外)。

我想知道我应该如何处理这个...通常,当应用程序使用 Web API 时,您可能会遇到类似这样的情况:

public class AccountsController : Controller
{
private readonly SomeContext _context;

public FilesController(SomeContext context)
{
_context = context;
}

// GET: api/Files
[HttpGet)]
public IEnumerable<Account> GetAccounts()
{
return _context.Accounts;
}
}

现在,在上面的示例中,问题是上下文必须指向不同的数据库,这取决于哪个客户端正在请求帐户列表。我不确定如何最好地解决这个问题。如果前端在每次 API 调用时在查询字符串中发送一个客户端标识符,是否可以?所以每个 Controller Action 都会有一个 ClientId 参数。并且基于此参数,该操作会在调用它之前即时修改 Context 的连接字符串?不过,这听起来很糟糕——无论是从实现还是安全的角度来看。问题是,据我所知,ASP.NET 是无状态的,因此每次调用 API 时,API 都不知道这是谁?

或者我还能怎么做?

最佳答案

@Srivaishnav

我所做的是,每个客户端在每个请求的 header 中向 Web API 发送一个 tenantId。然后,Web API 在一些中间件中读取这个 tenantId,并将其保存在 HttpContext 中,以便它在 API 中的任何位置都可读。然后,在我的 DbContext 中,在 OnConfiguring 方法中,我从 HttpContext 中读取 tenantId,并使用它为该 DbContext 创建连接字符串。代码:

TenantIdentifier.cs 中间件:

public class TenantIdentifier
{
private readonly RequestDelegate _next;
private readonly IMemoryCache _memoryCache;
private DbContext _dbContext;

public TenantIdentifier(RequestDelegate next, IMemoryCache memoryCache)
{
_next = next;
_memoryCache = memoryCache;
}

public async Task Invoke(HttpContext httpContext, DbContext dbContext)
{
_dbContext = dbContext;

string clientIdHeader = httpContext.Request.Headers["clientId"].FirstOrDefault();
if (string.IsNullOrEmpty(clientIdHeader))
{
await _next.Invoke(httpContext);
return;
}

int clientId = int.Parse(clientIdHeader);

httpContext.Items["CLIENT"] = clientId;

await _next.Invoke(httpContext);
}

public static class TenantIdentifierExtension
{
public static IApplicationBuilder UseTenantIdentifier(this IApplicationBuilder app)
{
app.UseMiddleware<TenantIdentifier>();
return app;
}
}

DbContext.cs:

    private readonly IHttpContextAccessor _httpContextAccessor;

public TenantContext(DbContextOptions<DbContext> options, IHttpContextAccessor httpContextAccessor)
: base(options)
{
_httpContextAccessor = httpContextAccessor;
}

protected override async void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (_httpContextAccessor == null)
return;

int? clientId = (int?)_httpContextAccessor.HttpContext.Items["CLIENT"];
if (!client.HasValue)
{
optionsBuilder = null;
return;
}

string connectionString = null;

switch (tenantId.Value)
{
case 1:
connectionString = "some connection string";
break;

case 2:
connectionString = "some other connection string";
break;
}

optionsBuilder.UseMySql(connectionString);
}

Startup.cs

    public void Configure(IApplicationBuilder app)
{
app.UseTenantIdentifier();
app.UseMvc();
}

我已经稍微简化了示例,但这几乎就是问题的症结所在。如果您有任何问题,请告诉我...祝您好运!

关于rest - 如何根据客户端调用实现具有多个数据库的Web API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45412641/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com