【问题标题】:ASP.NET Core mock service only in scope of one requestASP.NET Core 模拟服务仅在一个请求的范围内
【发布时间】:2020-09-24 10:06:22
【问题描述】:

假设我在应用程序启动时注册了一些服务,并且我想用另一个实现替换它,仅用于单个请求。 有没有办法做到这一点?

为什么我需要它?因为在某些情况下,我希望在没有数据库中该逻辑的必要数据的情况下继续执行某些逻辑,而是通过在请求中传递该数据并模拟它,因此从数据库获取它的服务将返回从请求传递的模拟数据。

【问题讨论】:

    标签: c# asp.net-core dependency-injection mocking service-provider


    【解决方案1】:

    一旦应用程序运行,就无法替换注册。这个问题的一般解决方案是使用代理实现,根据需要的条件转发到所需的实现。

    所以考虑以下抽象和实现:

    public interface IMyService
    {
        void DoSomething();
    }
    
    public class RealService : IMyService
    {
        public void DoSomething() { ... }
    }
    
    
    public class AlternativeService : IMyService
    {
        public void DoSomething() { ... }
    }
    

    在这两个实现旁边,您可以创建第三个代理实现:

    public class ProxyService : IMyService
    {
        private readonly RealService real;
        private readonly AlternativeService alternative;
        private readonly IHttpContextAccessor accessor;
    
        public ProxyService(
            RealService real,
            AlternativeService alternative,
            IHttpContextAccessor accessor)
        {
            this.real = real;
            this.alternative = alternative;
            this.accessor = accessor;
        }
    
        public void DoSomething() => this.Service.DoSomething();
    
        private IMyService Service => this.UseRealThing ? this.real : this.alternative.
    
        private bool UseRealThing => this.accessor.HttpContext.User.Name != "Artem";
    }
    

    ProxyService 实现根据某些条件将任何传入呼叫转发到实际实现或替代实现。在示例中,该条件读取当前请求的用户名,但实际上它可以是任何内容。

    类可以注册如下:

    services.AddTransient<IMyService, ProxyService>();
    services.AddScoped<RealService>();
    services.AddScoped<AlternativeService>();
    

    【讨论】:

      【解决方案2】:

      假设您已经注册了接口实现,我的解决方案是拥有 2 个接口。您可以使用接口继承来管理一致性。

      所以你最终会得到类似的东西

      interface IDataProvider
      {
         object GetData();
      }
      
      interface IDbDataProvider : IDataProvider
      {
      }
      
      interface IMockDataProvider : IDataProvider
      {
      }
      
      class DbDataProvider() : IDbDataProvider
      {
          object GetData()
          {
              // Do databasey stuff
          }
      }
      
      class MockDataProvider() : IMockDataProvider
      {
          object GetData() => new MockData(); // Or whatever
      }
      
      class Normal(IdbDataProvider dataProvider)
      {
          var data = dataProvider.GetData();
      }
      
      class Weird(IMockDataProvider dataProvider)
      {
          var data = dataProvider.GetData();
      }
      
      

      【讨论】:

        【解决方案3】:

        通用的问题是如何替换注册的实现?

        我想你会在这里找到回复:Replace service registration in ASP.NET Core built-in DI container?

        【讨论】:

        • 感谢您的回答,但问题是提供的选项替换了整个 serviceProvider 中所有请求的服务实现,但我需要的只是在 SINGLE 请求的范围内替换它
        • 好吧,我认为您需要另找方法,据我所知,.net core DI 系统不允许在启动之外访问IServiceCollection。通过一些技巧和技巧,它也许是可能的,但我认为这不是一个好主意。这篇文章描述了其他一些方式:stackoverflow.com/a/57790127/12661958
        猜你喜欢
        • 2015-04-14
        • 2022-06-28
        • 2019-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-03
        相关资源
        最近更新 更多