我可以在 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() 将添加用户和角色,以便您可以在整个应用程序中使用【参考方案2】:

在 .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 应用程序启动期间运行异步代码

放置请求期间的 ASP Net Core CORS 错误

如何从 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 的问题

asp.net求助