使用AutoFac 2避免服务定位器

时间:2010-04-29 13:17:24

标签: ioc-container autofac

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

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

previous question的答案中,我找到了一种方法,可以通过Auto-generated Factories帮助减少在我的UnitOfWork中使用IoCHelper的需要。继续沿着这条路走下去,我很好奇我是否可以彻底消除我的IoCHelper。

以下是该方案:

我有一个静态的Settings类,它作为我的配置实现的包装器。由于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
  • 登录
  • 缓存

1 个答案:

答案 0 :(得分:4)

我宁愿将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"];
        }
    }
}