asp.net-core - 将数据库上下文注入自定义属性 .NET Core
问题描述
我正在创建 ASP.NET Core 3.1 应用程序,使用 SPA 作为前端。所以我决定创建自定义身份验证和授权。所以我创建了自定义属性来分发和验证 JWT。
假设它看起来像这样:
[AttributeUsage(AttributeTargets.Method)]
public class AuthLoginAttribute : Attribute, IAuthorizationFilter
{
public async void OnAuthorization(AuthorizationFilterContext filterContext)
{
//Checking Headers..
using (var EF = new DatabaseContext)
{
user = EF.User.Where(p => (p.Email == username)).FirstOrDefault();
}
filterContext.HttpContext.Response.Headers.Add(
"AccessToken",
AccessToken.CreateAccessToken(user));
}
}
一切都很好,但我的DatabaseContext
,看起来像这样:
public class DatabaseContext : DbContext
{
public DbSet<User> User { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySQL("ConnectionString");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//....
}
}
我想从 Appsettings.json 中获取连接字符串,并可能使用依赖注入。我将 Startup.cs 更改为如下所示:
//...
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<DatabaseContext>(
options => options.UseMySQL(Configuration["ConnectionStrings:ConnectionString"]));
services.Add(new ServiceDescriptor(
typeof(HMACSHA256_Algo), new HMACSHA256_Algo(Configuration)));
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
//...
将数据库上下文类更改为:
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }
public DbSet<User> User { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
///..
}
}
在控制器中,我注入了数据库上下文,一切正常。它看起来像这样:
[ApiController]
[Route("API")]
public class APIController : ControllerBase
{
private DatabaseContext EF;
public WeatherForecastController(DatabaseContext ef)
{
EF = ef;
}
[HttpGet]
[Route("/API/GetSomething")]
public async Task<IEnumerable<Something>> GetSomething()
{
using(EF){
//.. this works
}
}
}
但是我的自定义属性不再起作用。我无法声明新的数据库上下文,因为它需要DatabaseContextOptions<DatabaseContext>
声明对象,那么如何将 DBContext 注入到属性中,就像对控制器所做的那样?
这不起作用:
public class AuthLoginAttribute : Attribute, IAuthorizationFilter
{
private DatabaseContext EF;
public AuthLoginAttribute(DatabaseContext ef)
{
EF = ef;
}
public async void OnAuthorization(AuthorizationFilterContext filterContext)
{
using(EF){
}
}
}
这适用于控制器,但属性抱怨没有具有 0 个参数的构造函数。
解决方案
您可以做的是利用 RequestServices:
[AttributeUsage(AttributeTargets.Method)]
public class AuthLoginAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var dbContext = context.HttpContext
.RequestServices
.GetService(typeof(DatabaseContext)) as DatabaseContext;
// your code
}
}
如果您允许我在您的代码中添加两条注释:
- 尽量不要使用
async void
,因为一旦发生异常,你会很困惑发生了什么。 - 没有必要将注入的 DbContext 包装在这样的 using 语句中
using(EF) { .. }
。您将提前处理它,这将导致稍后在请求中出现错误。DI 容器正在为您管理生命周期,相信它。
推荐阅读
- excel - 基于 Excel 表格提取某些 Powerpoint 幻灯片并结合到新的演示文稿中
- java - 如何在 Spring Boot 执行器中禁止 TRACE http 方法
- php - Laravel - 如何从 Stripe 检索所有带有元数据的订阅
- python - 如何在 Python 中使用 Twitter API 进行多次调用
- android - Android - 在构建项目时
- php - 将文件中的字符串(stdobject)解析为stdobject
- c# - 如何为ChoicePrompt Bot framework V4 c#添加10多个按钮
- android - 仅支持 armeabi 和 x86 的 android 库的问题
- java - 自定义对象作为 Map 键
- c# - 单击按钮时调用控制器方法时需要将文本框值作为参数传递