Dependency injection 每个用户的netcore依赖项注入

Dependency injection 每个用户的netcore依赖项注入,dependency-injection,asp.net-core,Dependency Injection,Asp.net Core,我想知道如何为mvc设置netcore依赖容器,每个用户一个实例 据介绍,目前只有三种指定生存期的方法:singleton(每个应用程序一个实例)、scoped(在HttpRequest中共享一个实例)、transient(每个DI实例请求一个实例) 是否有人试图为每个用户创建实例?我会很好奇它是如何完成的——如果不是,我可能会在某个时候翻阅文档,看看如何完成并共享解决方案。在第一个用户请求时创建实例,并使其保持活动状态(用于下一个请求),直到过期超时。。。这看起来像是一个大问题 您可以使用fa

我想知道如何为mvc设置netcore依赖容器,每个用户一个实例

据介绍,目前只有三种指定生存期的方法:singleton(每个应用程序一个实例)、scoped(在HttpRequest中共享一个实例)、transient(每个DI实例请求一个实例)


是否有人试图为每个用户创建实例?我会很好奇它是如何完成的——如果不是,我可能会在某个时候翻阅文档,看看如何完成并共享解决方案。

在第一个用户请求时创建实例,并使其保持活动状态(用于下一个请求),直到过期超时。。。这看起来像是一个大问题


您可以使用factory方法注册服务并在其中分析当前会话。

如果这是asp.net核心应用程序,自动添加到中间件管道的中间件将在请求开始时创建新的DI作用域,并在请求结束时处理该作用域。此作用域存储在HttpContext中。此作用域将在注入MVC控制器等时使用。因此,如果您希望将每用户服务注入到MVC控制器/操作方法中,则需要将HttpContext中的此作用域替换为您自己为当前用户构建的作用域。您必须使用中间件来实现这一点,中间件必须在认证中间件之后运行(因此在当前用户建立之后)。您的自定义中间件将查看当前经过身份验证的用户,并且getor将创建保存在某个缓存中的IServiceProvider(容器),该缓存可能具有滑动到期。有了每用户IServiceProvider,它将为当前请求创建一个作用域,并用这个特定于用户的作用域替换HttpContext中当前的作用域,同时确保在请求结束时处理它。问题是,在构建每个用户容器时,如果您为每个用户创建一个新的ServiceCollection,并注册一些服务,并为该用户构建和缓存IServiceProvider,那么您将无法解析仅在应用程序级别(即启动时)注册的任何服务。这就是子容器的概念很方便的地方,微软并没有开箱即用地实现它,但是如果您切换到使用另一个DI提供程序(如Autofac),您可以使用它。Autofac提供了IServiceProvider的实现以及生成子容器的能力。如果使用此机制,您可以为每个用户创建一个子容器,这意味着它仍然能够解析所有更高级别的服务,但现在您还可以解析特定于用户的服务。如果您完成了所有这些,您将能够注入每个用户的服务


这是相当多的工作。如果有足够的兴趣,我会考虑把这个特性添加到我的多租户库中,因为它已经做了类似于每个租户容器创建的事情:

类似的事情?

    var shoppingLists = new Dictionary < string,
ShoppingListStateContainer > ();

services.AddTransient < ShoppingListStateContainer > (s = >{
    var userName = s.GetRequiredService < AuthenticationStateProvider > ().GetAuthenticationStateAsync().GetAwaiter().GetResult().User.Identity.Name ? ?"null";
    lock(s) {
        if (!shoppingLists.ContainsKey(userName)) shoppingLists.Add(userName, new ShoppingListStateContainer());
    }
    return shoppingLists[userName];
});
var shoppingLists=newdictionary();
services.AddTransient(s=>{
var userName=s.GetRequiredService().GetAuthenticationStateAsync().GetWaiter().GetResult().User.Identity.Name???“null”;
锁{
如果(!shoppingLists.ContainsKey(userName))shoppingLists.Add(userName,new ShoppingListStateContainer());
}
退货购物清单[用户名];
});

您可以为每个请求(而不是每个用户)创建一个实例。该实例在请求的整个生命周期内都是可用的。你能详细说明一下你想如何使用这个实例吗?基本上我有一个登录控制器,在这里我输入RESTAPI的凭证。这些rest客户端实例使用登录时传递的凭据进行初始化。因此,我的计划是使用每个用户在声明标识中存储的登录信息为实例使用工厂注册。虽然这已经在每个作用域/每个请求的基础上起作用,但就性能而言,它是次优的。(1)带超时的内存缓存;(2) 单例范围的字典,带有一些令牌作为密钥(会话id?)-您需要手动清理;(3)我对完全相同的问题“dl”感兴趣,如果你有这个问题的解决方案,你能和我分享吗?我会考虑把这个特性添加到我的多租借库中:如果有足够的兴趣。如果你想让我看的话,请提出一个问题。我已经创建了每个租户的容器。我可以添加一个钩子,在用户验证后运行。我可以将容器存储在内存缓存中,使用滑动过期、由某个用户属性ooke会话或用户名设置的密钥。如果用户在缓存滑动时关闭浏览器,容器最终将被释放。虽然这肯定会起作用,但我不想将依赖注入相关服务卸载到会话中。不过我会记住这一点。对自己说实话——你正在寻找一些可以混合DI和会话的东西。不管你怎么称呼它,它都是真的。它是用户范围的。您可以用不同的方式实现它——比如说,创建您自己的“作用域”(根据DI)并将其放入会话中,并从此作用域解析其他服务,但您是否仍将使用“某些会话”机制,即每个用户使用内存,在webfarm中不起作用(您无法序列化服务并在多个进程/机器之间共享服务)等等。如果你不喜欢这样(这不利于扩展)-也许你应该回顾/重新思考你的体系结构?虽然我部分同意你的观点,但我仍然不想将其混为一谈。DI从禁用会话中断将是一个意外的后果,而实际上我的DI所依赖的只是一个唯一的请求标识。