如何将数据传递到注入的服务

时间:2018-08-15 16:48:35

标签: c# dependency-injection inversion-of-control

我想编写一个小的WinForms或WPF程序,该程序控制一次只有一个人/计算机通过网络共享使用特定的共享文件。该文件在工作时需要本地复制,并在工作完成后复制回网络共享。

我想用一个按钮创建一个小的WPF应用程序,以将文件标记为已锁定,在本地复制并打开与该文件扩展名关联的应用程序。关闭此应用程序后,文件将被复制回网络共享并释放锁定。每台计算机都将使用此应用程序访问该文件,因此,绝对不能是两台计算机同时编辑同一文件。

应用程序必须具有某种配置文件,其中包含本地和远程文件夹的路径,文件名以及打开该文件的应用程序的路径。为了简化应用程序的设置,可以使用SettingsWindow来完成。

我正在尝试使用IoC和某种轻量级的DI容器(即SimpleInjector)来完成此操作,但是我对如何正确执行操作有一些疑问:

Program.cs

static class Program
{
    [STAThread]
    static void Main()
    {
        var container = Bootstrap();

        // Any additional other configuration, e.g. of your desired MVVM toolkit.

        RunApplication(container);
    }

    private static Container Bootstrap()
    {
        // Create the container as usual.
        var container = new Container();

        // Register your types, for instance:
        container.Register<ILauncher, Launcher>();
        container.Register<IFileSyncService, FileSyncronizer>();
        container.Register<IAppRunnerService, AppRunnerService>();
        container.Register<ILockService, LockService>();

        // Register your windows and view models:
        container.Register<MainWindow>();
        container.Register<ConfigurationWindow>();

        container.Verify();

        return container;
    }

    private static void RunApplication(Container container)
    {
        try
        {
            var app = new App();
            var mainWindow = container.GetInstance<MainWindow>();
            app.Run(mainWindow);
        }
        catch (Exception ex)
        {
            //Log the exception and exit
        }
    }
}

MainWindow

我修改了构造函数以接收将由DI容器解析的接口ILauncher。

    public partial class MainWindow : Window
    {
        public MainWindow(ILauncher launcher)
        {
            InitializeComponent();
        }
…
}

ILauncher界面

public interface ILauncher
{
    void Run();
}

启动器实现

启动器实现将负责协调启动应用程序和编辑文件所需的每个任务。这包括:检查和获取锁,同步文件,执行和监视应用程序已关闭。要遵循“单一职责原则”(SRP),可以通过注入一些服务来做到这一点:

public class Launcher : ILauncher
{
    public Launcher(
        ILockService lockService,
        IAppRunnerService appRunnerService,
        IFileSyncService fileSyncService
        )
    {
        LockService = lockService;
        AppRunnerService = appRunnerService;
        FileSyncService = fileSyncService;
    }

    public ILockService LockService { get; }
    public IAppRunnerService AppRunnerService { get; }
    public IFileSyncService FileSyncService { get; }

    public void Run()
    {
        //TODO check lock + adquire lock
        //TODO Sinchronize file
        //TODO Subscribe to the IAppRunnerService.OnStop event 
        //TODO Start app through IAppRunnerService.Run method
    }
}

我的问题:

  1. 使用“ new”关键字或在类或窗口中手动调用容器来创建新实例是一种不好的做法,因此桌面应用程序(通常是某种主窗口)的入口点应该询问(通过构造函数)进行所有操作。当应用程序增长时,这似乎不是正确的方法。我对吗?解决方案是什么?

  2. 在我的应用程序中,每个服务都需要某种类型的运行时数据(可执行文件路径,本地或远程目录…)。容器在应用程序执行的早期就实例化了它们,甚至在此数据未知之前也是如此。服务如何接收此数据? (请注意,以后可以通过SettingsWindow修改数据)。

对不起,本文的扩展名是我,但我想让我的问题和上下文更清楚。

1 个答案:

答案 0 :(得分:1)

  1. 您已经说过,您必须在入口点请求一些服务,但是什么意思是要求一切?您的入口点应仅具有直接用作ctor参数指定的服务。如果您的应用程序增长,并且突然有许多服务被您的入口点直接调用-这可能表明某些服务可以合并为一个更大的数据包。不过,这是基于意见的领域,只要您认为它可以维护就可以。

  2. 这里有许多可能的解决方案,其中一个是ISettingsManager,它允许跨所有将其视为依赖项的服务实时访问设置。