如何在 C# / ASP 中的单例中使用范围依赖

2023-11-30

我是来自 Java 世界的 C#/ASP 新手。我读过这篇文章:https://docs.asp.net/en/latest/fundamentals/dependency-injection.html#service-lifetimes-and-registration-options它明智地警告了与注入较小范围的依赖项相关的危险。不幸的是它没有解释如何在 C#/ASP 中解决这个问题。 Java中有一个Provider的概念

interface Provider<T> { T get(); }

除其他外,这有助于解决范围界定问题: 每当注册某种类型 T 的绑定时,我们都可以注入自动生成的 Provider 实例而不是 T,然后在需要时获取 T 的实例:自动生成的 Provider 确保我们获得适合该类型的实例当前范围(无论该范围是什么:HTTP 请求、HTTP 会话或其他自定义范围)。 ASP.NET core 中内置的标准 DI 框架没有这样的东西,但我认为在 C# 中它应该很容易实现,因为 C# 泛型不像 java 那样糟糕(https://docs.oracle.com/javase/tutorial/java/generics/erasure.html)。所以我创建了以下类:

public class Provider<T>: IProvider<T> {
  private readonly IServiceProvider serviceProvider;
  public Provider(IServiceProvider serviceProvider) {
    this.serviceProvider = serviceProvider;
  }
  public T IProvider<T>.Get() {
    return serviceProvider.GetService<T>();
  }
}

我尝试按以下方式使用它:

public class SingletonService : ISingletonService {
  private readonly IProvider<IScopedService> scopedServiceProvider;

  public SingletonService(IProvider<IScopedService> scopedServiceProvider) {
    this.scopedServiceProvider = scopedServiceProvider;
  }

  public string PerformMyTask() {
    var scopedDependency = scopedServiceProvider.Get();
    // do something with scopedDependency to verify we get instances
    // appropriate for the current scope
  }
}

在我的启动课程中:

public void ConfigureServices(IServiceCollection services) {
  services.AddSingleton<ISingletonService, SingletonService>();
  services.AddScoped<IScopedService, ScopedService>();
  services.AddTransient<IProvider<IScopedService>, Provider<IScopedService>>();
  // other bindings here
}

不幸的是,这并没有按照我想要的方式工作,因为 IServiceProvider 实例的范围似乎也限于当前的 HTTP 请求,并且在处理不同请求期间我从我的提供者那里获得了完全相同的 ScopedDependency 实例:(

有任何提示我该如何解决这个问题吗? 是否有比 ServiceProvider 更高级别的对象,大致绑定到应用程序生命周期(而不是当前请求),创建请求范围对象(或 ServiceProvider 本身)的实例,我可以将其注入到我的 Provider 对象而不是 ServiceProvider 中?例如,在 Java 中,如果我使用 google Guice 作为 DI 框架,则会有一个 Injector 对象,通常在应用程序启动时创建,该对象保存所有类型绑定并具有一个方法

<T> T getInstance(Class<T> type);

它检查当前作用域是什么并返回相应的实例。

edit:

我认为一种可能的方法是每次在 Proivder.Get() 方法中获取对 ServiceProvider 实例的新引用,而不是注入构造函数并存储为实例变量。这样,我的组件仍然不会受到对特定于框架的 IServiceProvider 的引用的污染,因为在它们通过抽象 IProvider 接口访问的 Provider 实现中,它将对它们隐藏起来。然而,我无法在网上找到是否可以从我的 Provider 类获取这样的引用以及如何执行此操作。任何朝这个方向的指示将不胜感激:)

Thanks!


好的,找到了:

public class Provider<T> : IProvider<T> {
    IHttpContextAccessor contextAccessor;
    public Provider(IHttpContextAccessor contextAccessor) {
        this.contextAccessor = contextAccessor;
    }
    T IProvider<T>.Get() {
        return contextAccessor.HttpContext.RequestServices.GetService<T>();
    }
}

并在启动中:

    public void ConfigureServices(IServiceCollection services) {
        services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<ISingletonService, SingletonService>();
        services.AddScoped<IScopedService, ScopedService>();
        services.AddTransient<IProvider<IScopedService>, Provider<IScopedService>>();
        // other bindings
    }

:)

see https://github.com/aspnet/Hosting/issues/793有关使用和注册 HttpContextAccessor 的更多详细信息

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

如何在 C# / ASP 中的单例中使用范围依赖 的相关文章

  • 如何为 C 分配的 numpy 数组注册析构函数?

    我想在 C C 中为 numpy 数组分配数字 并将它们作为 numpy 数组传递给 python 我可以做的PyArray SimpleNewFromData http docs scipy org doc numpy reference
  • 如何修复此错误“GDI+ 中发生一般错误”?

    从默认名称打开图像并以默认名称保存 覆盖它 我需要从 Image Default jpg 制作图形 将其放在 picturebox1 image 上并在 picurebox1 上绘制一些图形 它有效 这不是我的问题 但我无法保存 pictu
  • XamlReader.Load 在后台线程中。是否可以?

    WPF 应用程序具有从单独的文件加载用户控件的操作 使用XamlReader Load method StreamReader mysr new StreamReader pathToFile DependencyObject rootOb
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • 如何从 .resx 文件条目获取注释

    资源文件中的字符串有名称 值和注释 The ResXResourceReader类让我可以访问名称和值 有办法看评论吗 你应该能够得到Comment via ResXDataNode class http msdn microsoft co
  • 将 System.Windows.Input.KeyEventArgs 键转换为 char

    我需要将事件参数作为char 但是当我尝试转换 Key 枚举时 我得到的字母和符号与传入的字母和符号完全不同 如何正确地将密钥转换为字符 这是我尝试过的 ObserveKeyStroke this new ObervableKeyStrok
  • 用于检查项目文件中的项目变量和引用路径的 api

    我正在研究一个 net application VS2010 与 x 没有 解和变量号这些解决方案中的项目数量 我需要检查项目属性 特定于一定数量的项目 是否同质 并且检查 验证构建期间的参考路径 有没有一个API是这样的吗 如果没有 我该
  • C# Dns.GetHostEntry 不返回连接到 WiFi 的移动设备的名称

    我有一个 C 中的 Windows 窗体应用程序 我试图获取列表中所有客户端的主机名 下面给出的是 ra00l 来自此链接的代码示例 GetHostEntry 非常慢 https stackoverflow com questions 99
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • 当下拉列表内部触发选定索引更改事件时,引导模式关闭

    我在 Bootstrap 模式中有一个 ASP NET 图表 一切都工作正常 直到我在里面添加了一个下拉列表 每次我在下拉列表中选择一个新项目时 所选项目更改事件都会触发 并且如果事件内没有代码 则 Boostrap 模式会关闭 这是模式引
  • 未定义的行为或误报

    我 基本上 在野外遇到过以下情况 x x 5 显然 它可以在早期版本的 gcc 下编译干净 在 gcc 4 5 1 下生成警告 据我所知 警告是由 Wsequence point 生成的 所以我的问题是 这是否违反了标准中关于在序列点之间操
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • C++:.bmp 到文件中的字节数组

    是的 我已经解决了与此相关的其他问题 但我发现它们没有太大帮助 他们提供了一些帮助 但我仍然有点困惑 所以这是我需要做的 我们有一个 132x65 的屏幕 我有一个 132x65 的 bmp 我想遍历 bmp 并将其分成小的 1x8 列以获
  • 等待线程完成

    private void button1 Click object sender EventArgs e for int i 0 i lt 15 i Thread nova new Thread Method nova Start list
  • 用于 C# 的 TripleDES IV?

    所以当我说这样的话 TripleDES tripledes TripleDES Create Rfc2898DeriveBytes pdb new Rfc2898DeriveBytes password plain tripledes Ke
  • Server.MapPath - 给定的物理路径,预期的虚拟路径

    我正在使用这行代码 var files Directory GetFiles Server MapPath E ftproot sales 在文件夹中查找文件 但是我收到错误消息说 给定物理路径但虚拟路径 预期的 我对在 C 中使用 Sys
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • 线程和 fork()。我该如何处理呢? [复制]

    这个问题在这里已经有答案了 可能的重复 多线程程序中的fork https stackoverflow com questions 1235516 fork in multi threaded program 如果我有一个使用 fork 的
  • 使用 GROUP 和 SUM 的 LINQ 查询

    请帮助我了解如何使用带有 GROUP 和 SUM 的 LINQ 进行查询 Query the database IEnumerable
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当

随机推荐