1

It is possible to inject interface via constructor:

   private readonly IDataService _dataService;

    public MainViewModel(IDataService dataService)
    {
        _dataService = dataService;
    }

Above injection is proper if service is created in IoC container and never changes.

Another way is to inject via property (property injection)

   public IDialogService DialogService
    {
        get
        {
            return SimpleIoc.Default.GetInstance<IDialogService>();
        }    
    }

Such solution is useful if the instance of IDialogService may changed during application lifetime.

Then I could change some data:

  DialogService.SomeData = UpdatedData

The first way injection is done is easy to test.

I can mock Interface and inject via constructor.

I would like to know what is good practise to ensure above second way is testable.

I would like to ensure that all depended ViewModels using same IDialogService (being changed here in MainViewModel) has up to date same instance.

komizo
  • 1,052
  • 14
  • 21

1 Answers1

1

your example doesn't show property injection. your example shows the container being used outside of the Composition Root which is a bad idea. Generally you should construct your object graph in a single place, the afore mentioned Composition Root, and should not allow your container to be used outside of this location.

You should prefer constructor injection over property injection, and see this excellent answer

Property injection is using the container to SET the property value (in the composition root) NOT to get the value from the container every time the property is called.

If you simply set the initial value of the property from a variable passed in to the constructor (which can be done by the preferred method of constructor injection) then allow anything to set it via the property as normal, then its easy to test (just set it then call it again and check you get back the instance you set) and doesn't rely on the container outside of the composition root.

Edit what I would do, based on your response:

public IDialogService DialogService
{
    get
    {
        return dialogServiceProvider.ProvideService();
    }    
   set
    {
        dialogServiceProvider.SetNewService(value);
    }
}

public class DialogServiceProvider()
{
     public DialogServiceProvider(IDialogService service)
     {
          //save the dialog service
     }

     public ProvideService(){ //return it }

     public SetNewService(IDialogService newService){//overwrite existing reference}
}

now as long as the same instance of the DialogServiceProvider is injected into each view model, and changes to the IDialogService that any of them make will be seen by the others when they next call ProvideService

Community
  • 1
  • 1
Sam Holder
  • 32,535
  • 13
  • 101
  • 181
  • good explanation, thanks, but what if injected service is being changed (e.g. reinitialized in one place), how to ensure it is up do date in all clients' items that need to have up to date changed injected servcie? Now I have explanation why it is wrong. But main question is how to ensure reference be updated? Should I use e.g. Messsenger mechanism and reinitialize such services and it's dependent component in Composition Root every time it's needed? – komizo Nov 19 '14 at 15:08
  • Can't you just add a setter to the property? then use that to set the new service and as long as no clients cache the service and always ask for it by the property when they need to use it, then they will always get the up to date new version – Sam Holder Nov 19 '14 at 15:08
  • I could do that but it would violate what is recommended by Composition root: private IDialogService _dialogService; public IDialogService DialogService { get { return _dialogService; } set { _dialogService = value; SimpleIoc.Default.Unregister(); SimpleIoc.Default.Register(() => _dialogService); } } – komizo Nov 19 '14 at 15:56
  • I'm not seeing how it violates anything. The composition root is where you construct your object graph. If you then change elements of that object graph whilst you application is running you don't need to involve the container. How are you creating the new instance to set in the property? Presumably you have some factory, and are not calling the container to create the new instance? – Sam Holder Nov 19 '14 at 16:18
  • it violates because as you have written: "your example shows the container being used outside of the Composition Root which is a bad idea". New Instance is being created in locator and injected via constructor. Then during lifetime there is a logic (a command) which set this property again therefore I have to do sth to ensure all dependend view models using that service have up to date version. – komizo Nov 19 '14 at 17:16
  • Ah I think I see the confusion, your property `DialogService` is on each view model, right? I'll update the answer with what I would do – Sam Holder Nov 19 '14 at 17:28