避免依赖注入中的依赖循环

时间:2017-12-18 15:42:14

标签: c# dependency-injection signalr autofac

C#Windows窗体应用程序。 我有一个Hub和一个班级。两者都应该互相参考。 这是因为:

    来自集线器的
  1. 我需要调用类'methods
  2. 来自我需要检索我的Hub的课程
  3. 现在我可以使用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);
            }
        }
    }
    

    这里是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();
            }
        }
    }
    

    这里是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();
        }
    }
    

    here我读到了:

      

    OWIN集成中的常见错误是使用GlobalHost。在OWIN中,您可以从头开始创建配置。使用OWIN集成时,不应在任何地方引用GlobalHost。 Microsoft在此处提供了有关此问题和其他IoC集成问题的文档。

    如果我不能使用“旧”方法,我应该如何检索我的Hub? 我试图在Erp中为LiveHub添加另一个DI,但它不起作用。在我的表单中,我创建了一个Erp实例:

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

    如果我添加DI那么声明是不可能的,因为我需要在构造函数中定义LiveHub,这需要自己的Erp参数......

    我没看到什么?

1 个答案:

答案 0 :(得分:2)

您可以通过发出事件将Hub与对象(案例中为Erp)分离。

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

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

现在您可以连接Erp,而Hub不必知道它。您必须在代码中的其他位置订阅该事件。但循环引用被打破了。

要将引擎与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.
}