将数据库上下文注入自定义属性 .NET Core
inject Database Context into Custom Attribute .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";
});
}
//...
已将数据库上下文 class 更改为:
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
,因为一旦出现异常你会很困惑是怎么回事。
- 没有必要像这样
using(EF) { .. }
在 using 语句中包装注入的 DbContext。您将尽早处理它,这将导致稍后在请求中出现错误。 DI 容器正在为你管理生命周期,相信它。
我正在创建 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";
});
}
//...
已将数据库上下文 class 更改为:
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
,因为一旦出现异常你会很困惑是怎么回事。 - 没有必要像这样
using(EF) { .. }
在 using 语句中包装注入的 DbContext。您将尽早处理它,这将导致稍后在请求中出现错误。 DI 容器正在为你管理生命周期,相信它。