Как избежать поиска сервисов с помощью AutoFac 2 - PullRequest
5 голосов
/ 29 апреля 2010

Я создаю приложение, которое использует AutoFac 2 для DI. Я читал , что следует избегать использования статического IoCHelper (Service Locator).

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 в моем UnitOfWork за счет использования автоматически сгенерированных фабрик . Продолжая идти по этому пути, мне любопытно, смогу ли я полностью уничтожить свой 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 в каждый класс? Ниже перечислены 3 области, в которых я продолжаю опираться на ServiceLocator вместо внедрения конструктора:

  • AppSettings
  • Вход
  • Кэширование

1 Ответ

4 голосов
/ 29 апреля 2010

Я бы предпочел внедрить 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"];
        }
    }
}
...