覆盖 DI 范围内的服务实现

2023-12-04

如何使用miscrosoft 的默认 DI 机制在某个范围内注册不同的服务实现?

我的情况是这样的:

我有一个服务(我们称之为 MyJobService),它依赖于上下文值(登录的用户和其他一些信息)。我已经注册了另一个服务(UserSessionProvider),它从当前的 HttpContext 读取所需的数据。但我的初始服务也可能在后台作业中运行,其中 HttpContext 不存在,but该作业是从网络请求中解雇的。

所以我想要 UserSessionProvider 的第二个实现,其中当前用户的信息不是从 http 上下文中读取的,而是作为只读数据传递给服务实现,然后我将使用 UserSessionProvider 的这个实例作为创建的范围。

public IActionResult ControllerMethod(
   [FromService] IUserSessionProvider sessionProvider, // this instance reads from http context
   [FromServices] IServiceProvider sp)
{
    var staticSessionProvider = new StaticDataSessionProvider(  // this instance uses what you pass to the constructor
      userName: sessionProvider.userName,
      userData: sessionProvider.userData
    );
    
    ExecuteInBackground(()=>{
     using(var scope = sp.CreateScope()){
       scope.AddScoped<IUserSessionProvider>(staticSessionProvider); // can I do that?
       var myJob=scope.ServiceProvider.GetService<MyJobService>(); // here 'myJob' would use the staticDataSessionProvider instance
       myJob.Run();
     }
    });
      
}

如何使用miscrosoft 的默认 DI 机制在某个范围内注册不同的服务实现?

你不能。在启动过程结束时,容器被创建,并且它的注册集是固定的。这是一件好事,因为允许中途更改容器可能会导致非常不幸的后果(如本文档部分此竞争 DI 容器的)。你必须想出另一个解决方案。

例如,您可以创建一个代理实现并将其用作替代:

// Proxy implementation that dispatches to the real IUserSessionProvider
public sealed class OverwritableUserSessionProvider : IUserSessionProvider
{
    // NOTE: Depends on the UserSessionProvider implementation
    public OverwritableUserSessionProvider(UserSessionProvider provider)
    {
        this.Provider = provider;
    }
    
    // Allows replacing the dependency
    public IUserSessionProvider Provider { get; set; }
    
    // Implement IUserSessionProvider
    public string UserName => this.Provider.UserName;
    public UserData UserData => this.Provider.UserData;
}

该代理和真实提供者可以按如下方式注册:

// Register both the 'real' provider and the proxy.
services.AddScoped<UserSessionProvider>();
services.AddScoped<OverwritableUserSessionProvider>();

// Register the proxy as IUserSessionProvider.
services.AddScoped<IUserSessionProvider>(
    sp => sp.GetRequiredService<OverwritableUserSessionProvider>());

这允许您实施您的ControllerMethod如下:

var staticSessionProvider = new StaticDataSessionProvider(
  userName: sessionProvider.userName,
  userData: sessionProvider.userData);

ExecuteInBackground(() =>
{
    using (var scope = sp.CreateScope())
    {
        // Resolve the proxy
        var provider = scope.ServiceProvider
            .GetRequiredService<OverwritableUserSessionProvider>();
            
        // Replace the default dependency
        provider.Provider = staticSessionProvider;
        
        // Resolve and execute the service as usual.
        var myJob = scope.ServiceProvider.GetRequiredService<MyJobService>(); 
        myJob.Run();
    }
});

TIP:将这个逻辑从控制器中提取出来并放入一个专门的类中;该逻辑是基础设施,与控制器相比有不同的关注点。

基于上述解决方案还有其他可能的解决方案和变体,但这里的技巧是始终确保容器组成相同的对象图。不要使组合对象结构动态化;不要基于运行时数据.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

覆盖 DI 范围内的服务实现 的相关文章

  • C# 无法访问已释放的对象

    我正在制作一个服务器 客户端应用程序 我将服务器套接字设置为侦听 并设置 BeginAccept 方法 当我关闭服务器套接字 Socket Close 以关闭服务器时 BeginAccept 方法的异步回调方法抛出异常 我检查了异常 发现异
  • 为什么 System.Math 有 Sin、Cos 等外部方法?

    MethodImpl MethodImplOptions InternalCall public static extern double Sin double a 其原因何在 MethodImplOptions InternalCall表
  • 这是依赖注入吗?这是一种不好的做法吗?

    我有一个小框架 我是这样编码的 我不确定这是否称为依赖注入 我不知道它是否像设计模式 我也不知道并且想知道是否通过 this因为 param 是一种不好的做法 看看这个 不是一个有效的示例 只是将这些代码写入浏览器中以供解释 This is
  • 为什么 Application.Exit 无法工作?

    我有一个应用程序在取消对话框时出现奇怪的错误 如果该框被取消 应用程序将无法继续 因此它会退出 但由于某种原因它无法工作 因此它会继续运行并崩溃 我调试了这个问题 并且不知何故应用程序在 Application Exit 调用之后运行 我正
  • 大学软件开发:从 Datatel/Colleague 获取数据

    我在北卡罗来纳州的一所社区大学工作 我们最核心的数据存储库是一个名为 Datatel 的软件系统 又名 Colleague 为什么它有两个名字 我不知道 在我们的例子中 底层数据存储是 IBM Unidata 我使用 net 技术进行开发
  • 没有端点在 net.pipe://localhost/ 上监听

    我有两个 WCF 服务托管在 Windows Server 2003 计算机上的单个 Windows 服务中 如果 Windows 服务需要访问任一 WCF 服务 例如发生定时事件时 它将使用公开的五个命名管道端点之一 不同的服务协定 该服
  • 如何在 C# 控制台应用程序中将修饰符(ctrl、alt、shift)按键捕获为单个按键?

    Console ReadKey 仅在按下 正常 键时捕获输入 然后将修饰符 如果有 附加为键信息的一部分 如何将单个修饰键注册为输入 提供了一种解决方案这个链接 https blogs msdn microsoft com toub 200
  • 类似于 .NET Framework 2.0 的 MEF(托管可扩展性框架)

    我在自己的项目中使用了 MEF 并且非常喜欢它 这很容易 在弄清楚我们的awkwardAPI模型 它刚刚工作了 现在我需要 NET Framework 2 0 类似的东西 有没有可以在 NET Framework 2 0 下工作的类似项目
  • 如何在 Spring 3.1 中构造函数自动装配 HttpServletResponse?

    我有一个请求范围的 bean 并且需要访问 HttpServletResponse 和 HttpServletRequest 对象 我需要在构造函数中访问这些对象 因此属性自动装配不是一个选项 我做了以下事情 Component Scope
  • Global.asax PostAuthenticateRequest 事件绑定是如何发生的?

    我怎样才能使用发布验证请求Global asax 事件 我正在跟进本教程 http www asp net security tutorials forms authentication configuration and advanced
  • 当进程等待完成时如何显示加载控件?

    我决定使用这个第三方组件在我的 Windows 窗体中制作一个简单的加载控件 http www codeproject com Articles 14841 How to write a loading circle animation i
  • 有没有一种简单的方法来为每个类创建一个记录器实例?

    我现在使用静态方法来记录 因为我发现在Android中登录非常容易 但是现在我需要为不同的类配置不同的appender 所以我对静态记录方法有一个问题 我读了Log4J 创建 Logger 实例的策略 https stackoverflow
  • StringComparison.InvariantCultureIgnoreCase 去哪儿了?

    我正在将 C 代码移植到 Windows 应用商店应用程序 令我惊讶的是 以下代码不再起作用 someString Equals someOtherString StringComparison InvariantCultureIgnore
  • 如何禁用 Alt + F4 关闭表单?

    What is the best way to disable Alt F4 in a c win form to prevent the user from closing the form 我使用表单作为弹出对话框来显示进度条 但我不希
  • 有没有基于 WPF 的 Markdown 渲染器? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我们有基于 WPF 的应用程序 我们有单独的字符串存储库 其中的文本在网络中进行编辑 在我们的 WPF
  • 两个 RichTextBox 具有相同的滚动条

    是否有任何可用的第三方工具有两个富文本框 但两者只有一个共享滚动条 我需要用两种不同的语言实现一些文本 但两个文本框应该同时滚动 public enum ScrollBarType uint SbHorz 0 SbVert 1 SbCtl
  • C# 如何使用 CallNtPowerInformation 和 Interop 来获取 SYSTEM_POWER_INFORMATION

    我正在尝试编写一个小程序 该程序作为服务运行并监视用户是否处于活动状态 如果用户空闲 没有鼠标 键盘 一个小时 则某些进程将被终止 如果用户使用 user32 dll 中的 LASTINPUTINFO 运行它 它就可以工作 但它不能作为服务
  • 有条件地在 Visual Studio 中嵌入资源 (C#)

    有没有办法有条件地将资源嵌入到 NET 项目中 IE 如果我定义了 INCLUDETHIS 那么我想要将某个大文件嵌入到 dll 中 否则我不希望它嵌入 我知道我可以做两个项目来做到这一点 但我希望在一个项目中完成这一切 使用该文件的代码很
  • ASP.NET Core Identity 更改登录 URL

    我正在使用 ASP NET Core 2 1 并且使用脚手架来添加身份 工作正常 除了当我尝试转到需要登录的页面时 它需要我 Identity Account Login ReturnUrl 如何将其更改为仅转到 Account Login
  • IDisposable 的显式实现

    虽然有很多关于IDisposable在 SO 上找到 我还没有找到答案 我通常遵循这样的做法 当我的一个班级拥有一个IDisposable对象然后它也实现IDisposable并打电话Dispose在拥有的对象上 然而最近我遇到了一个类 它

随机推荐