Search code examples
c#wpfmvvmserviceautofac

Should I pass View Model to my service, and if yes, how to do it?


I have a solution, that uses Autofac, and I moved some methods from my View Model to the service file. Right now I am facing a problem, where some of the variables in the service methods and refering to VM properties. So I figured out, that maybe I should pass the View Model to the Service.

First of all, I am not sure that I am supposed to do that, for separation of layers and testability. But I am guessing, that it should be no problem with mocking, correct me if I am wrong.

Another thing is that I am not sure yet how to pass the VM to Service. With my current solution, that you can find below, I am getting StackOverflow exception on setter of the Model prop. The thing is, that right now it is the best I have and Im out of any new ideas.

Another thing, if passing a VM to the Service layer is an antipattern, how should I refer a VM property from the Service layer? Should I create some Wrapper for this, that VM and Service will refer to it?

The code will be shown on simplified example. MainViewModel:

public class MainViewModel : ViewModelBase
  {
        private MainViewModel _vm;
        private Person _person;
        private ISomeService _someService;
        public MainViewModel(ISomeService someService)
        {
            _person = new Person();
            _someService = someService;
            Name = "Slim Shady";
            _vm = new MainViewModel(_someService);

            Execute();
        }

        public string Name
        {
            get
            {
                return _person.Name;
            }
            set
            {
                _person.Name = value;
                OnPropertyChanged();
            }
        }

        private void Execute()
        {
            string dupa = _someService.GetTheName(_vm);
            System.Windows.MessageBox.Show(dupa);
        }
    }

Model:

public class Person
    {
        public string Name { get; set; }
    }

Service:

public interface ISomeService
    {
        string GetTheName(ViewModel.MainViewModel _vm);
    }
    public class SomeService : ISomeService
    {

        public string GetTheName(MainViewModel _vm)
        {
            return _vm.Name;
        }
    }

Autofac:

public class BootStrapper
    {
        public IContainer BootStrap()
        {
            var builder = new ContainerBuilder();

            builder.RegisterType<SomeService>()
              .As<ISomeService>().SingleInstance();

            builder.RegisterType<MainWindow>().AsSelf();
            builder.RegisterType<MainViewModel>().AsSelf().SingleInstance();

            return builder.Build();
        }
    }

UPDATE Need also consider situation, where some other services will also refer to the Name property of Person.


Solution

  • FINAL SOLUTION

    in my Service layer I created:

    public interface IPersonService
        {
            string Name { get; set; }
        }
    
        public class PersonService : IPersonService
        {
            Person _personModel = new Person();
            public string Name
            {
                get
                {
                    return _personModel.Name;
                }
                set
                {
                    _personModel.Name = value;
                }
            }
        }
    

    and modified:

    public interface ISomeService
        {
            string GetTheName(IPersonService personService);
        }
        public class SomeService : ISomeService
        {
    
            public string GetTheName(IPersonService personService)
            {
                return personService.Name;
            }
        }
    

    So now I inject to my VM both services, and when retrieving name from SomeService I am passing injected PersonServie:

    public class MainViewModel : ViewModelBase
        {
            private IPersonService _personService;
            private ISomeService _someService;
            public MainViewModel(ISomeService someService, IPersonService personService)
            {
                _personService = personService;
                _someService = someService;
                Name = "Slim Shady";
    
                Execute();
            }
    
            public string Name
            {
                get
                {
                    return _personService.Name;
                }
                set
                {
                    _personService.Name = value;
                    OnPropertyChanged();
                }
            }
    
            private void Execute()
            {
                string dupa = _someService.GetTheName(_personService);
                System.Windows.MessageBox.Show(dupa);
                System.Windows.MessageBox.Show(Name);
            }
        }