Как использовать DI-контейнер (Autofac) для регистрации сервиса с параметрами - PullRequest
0 голосов
/ 08 марта 2019

У меня есть следующий фрагмент кода на моем ViewModel, и я хотел бы избавиться от ключевого слова new и возложить ответственность за создание на DI-контейнер. Однако у меня возникают некоторые трудности с возможностью ввода IDataFileReader в мой ViewModel, поскольку данный параметр progress связан со свойством ViewModel ProgressBarValue.

По сути, мой файл-ридер требует прогресс в качестве параметра, чтобы я мог отображать прогресс в своем пользовательском интерфейсе.

Так что вопрос в том, как зарегистрировать IDataFileReader с модулями AutoFac на ViewModelLocator

VieModel.cs

  ProgressBarIsIndetermined = true;
  var progress = new Progress<int>(status => { ProgressBarValue = status; });

  await Task.Run(() =>
  {
    IDataFileReader fileImporter = new DataFileReader(progress);
    DataSet = new ObservableCollection<MeasurementPoint>(fileImporter.DataSet);
  });

Я использую Mvvm Light viewmodelLocator и MVVM с WPF. Для простых сервисов, которые не требуют каких-либо параметров, я могу легко добиться этого путем внедрения в конструктор.

ViewModelLocator.cs

static ViewModelLocator()
{
  var builder = new ContainerBuilder();
  builder.RegisterModule<AutofacModule>();
  var container = builder.Build();
  ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
}

public SettingsViewModel SettingsViewModel => ServiceLocator.Current.GetInstance<SettingsViewModel>();

AutoFacModule.cs

Следующий модуль является всего лишь черновиком и будет работать для простого конструктора без параметров.

  public class AutofacModule : Module
  {
    protected override void Load(ContainerBuilder builder)
    {
      builder.RegisterType<DataFileReader>().As<IDataFileReader>();   
      builder.RegisterType<SettingsViewModel>().AsSelf().SingleInstance();

    }
  }

Ответы [ 3 ]

1 голос
/ 08 марта 2019

То, что вам нужно, это DataFileReader обновить свойство ProgressBarValue вашей ViewModel.Самый простой способ сделать это - добавить OnUpdate метод к DataFileReader

reader.OnUpdate(status => this.ProgressBarValue = status.PercentProgress); 

. Таким образом вы добавите новую ответственность к вашему IDataFileReader интерфейсу, который может оказаться неподходящим иперерыв Принцип единой ответственности .

В этом случае принято вводить новый компонент, который будет сосредоточен только на одном.

public interface IProgressObserver
{
    void OnUpdate(Action<Int32> updater);
    void Update(Int32 percent);
}

Ваш DataFileReader может положиться на этот компонент и при необходимости вызвать метод Update.Ваша ViewModel будет иметь зависимость IProgressObserver и IDataFileReader

Одна из возможных реализаций IProgressObserver может быть такой же простой, как

public class ProgressObserver : IProgressObserver
{
    private Action<Int32> _updater = _ => { };

    public void Update(Int32 percent)
    {
        this._updater(percent);
    }
    public void Register(Action<Int32> updater)
    {
        this._updater = updater;
    }
}
1 голос
/ 08 марта 2019

Альтернативным вариантом является внедрение делегата, который может создать IDataFileReader, а не уже созданный экземпляр. Это позволит вам передать ему объект Progress.

Autofac поддерживает фабрики делегатов . Это может привести к чему-то вроде следующего (не проверено):

public class DataFileReader : IDataFileReader
{
  public delegate DataFileReader Factory(Progress progress);

  public Shareholding(Progress progress)
  {
    Progress = progress;
  }
}

public class ViewModel
{
  private readonly DataFileReader.Factory factory;
  public ViewModel(DataFileReader.Factory dataFileReaderFactory)
  {
    factory = dataFileReaderFactory;
  }

  ...
  IDataFileReader fileImporter = factory(progress);
}
1 голос
/ 08 марта 2019

По сути, вы не можете сделать это хорошим способом :) Сначала вы должны спросить себя, почему DataFileReader заботится о прогрессе. Может быть, что-то еще должно наблюдать за прогрессом и сообщать об этом миру?

Я бы также рекомендовал избегать использования шаблона ServiceLocator. Классы должны содержать только четко определенные зависимости, введенные явно через конструктор. Свойства инъекций также следует рассматривать как анти-шаблон по моему мнению.

...