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

Bar*_*ran 1 .net c# dependency-injection winforms 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
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 5

简单注入器中的默认作用域机制是环境的。这意味着您可以创建一个范围,并且在该范围的上下文中的任何位置都可以解析实例。当您有某种请求,并且在特定的“泡沫”内,只有所需的范围时,这非常有效。

然而,当使用 Win Forms 时,当您想让每个 Form 及其依赖项存在于其自己的范围内时,此模型不太直观,因为 Form 并不存在于隔离的上下文中,例如线程或异步上下文。在这种情况下,环境作用域不起作用。

这个伟大的答案给出了这个问题的可能解决方案。规定的解决方案是将表单注册为瞬态,并防止将任何作用域依赖项作为表单对象图的一部分。相反,您可以确保按下按钮时启动作用域,并在按钮事件结束时结束作用域。正如答案所描述的,这可以使用作为组合根一部分的一些基础设施代码来完成。

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

但是,如果这不是一个选项,则可以在简单注入器中切换到无环境范围。

这需要三件事:

  • 使用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();
}
Run Code Online (Sandbox Code Playgroud)

有时 Form 的生命周期并不那么明确,当您调用Form.Show()而不是 时,就会发生这种情况Form.ShowDialog。在这种情况下,您可以通过挂钩事件将范围的生命周期与表单的生命周期联系起来Closed。当 .NET 关闭并处理表单时,Scope其所有Scoped依赖项也将关闭并处理。

您可以按如下方式执行此操作:

var scope = new Scope(container);

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

from.Closed += (s, e) => scope.Dispose();
Run Code Online (Sandbox Code Playgroud)