asp.net core 数据库上下文在中间件(Middleware)中的使用

文章讲述了在ASP.NETCore中,如何在中间件中正确使用数据库上下文,避免在构造函数注入导致的问题,提倡在Invoke/InvokeAsync函数中通过作用域获取并注入DataContext,确保每个请求一个独立的数据库上下文实例以维护数据一致性。
摘要由CSDN通过智能技术生成

 推荐直接在Invoke/InvokeAsync 函数中进行依赖注入

public async Task Invoke(HttpContext context,DataContext data)

一个很尴尬的事情是,在我学习asp.net core 的书中没有介绍在中间件中使用数据库的介绍,甚至是例子都没有。

但是我写的一个小项目中却需要在中间件中使用数据库上下文来进行数据库查询。

当我直接在中间件的构造函数中使用依赖注入来使用数据库上下文时,会报错。

一些关于什么Scope的东西,今天问了其他方面,有些解释。

如果直接在中间件的构造函数中注入数据库上下文,可能会导致一些问题。这是因为中间件的构造函数在应用程序启动时就会被调用,而不是在每个请求处理过程中调用。数据库上下文是一个瞬态(transient)服务,它在每个请求中应该是唯一的。

在上面的代码中,我们使用了 IServiceProvider 来获取一个作用域,并从作用域中获取 DataContext 的实例。这样可以确保在每个请求中都创建一个新的数据库上下文实例,并在请求结束时适当地清理和释放资源。

通过使用作用域来获取数据库上下文,我们遵循了每个请求一个数据库上下文的最佳实践。这样可以避免在多个请求之间共享同一个上下文实例可能导致的并发和数据一致性问题。

因此,使用 IServiceProvider 创建作用域,并从作用域中获取数据库上下文实例是一种可行的方式,可以在中间件中安全地使用数据库上下文。

 大致可以理解是,中间件的构造只会在每个作用链的当前结点构造一次。

这一次构造会处理多个通过的http请求。而,DataContext的注入需要作用域(一般是一个请求)。

我之前是这样处理的。不要这样做

这是一个链条

app.Map("/v1", apiApp =>
{
    apiApp.UseMiddleware<RosterMiddleware>();
    apiApp.UseMiddleware<SecureMiddleware>(app.Services);
    apiApp.UseMiddleware<RequestChooserMiddleware>();
    apiApp.UseMiddleware<PricingMiddleware>(app.Services);
    apiApp.UseEndpoints(endpoints => { endpoints.MapPost("v1/{*path}", new TransferEndpoint().Endpoint); });
});

其中中间件SecureMiddleware和PricingMiddleware需要用到数据库上下文来进行数据库操作。

以SecureMiddleware为例。

构造函数和基本属性如下

public class SecureMiddleware
{
    private DynamicTable _table;
    private readonly RequestDelegate _next;
    private readonly IServiceProvider _provider;

    public SecureMiddleware(RequestDelegate next,IServiceProvider provider,DynamicTable table)
    {
        _provider = provider;
        _next = next;
        _table = table;
    }

在Invoke/InvokeAsync中这样使用

public async Task Invoke(HttpContext context)
    {
        using var scope = _provider.CreateScope();
        await using var data = scope.ServiceProvider.GetRequiredService<DataContext>();

 data就是一个DataContext类型的对象,紧接着就可以使用DataContext来进行数据库操作了。

这样是可行的,但是在我进行测试的时候。

        await context.Response.WriteAsync("Secure "+data.GetHashCode());

在使用数据库上下文的中间件分别输出,然后在处理程序中进行输出,他们的哈希值不一样,也就是他们是属于不同的对象。

紧接着我又测试了下面的使用方式。可行,并且输出的哈希值是一样的。

app.Map("/v1", apiApp =>
{
    apiApp.UseMiddleware<TestMiddleware>();
    apiApp.UseMiddleware<RosterMiddleware>();
    apiApp.UseMiddleware<SecureMiddleware>();
    apiApp.UseMiddleware<ModelFilterMiddleware>();
    apiApp.UseMiddleware<RequestChooserMiddleware>();
    apiApp.UseMiddleware<PricingMiddleware>();
    apiApp.UseEndpoints(endpoints =>
        { endpoints.MapPost("v1/{*path}", new TransferEndpoint().Endpoint); });
});

 test 36736776Secure 36736776Process 36736776Pricing 36736776

是直接在Invoke/InvokeAsync 函数 中进行依赖注入。

这样使用,推荐的方式

public async Task Invoke(HttpContext context,DataContext data)

这样的话,在一个http请求,会共用一个数据库上下文对象,(这里是DataContext)。

并且,上下文对象会自己进行销毁(框架实现的效果)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫叶kx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值