简体   繁体   English

避免依赖注入中的依赖周期

[英]Avoid Dependency cycles in Dependency Injection

C# Windows Form application. C#Windows窗体应用程序。 I have an Hub and a class. 我有一个集线器和一个类。 Both should reference each other. 两者都应该互相参考。 This is because: 这是因为:

  1. from the hub I need to call the class' methods 从中心我需要调用类的方法
  2. from the class I need to retrieve my Hub 从班级中,我需要检索我的Hub

Right now I'm able to do the first point using Autofac: 现在,我可以使用Autofac进行第一点:

using Autofac;
using Autofac.Integration.SignalR;
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Hosting;
using Owin;
using MyProject.Classes;
using System;
using System.Reflection;
using System.Windows.Forms;

namespace MyProject
{
    static class Program
    {
        static IDisposable webApp;

        [STAThread]
        static void Main()
        {
            string url = "http://localhost:8080";
            webApp = WebApp.Start(url);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Engine());
        }
    }

    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(CorsOptions.AllowAll);

            var builder = new ContainerBuilder();
            var config = new HubConfiguration();
            builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();
            builder.RegisterType<Erp>().PropertiesAutowired().InstancePerLifetimeScope();
            var container = builder.Build();
            config.Resolver = new AutofacDependencyResolver(container);
            app.UseAutofacMiddleware(container);
            app.MapSignalR(config);
        }
    }
}

here the Hub: 在这里枢纽:

using Microsoft.AspNet.SignalR;
using MyProject.Classes;
using System;
using System.Threading.Tasks;

namespace MyProject.Hubs
{
    public class LiveHub : Hub
    {
        private readonly Erp _erp;

        public LiveHub(Erp erp)
        {
            _erp = erp;
        }

        public override Task OnConnected()
        {
            _erp.someMethod();
            return base.OnConnected();
        }
    }
}

and here Erp.cs: 在这里Erp.cs:

public class Erp
{
    public Erp()
    {
    }

    public void SomeMethod()
    {
        // do something
    }

    public void SomeOtherMethod()
    {
        // usually I do:
        var hub = GlobalHost.ConnectionManager.GetHubContext<LiveHub>();
        hub.Clients.All.foo();
    }
}

but here I read: 在这里我读到:

A common error in OWIN integration is use of the GlobalHost. OWIN集成中的一个常见错误是使用GlobalHost。 In OWIN you create the configuration from scratch. 在OWIN中,您可以从头开始创建配置。 You should not reference GlobalHost anywhere when using the OWIN integration. 使用OWIN集成时,不应在任何地方引用GlobalHost。 Microsoft has documentation about this and other IoC integration concerns here. Microsoft在此处有关于此以及其他IoC集成问题的文档。

If I cannot use the "old" method, how should I retrieve my Hub? 如果我不能使用“旧”方法,应该如何检索我的集线器? I tried to add another DI in Erp for LiveHub but it doesn't work. 我试图在Erp中为LiveHub添加另一个DI,但是它不起作用。 In my form I create an instance of Erp: 在我的表单中,我创建一个Erp实例:

public partial class Engine : Form
{
    private Erp _erp = new Erp();

    public Engine()
    {
        InitializeComponent();
    }
}

if I add that DI the declaration will be impossible because I need to define the LiveHub in constructor, that requires itself the Erp parameter... 如果我添加DI,则声明将是不可能的,因为我需要在构造函数中定义LiveHub,这本身需要Erp参数...

What am I not seeing? 我没看到什么?

You can decouple the Hub from the object ( Erp in your case) by emitting events. 您可以通过发出事件将Hub与对象(在您的情况下为Erp )分离。

namespace MyProject.Hubs
{
    public class LiveHub : Hub
    {    
        public event Action SomethingHappened;

        public override Task OnConnected()
        {
            SomethingHappened?.Invoke();
            return base.OnConnected();
        }
    }
}

Now you can connect the Erp without the Hub having to know it. 现在,您无需集线器即可连接Erp You will have to subscribe to the event somewhere else in your code. 您将不得不在代码中的其他位置订阅该事件。 But the circular reference is broken. 但是循环引用被破坏了。

To decouple Engine from Form you could do something like this: 要将Engine与Form分离,可以执行以下操作:

public partial class EngineForm : Form
{    
    public EngineForm()
    {
        InitializeComponent();
    }
}

public class Engine
{
    public Engine(EngineForm form, Erp erp)
    {
        this.form = form;
        this.erp = erp;
    }

    // Here is where you'll write some code to coordinate
    // communication between the Erp and the EngineForm. 
    //
    // The main advantage is that you can inject the Erp 
    // and have it preconfigured.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM