我可以在 ASP.NET Core 启动期间访问数据库吗?
Posted
技术标签:
【中文标题】我可以在 ASP.NET Core 启动期间访问数据库吗?【英文标题】:Can I access a database during startup in ASP.NET Core? 【发布时间】:2016-08-02 19:07:19 【问题描述】:我最近一直在研究 .NET Core Web API。我刚刚按照https://stormpath.com/blog/token-authentication-asp-net-core 上的指南尝试使用 JWT 进行身份验证。
一切都很顺利,直到我不得不用数据库查询替换 GetIdentity
方法中的硬编码用户名和密码,并意识到我不知道如何从这个文件中访问数据库!
我所指的方法显示在下面第 70 行的链接中。 https://github.com/nbarbettini/SimpleTokenProvider/blob/master/test/SimpleTokenProvider.Test/Startup.Auth.cs
我的问题如下。
-
我可以在这里访问数据库吗?如果有怎么办?
这应该是 GetIdentity 方法所在的位置,还是有更好的方法?
【问题讨论】:
【参考方案1】:是的,您可以访问数据库!在Configure
方法中运行的代码可以访问在ConfigureServices
方法中添加的任何服务,包括数据库上下文等内容。
例如,如果您有一个简单的实体框架上下文:
using Microsoft.EntityFrameworkCore;
using SimpleTokenProvider.Test.Models;
namespace SimpleTokenProvider.Test
public class SimpleContext : DbContext
public SimpleContext(DbContextOptions<SimpleContext> options)
: base(options)
public DbSet<User> Users get; set;
然后你把它添加到ConfigureServices
:
services.AddDbContext<SimpleContext>(opt => opt.UseInMemoryDatabase());
然后,你可以在设置中间件时访问它:
var context = app.ApplicationServices.GetService<SimpleContext>();
app.UseSimpleTokenProvider(new TokenProviderOptions
Path = "/api/token",
Audience = "ExampleAudience",
Issuer = "ExampleIssuer",
SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
IdentityResolver = (username, password) => GetIdentity(context, username, password)
);
并稍微改写GetIdentity
方法:
private Task<ClaimsIdentity> GetIdentity(SimpleContext context, string username, string password)
// Access the database using the context
// Here you'd need to do things like hash the password
// and do a lookup to see if the user + password hash exists
我是原始样本的作者。抱歉一开始不清楚!我尝试以一种易于提供您自己的功能的方式编写IdentityResolver
委托——例如与您自己的数据库集成(如上所述),或将其连接到 ASP.NET Core Identity。当然,您也可以随意丢弃我的代码并做一些更好的事情。 :)
【讨论】:
如果您只是将 JWT 添加到 aspnet 身份,您可以传递 signinmanager 而不是 dbcontext: var userManager = app.ApplicationServices .GetService(typeof(UserManager)) @xcud 这正是我想要做的,但得到一个错误“无法解析范围服务'Microsoft.AspNetCore.Identity.UserManager`”,我在这里缺少什么? 应该更新样本或在 cmets 中添加这个概念,这让我发疯了好几个小时!谢谢你的回答! 这不适用于范围服务。如果您已将AddDbContext
与 Entity Framework 一起使用,那么您的 DB 服务是有作用域的。查看我的答案以获得解决方案。
@xcud 您需要将身份添加到服务中,例如 services.AddIdentity在 .NET CORE 2.1 上,只需将上下文作为参数传递给 Configure 方法:
public void Configure(IApplicationBuilder app, YourDbContext context, IHostingEnvironment env, ILoggerFactory loggerFactory)
//do whatever you want with the context here...
将服务添加到 服务容器 使它们在 应用程序并在 Configure 方法中。服务通过以下方式解决 依赖注入或来自 ApplicationServices。
【讨论】:
这是实际且最简单的答案,前提是您已预先将DbContext
注册为 DI
或隐式注册为 AddDbContext
。至少从.net core 2.1
开始工作,如this answer中所述(没有检查,适用于3.0 prev)
请问如果您将服务注册为作用域,您仍然可以在Configure
方法中访问它还是只有瞬态和单例在这里工作?
@jegtugado 应该可以工作。顺便说一句 AddDbContext 添加为作用域【参考方案3】:
接受的答案不适用于范围服务(scoped 服务是根据请求创建的,如果您使用的是实体框架并使用AddDbContext
添加上下文然后this is the case)。
您可以按如下方式在启动时使用作用域服务 (source):
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
using (var serviceScope = app.ApplicationServices.CreateScope())
var services = serviceScope.ServiceProvider;
var myDbContext = services.GetService<MyDbContext>();
或将其传递给Configure
方法的参数,如答案所示
胡诺拉
【讨论】:
我认为这是在单例和服务中使用作用域服务的推荐方式,参考示例代码:consuming-a-scoped-service-in-a-background-task【参考方案4】:我可能在其他层面上错了,但我找到的解决方案是创建一个范围。
我在 GetIdentity 中传递了应用程序而不是 ctx,然后在 GetIdentity 中使用范围:
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
if (serviceScope.ServiceProvider.GetService<YourAppDbContext>() != null)
var ctx = serviceScope.ServiceProvider.GetService<YourAppDbContext>();
if (AnAuthenticateMethodHereMaybe(ctx, username, password))
return Task.FromResult(new ClaimsIdentity(new
GenericIdentity(username, "Token"), new Claim[] ));
【讨论】:
以上是关于我可以在 ASP.NET Core 启动期间访问数据库吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Asp.NET Core 3.1 启动类访问 launchSettings.json 中的 `applicationUrl` 属性?
在 Asp.net core 2.2.1 中访问 XMLHttpRequest
在 asp.net core vs2015 update2 情况况下创建 asp.net core web application 的问题