【问题标题】:Dependency Injection not resolving fast enough for use when a service relies on another service当一个服务依赖于另一个服务时,依赖注入的解决速度不够快
【发布时间】:2020-09-04 20:27:30
【问题描述】:

我将两个服务注入到我的 dot net core web api 中,主要服务依赖于辅助服务中的数据。辅助服务在构造函数中填充这些数据,但是当主服务开始使用这些数据时,它还没有准备好,因为辅助服务的构造函数在需要的时候还没有完成。

我认为 DI 和编译器会正确解析和链接这些服务,因此在完全实例化之前不会使用辅助服务。

我如何告诉主服务等到辅助服务完全解析并实例化?

我正在做的通用示例代码。我在 MainSerice 中调用 DoSomething(),HelperService 调用外部 API 来获取一些数据,这些数据在 MainService 中是需要的。

StartUp.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IHelperService, HelperService);
    services.Scoped<IMainService, MainService);
}

MainService.cs

public class MainService : IMainService
{
    private readonly IHelperServuce _helper;

    public MainService(IHelperService HelperService)
    {
        _helper = HelperService;
    }

    public void DoSomething()
    {   
        string helperParameter = _helper.Param1; //This fails because the constructor of HelperService has not finished 
    }
}

HelperService.cs

public class HelperService : IHelperService
{

    public HelperService()
    {
        GetParamData();
    }

    private async void GetParamData()
    {
        var response = await CallExternalAPIForParameters(); //This may take a second.
        Params1 = response.value;
    }


    private string _param1;

    public string Param1
    {
        get
        {
            return _param1;
        }

        private set
        {
            _param1 = value;
        }
    }
}

【问题讨论】:

  • 你没有在构造函数中等待异步方法GetParamData()数据。那当然是不可能的。您的构造函数应该只初始化简单数据。您可以解决此问题,而不是使用属性返回,您也可以从名为 (例如) Task&lt;string&gt; GetParam1() 的方法返回 Task&lt;string&gt;。哪个可以缓存字符串值。
  • @JeroenvanLangen 我是 DI 和 netcore 的新手,这个例子只有 1 个参数,但真正的项目有两个。那么 Task GetParam() 会是方法定义吗?然后构造函数会调用任务?
  • 问题是不能等待构造函数。它是在实例化对象时调用的初始化“方法”。构造函数不能分解为状态机。

标签: c# .net-core dependency-injection asp.net-core-3.1


【解决方案1】:

将 lambda 传递给初始化主服务中的变量的辅助服务,如...

Helper service.getfirstparam(  (response) -> 
    {  firstparam = response.data;});

    While (firstparam == null)
          sleep

  // now do your processing

【讨论】:

    【解决方案2】:

    您不是在等待构造函数中的异步方法 GetParamData() 数据。那当然是不可能的。您的构造函数应该只初始化简单数据。您可以通过(例如)Task&lt;string&gt; GetParam1() 的方法返回任务,而不是使用属性返回来解决此问题。哪个可以缓存字符串值。

    例如:

    public class HelperService : IHelperService
    {
        private string _param1;
    
        // note: this is not threadsafe.
        public async Task<string> GetParam1()
        {
            if(_param1 != null)
                return _param1;
    
            var response = await CallExternalAPIForParameters(); //This may take a second.
            _params1 = response.value;
            return _param1;
        }
    }
    

    您甚至可以返回 ValueTask&lt;string&gt;,因为大多数调用都可以同步执行。

    【讨论】:

    • 我明白你现在的意思了,不会有构造函数。即使是单例,它也不是线程安全的吗?我们正在从程序将使用的 Web 服务中检索凭据,因此我们只需要它在程序启动时运行一次,但每次之后它们都不会改变。也许有更好的方法从 Startup.cs 中的 Configure(IApplicationBuilder app, IWebHostEnvironment env) 填充这些数据?
    • 对于线程安全,我的意思是我不完全确定实例中的这个方法不会被其他线程调用。
    猜你喜欢
    • 2020-01-27
    • 2017-10-31
    • 2016-08-07
    • 2022-12-20
    • 1970-01-01
    • 2019-10-19
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    相关资源
    最近更新 更多