在Web窗体中创建自定义简单注入器作用域

时间:2018-08-01 20:01:35

标签: c# .net winforms dependency-injection simple-injector

我的Windows窗体应用程序中有一个文本框和一个按钮。当按下开始键并在文本框中输入值时,应使用该值打开一个新表格。我想为每个打开的表单创建一个范围。当我关闭表格时,我想关闭相关范围。

如何使用简单的注入器创建自定义范围?

这是一个简单的示例代码

static class Program
{
    static readonly Container container;

    static Program()
    {
        container = new Container();

        container.Register<MyProgram>();
        //??
        container.Register<MyCustomClass>(Lifestyle.Scoped);

        container.Verify();
    }

    static void Main()
    {
        //Something...
    }
}

class User
{
    public int UserID { get; set; }
    public string UserName { get; set; }
}

class MyCustomClass
{
    User _user;
    public MyCustomClass(User user)
    {
        _user = user;
    }

    public void Print()
    {
        Console.WriteLine(_user.UserName);
    }
}    

class MyProgram
{
    public void StartNewScope(string username, int userid)
    {
        //Start a new scope for this user
    }

    //End parameter can be different...
    public void EndScope(string username)
    {
        //End relevant scpoe
    }
}

1 个答案:

答案 0 :(得分:1)

Simple Injector中的默认作用域机制为环境。这意味着您可以创建一个范围,并且可以在该范围的 context 中的任何位置解析实例。当您有某种请求时,这种方法非常有用,并且在特定的“气泡”中,只需要范围。

但是,在使用Win Forms时,当您希望让每个带有其依赖项的Form都生活在其自己的范围内时,此模型不太直观,因为Form并不生活在孤立的上下文中,例如线程或异步上下文。在这种情况下,环境范围将不起作用。

this great answer中给出了解决此问题的可能方法。规定的解决方案是将表单注册为临时表单,并避免将任何范围内的依赖项作为表单对象图的一部分。相反,您确保在按下按钮时启动作用域,该作用域将在按钮事件结束时终止。正如答案所描述的,这可以使用组成根目录中的一些基础结构代码来完成。

我强烈建议该解决方案,因为它为表格带来了一种有趣的体系结构样式,该样式基于SOLID原理,并且具有优势,解决了典型应用程序存在的许多可维护性问题。

但是,如果不是这样,则可以在Simple Injector中切换到无环境范围。

这需要三件事:

  • 使用ScopedLifestyle.Flowing生活方式
  • 手动创建Scope实例
  • 直接从Scope实例中解析

以下代码显示了这一操作:

var container = new Container();

// Uses the non-ambient scoped lifestyle
container.Options.DefaultScopedLifestyle = ScopedLifestyle.Flowing;

container.Register<MyCustomClass>(Lifestyle.Scoped);

container.Register<MyForm>();

container.Verify();


using (var scope = new Scope(container))
{
    var form = scope.GetInstance<MyForm>();

    form.ShowDialog();
}

有时候表单的生命周期不清楚,这将在您调用Form.Show()而不是Form.ShowDialog时发生。在这种情况下,您可以通过钩住Closed事件来将范围的生存期与Form的生存期联系起来。 .NET关闭并处理该表单时,Scope及其所有Scoped依赖项也会随之消失。

您可以执行以下操作:

var scope = new Scope(container);

var form = scope.GetInstance<MyForm>();

from.Closed += (s, e) => scope.Dispose();