EF Core 根据 API 中的参数调用数据库
Posted
技术标签:
【中文标题】EF Core 根据 API 中的参数调用数据库【英文标题】:EF Core to call database based on parameter in API 【发布时间】:2021-07-30 09:31:33 【问题描述】:我有一个在 .NET Core 中使用 EF Core 开发的 API。我必须为多个客户提供不同的数据(但相同的模式)。这是一个学校申请,由于竞争等原因,每所学校都希望单独保存他们的数据。所以我们为每所学校都有一个数据库。现在我的挑战是,基于一些参数,我想更改我的dbContext
对象的连接字符串。
例如,如果我调用 api/students/1 它应该得到所有来自学校 1 的学生,依此类推。我不确定在配置服务本身中是否有更好的方法来做到这一点。但我应该能够从我的客户端应用程序传递SchoolId
public void ConfigureServices(IServiceCollection services)
services.AddDbContext<SchoolDataContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("APIConnectionString")));
services.AddScoped<IUnitOfWorkLearn, UnitOfWorkLearn>();
2021 年 5 月 11 日
namespace LearnNew
public class Startup
public Startup(IConfiguration configuration)
Configuration = configuration;
public IConfiguration Configuration get;
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
//Comenting to implement Mr Brownes Solution
//services.AddDbContext<SchoolDataContext>(options =>
// options.UseSqlServer(
// Configuration.GetConnectionString("APIConnectionString")));
services.AddScoped<IUnitOfWorkLearn, UnitOfWorkLearn>();
services.AddControllers();
services.AddHttpContextAccessor();
services.AddDbContext<SchoolDataContext>((sp, options) =>
var requestContext = sp.GetRequiredService<HttpContext>();
var constr = GetConnectionStringFromRequestContext(requestContext);
options.UseSqlServer(constr, o => o.UseRelationalNulls());
);
ConfigureSharedKernelServices(services);
services.AddSwaggerGen(c =>
c.SwaggerDoc("v1", new OpenApiInfo Title = "LearnNew", Version = "v1" );
);
private string GetConnectionStringFromRequestContext(HttpContext requestContext)
//Trying to implement Mr Brownes Solution
var host = requestContext.Request.Host;
// Since I don't know how to get the connection string, I want to
//debug the host variable and see the possible way to get details of
//the host. Below line is temporary until the right method is identified
return Configuration.GetConnectionString("APIConnectionString");
private void ConfigureSharedKernelServices(IServiceCollection services)
ServiceProvider serviceProvider = services.BuildServiceProvider();
SchoolDataContext appDbContext = serviceProvider.GetService<SchoolDataContext>();
services.RegisterSharedKernel(appDbContext);
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "LearnNew v1"));
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
endpoints.MapControllers();
);
【问题讨论】:
你看过this answer吗? 【参考方案1】:您可以在配置 DbContext 时访问 HttpContext,如下所示:
services.AddControllers();
services.AddHttpContextAccessor();
services.AddDbContext<SchoolDataContext>((sp, options) =>
var requestContext = sp.GetRequiredService<IHttpContextAccessor>().HttpContext;
var constr = GetConnectionStringFromRequestContext(requestContext);
options.UseSqlServer(constr, o => o.UseRelationalNulls());
);
这段代码:
var requestContext = sp.GetRequiredService<IHttpContextAccessor>().HttpContext; var constr = GetConnectionStringFromRequestContext(requestContext);
options.UseSqlServer(constr, o => o.UseRelationalNulls());
将为每个请求运行,根据来自 HttpRequestContext 的详细信息配置连接字符串。
如果您需要在启动时使用您的 DbContext,请不要通过 DI 解决它。只需像这样配置一个连接:
var ob = new DbContextOptionsBuilder<SchoolDataContext>();
var constr = "...";
ob.UseSqlServer(constr);
using (var db = new Db(ob.Options))
db.Database.EnsureCreated();
但在生产环境中,您通常会提前创建所有租户数据库。
【讨论】:
大卫您好,感谢您的回复。由于我是新手,如果我的问题太基本,请多多包涵。假设我有两所学校订阅了这个 API,第一所学校将尝试从 schoolapis.azurewebsites.net/api/students/1 访问学生的控制器,第二所学校从 schoolapis.azurewebsites.net/api/students/2 访问。由于我假设 DbContext 处于启动状态,.net 核心将在这两种情况下运行配置服务?由于任何原因,我不想在学校 1 中获得学校 2 的学生名单。 这也意味着我必须将学校 ID 作为参数传递给所有控制器操作,对吗?有没有更好的办法? 对学校 ID 使用 URL 参数可能不是最好的主意。相反,您通常使用用户的身份。身份验证数据、请求标头和 URL 都可以通过 HttpContext 获得。 谢谢你,大卫。我将进行相同的测试并确认答案。再次感谢您的宝贵时间。我从 DbContextFactory 开始,但您的解决方案看起来更直接。 嗨大卫,它给了我以下错误,你能帮帮我吗? System.InvalidOperationException:'没有为类型'Microsoft.AspNetCore.Http.HttpContext'注册服务。'我知道当你从你的水平看我时,我只是一个绝对的初学者,但我相信在你的帮助下我可以让它发挥作用。下面是完整的代码。以上是关于EF Core 根据 API 中的参数调用数据库的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 EF 的情况下连接到 ASP.NET Core Web API 中的数据库?
带有 EF Core 更新实体的 ASP.Net 核心 Web Api 如何