使用 AutoFac 2 避免服务定位器

发布于 2024-08-30 08:56:20 字数 1895 浏览 3 评论 0原文

我正在构建一个使用 AutoFac 2 进行 DI 的应用程序。我阅读使用静态 IoCHelper(服务定位器)应该是避免了。

IoCHelper.cs

public static class IoCHelper
{
    private static AutofacDependencyResolver _resolver;

    public static void InitializeWith(AutofacDependencyResolver resolver)
    {
        _resolver = resolver;
    }

    public static T Resolve<T>()
    {
        return _resolver.Resolve<T>();
    }
}

上一个问题,我找到了一种方法,通过使用 自动生成的工厂。继续沿着这条路走下去,我很好奇是否可以完全消除我的 IoCHelper。

场景如下:

我有一个静态设置类,它充当我的配置实现的包装器。由于 Settings 类是大多数其他类的依赖项,因此包装器使我不必在整个应用程序中注入设置类。

Settings.cs

public static class Settings
{
    public static IAppSettings AppSettings
    {
        get
        {
            return IoCHelper.Resolve<IAppSettings>();
        }
    }
}

public interface IAppSettings
{
    string Setting1 { get; }
    string Setting2 { get; }
}

public class AppSettings : IAppSettings
{
    public string Setting1
    {
        get
        {
            return GetSettings().AppSettings["setting1"];
        }
    }

    public string Setting2
    {
        get
        {
            return GetSettings().AppSettings["setting2"];
        }
    }

    protected static IConfigurationSettings GetSettings()
    {
        return IoCHelper.Resolve<IConfigurationSettings>();
    }
}

有没有一种方法可以在不使用服务定位器且不必将 AppSettings 注入到每个类中的情况下处理此问题?下面列出了我一直依赖 ServiceLocator 而不是构造函数注入的 3 个领域:

  • AppSettings
  • 日志记录
  • 缓存

I'm building an application which uses AutoFac 2 for DI. I've been reading that using a static IoCHelper (Service Locator) should be avoided.

IoCHelper.cs

public static class IoCHelper
{
    private static AutofacDependencyResolver _resolver;

    public static void InitializeWith(AutofacDependencyResolver resolver)
    {
        _resolver = resolver;
    }

    public static T Resolve<T>()
    {
        return _resolver.Resolve<T>();
    }
}

From answers to a previous question, I found a way to help reduce the need for using my IoCHelper in my UnitOfWork through the use of Auto-generated Factories. Continuing down this path, I'm curious if I can completely eliminate my IoCHelper.

Here is the scenario:

I have a static Settings class that serves as a wrapper around my configuration implementation. Since the Settings class is a dependency to a majority of my other classes, the wrapper keeps me from having to inject the settings class all over my application.

Settings.cs

public static class Settings
{
    public static IAppSettings AppSettings
    {
        get
        {
            return IoCHelper.Resolve<IAppSettings>();
        }
    }
}

public interface IAppSettings
{
    string Setting1 { get; }
    string Setting2 { get; }
}

public class AppSettings : IAppSettings
{
    public string Setting1
    {
        get
        {
            return GetSettings().AppSettings["setting1"];
        }
    }

    public string Setting2
    {
        get
        {
            return GetSettings().AppSettings["setting2"];
        }
    }

    protected static IConfigurationSettings GetSettings()
    {
        return IoCHelper.Resolve<IConfigurationSettings>();
    }
}

Is there a way to handle this without using a service locator and without having to resort to injecting AppSettings into each and every class? Listed below are the 3 areas in which I keep leaning on ServiceLocator instead of constructor injection:

  • AppSettings
  • Logging
  • Caching

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

还给你自由 2024-09-06 08:56:20

我宁愿将 IAppSettings 注入到每个需要它的类中,只是为了让它们摆脱对 Settings 的隐藏依赖。问题是,您真的需要将这种依赖关系散布到每个类中吗?

如果您真的想使用静态 Settings 类,我至少会尝试使其测试友好/可伪造。考虑一下:

public static class Settings
{
    public static Func<IAppSettings> AppSettings { get; set; }
}

以及在哪里构建容器:

var builder = new ContainerBuilder();
...
var container = builder.Build();

Settings.AppSettings = () => container.Resolve<IAppSettings>();

这将允许在测试期间用假货进行交换:

Settings.AppSettings = () => new Mock<IAppSettings>().Object;

现在您可以使用常规构造函数注入来执行 AppSettings 类(我假设只有一个)。我还假设您确实希望对设置属性的每次调用进行解析,从而注入一个工厂委托,在需要时检索实例。如果不需要,您当然应该直接注入 IConfigurationSettings 服务。

public class AppSettings : IAppSettings
{
    private readonly Func<IConfigurationSettings> _configurationSettings;

    public AppSettings(Func<IConfigurationSettings> configurationSettings)
    {
        _configurationSettings = configurationSettings;
    }

    public string Setting1
    {
        get
        {
            return _configurationSettings().AppSettings["setting1"];
        }
    }

    public string Setting2
    {
        get
        {
            return _configurationSettings().AppSettings["setting2"];
        }
    }
}

I would rather inject IAppSettings into every class that needs it just to keep them clean from the hidden dependency on Settings. Question is, do you really need to sprinkle that dependency into each and every class?

If you really want to go with a static Settings class I would at least try to make it test-friendly/fakeable. Consider this:

public static class Settings
{
    public static Func<IAppSettings> AppSettings { get; set; }
}

And where you build your container:

var builder = new ContainerBuilder();
...
var container = builder.Build();

Settings.AppSettings = () => container.Resolve<IAppSettings>();

This would allow to swap out with fakes during test:

Settings.AppSettings = () => new Mock<IAppSettings>().Object;

Now the AppSettings class (which I assume there is only one of) you could do with regular constructor injection. I assume also that you really want to do a resolve on each call to your settings properties, thus injecting a factory delegate that retrieves an instance when needed. If this is not needed you should of course inject the IConfigurationSettings service directly.

public class AppSettings : IAppSettings
{
    private readonly Func<IConfigurationSettings> _configurationSettings;

    public AppSettings(Func<IConfigurationSettings> configurationSettings)
    {
        _configurationSettings = configurationSettings;
    }

    public string Setting1
    {
        get
        {
            return _configurationSettings().AppSettings["setting1"];
        }
    }

    public string Setting2
    {
        get
        {
            return _configurationSettings().AppSettings["setting2"];
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文