在ASP.NET Core应用程序中实现依赖注入时发生InvalidOperationException

时间:2017-05-16 07:14:07

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

当我正在学习依赖注入时,所以我也分享了我的理解(请在任何你想要的地方纠正我)。下面的示例背后的概念是检查使用依赖注入的优势,因为它有助于在应用程序中实现松散耦合,这将进一步阻止我在具体定义( classes <的情况下在项目中进行大量更改/ em>)将来会发生变化。

IEmailService - 界面:

public interface IEmailService
{
    void SendMail();
}

EmailService - 继承上述接口的类

public class EmailService : IEmailService
{
    public EmailService(string emailFrom, string emailTo)
    {

    }

    public void SendMail()
    {
        // Code here 
    }
}

的HomeController

public class HomeController : Controller
{
    private IEmailService _service;

    public HomeController(IEmailService service)
    {
       _service = service;
    }

    public IActionResult Index()
    {
        _service.SendMail();
        return View();
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   // Add framework services.
   ...
   services.AddTransient<IEmailService, EmailService>();
   ...
}

实际假设

我假设之前在 EmailService 类中没有参数化构造函数,但将来我觉得我需要添加一个参数化构造函数,但它不会对这些控制器产生影响(喜欢 HomeController ),它们使用抽象( interfaces )间接访问它们。

不幸的是,当我运行上面的代码时,我得到以下异常,如果我从 EmailService 类中删除参数化构造函数,它似乎就会消失。

  

InvalidOperationException:尝试激活“DependencyInjectionDemo.Services.EmailService”时无法解析类型“System.String”的服务。

1 个答案:

答案 0 :(得分:4)

您可以使用lambda注册EmailService

services.AddTransient<IEmailService>(_ => new EmailService("from@", "to@"));
然而,

emailFromemailTo似乎是运行时数据,这意味着Controller可能负责将此信息提供给IEmailService。由于EmailService 与控制器解耦,这意味着控制器不对其创建负责。

通常,您应该使用运行时数据来防止需要初始化组件(在您的情况下为EmailService),如here所述,建议是:

  

在构建期间不要将运行时数据注入应用程序组件;它会导致歧义,使组合根变得更加复杂,并且使得验证DI配置的正确性变得非常困难。我的建议是让运行时数据流过构造对象图的方法调用。

在您的情况下,这基本上意味着将IEmailService抽象更改为以下内容:

public interface IEmailService
{
    void SendMail(string emailFrom, string emailTo);
}