瀏覽標籤:

DI

[C#][DI] 相互依賴造成循環注入死結

問題緣由

最近在寫 .NET Core 的時候遇到了一個問題

A circular dependency was detected for the service of type 'WebApplication1.Service.A1Service'

 

A1Service

public class A1Service
{
    private readonly string guid = null;
    private readonly A2Service _a2Service = null;

    public A1Service(A2Service a2Service)
    {
        _a2Service = a2Service;

        if (guid == null)
        {
            guid = Guid.NewGuid().ToString();
        }
    }

    public void Run()
    {
        Console.WriteLine("A1Service: " + guid);
    }

    public void RunOther()
    {
        _a2Service.Run();
    }
}

 

這是網路教學文章上常見的從建構子中依賴注入 A2Service 的程式
接著我們再來看看另外一支程式

A2Service

public class A2Service
{
    private readonly string guid = null;
    private readonly A1Service _a1Service = null;

    public A2Service(A1Service a1Service)
    {
        _a1Service = a1Service;

        if (guid == null)
        {
            guid = Guid.NewGuid().ToString();
        }
    }

    public void Run()
    {
        Console.WriteLine("A2Service: " + guid);
    }

    public void RunOther()
    {
        _a1Service.Run();
    }
}

 

 

這裡就發生了一個循環依賴的問題 A1Service 在建構子中注入了 A2Service,而 A2Service 也在建構子中注入了 A1Service,造成兩個物件互相依賴造成 Exception

解決方法

改成不直接在建構子中注入 Service ,改注入 IServiceProvider,再利用 GetService 這個方法來取得物件,這樣就可以順利解決這個問題囉。

A3Service

public class A3Service
{
    private readonly string guid = null;
    private readonly IServiceProvider _serviceProvider = null;

    public A3Service(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;

        if (guid == null)
        {
            guid = Guid.NewGuid().ToString();
        }
    }

    public void Run()
    {
        Console.WriteLine("A3Service: " + guid);
    }

    public void RunOther()
    {
        _serviceProvider.GetService<A4Service>().Run();
    }
}

 

A4Service

public class A4Service
{
    private readonly string guid = null;
    private readonly IServiceProvider _serviceProvider = null;

    public A4Service(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;

        if (guid == null)
        {
            guid = Guid.NewGuid().ToString();
        }
    }

    public void Run()
    {
        Console.WriteLine("A4Service: " + guid);
    }

    public void RunOther()
    {
        _serviceProvider.GetService<A3Service>().Run();
    }
}

 

       

[C#][ASP.NET MVC5][Autofac] DI Framework – AutofacConfig.cs

之前嘗試很多次都失敗,這次終於成功註冊Controller、Service與Repository了,來記錄一下設定檔。

  • AutofacConfig.cs
    /// <summary>
    /// DI設定檔
    /// </summary>
    public class AutofacConfig
    {
    	/// <summary>
    	/// 註冊DI注入物件資料
    	/// </summary>
    	public static void Register()
    	{
    		// 容器建立者
    		ContainerBuilder builder = new ContainerBuilder();
    
    		// 註冊Controllers
    		builder.RegisterControllers(Assembly.GetExecutingAssembly());
    
    		// 註冊Service
    		builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
    			   .Where(t => t.Name.EndsWith("Service"))
    			   .AsSelf();
    
    		// 註冊Repository
    		builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
    			   .Where(t => t.Name.EndsWith("Repository"))
    			   .AsSelf();
    
    		// 建立容器
    		IContainer container = builder.Build();
    
    		// 解析容器內的型別
    		AutofacDependencyResolver resolver = new AutofacDependencyResolver(container);
    
    		// 建立相依解析器
    		DependencyResolver.SetResolver(resolver);
    	}
    }
  • Global.asax
    protected void Application_Start()
    {
        //加入這行
        AutofacConfig.Register();
    }