1

Let's simplify my application:
I have two prism modules : shell module which is visualizing some data and a second module - WCF service, which is fetching that data (let's say that data is a name and value of some register). My plan is to set is up as shared service, and inject it as a dependency to one of my shell module classes. My problem is, I have no idea, in which class this service reference should be: in model or in viewmodel (of mainwindow for example). I could set up a model of a register and it will and be fetching its name and value by itself (using stored reference to WCF service). But I am not sure that this is a correct way to implement this. My code:

//Bootstrapper.cs  ->register WCF service in a container
RegisterTypeIfMissing(typeof(IDatabaseService ), typeof(DatabaseService), true);

This could be my model, that I am referencing in my ViewModel:

public class Register
{
    IDatabaseService service;  //reference to WCF service (which is in separate module)
    public int RegisterValue { get; set; }
    public string  RegisterName { get; set; }   
    public Register(IDatabaseService _service) //this will be resolved in a container
    {
        service = _service;      
    }
}
karollo
  • 573
  • 8
  • 22
  • This is all very subjective and probably better for the software engineering stack exchange site. However if you mean Model as in data model, no keep it away from there. Depending on your architecture and the size of your program, it probably makes sense to either inject it into your VM or if you have some sort of business layer, it maybe better suited there. however on saying all that, this is all subjective, and i have simply no idea on your requirements and existing architecture – TheGeneral Apr 20 '18 at 10:18

2 Answers2

2

You need to be careful of your definition of "model", I explain this here. Your service is part of the "model".

You are almost on the right track, but you should not inject something like a service into a data entity. If your app is smaller then feel free to use the service from your viewmodel. If your application is larger and you have a requirement for some business logic then one option is to have another class behind your viewmodel that uses the service, that class would be the business layer in a n-tier architecture.

So to illustrate that textually, you would have view->viewmodel->business class->service.

slugster
  • 49,403
  • 14
  • 95
  • 145
  • 1
    I agree. Inject IDatabaseService (which is part of your model) into your view model. – mm8 Apr 20 '18 at 11:32
  • Ok, thanks. There is only one thing left: what if multiple viewmodels need to access that data fetched by DatabaseService? – karollo Apr 20 '18 at 20:45
  • 1
    @KarolŻurowski they should all have the service injected, you can configure Prism to keep just a single instance (although I'd recommend against that for most scenarios). If the data is expensive to fetch (i.e. it is large or takes a long time) then you could consider a caching pattern - the service first goes to the cache for the data and if it is absent it then goes to the data source for it. – slugster Apr 21 '18 at 01:34
1

I've had great success with the below scenario of decoupling a simpler application, but in my opinion this would work well for your purposes.

WFCApp
-WCFApp.Models      <- Data Model
-WCFApp.DataAccess  <- Data Access Layer
-WCFApp.Service     <- Expose Service as IDatabaseService

PrismApp
-PrismApp.Models
-PrismApp.ViewModels
-PrismApp.Views
-PrismApp.DataProvider  <-This is the only thing that knows about IDatabaseService.

So, instead of injecting IDatabaseService into your ViewModel, you can now inject IDataProvider.

The problems this solves the following, which may or may not be applicable:

  1. Allows you to write unit tests your ViewModel (if you were injecting IDatabaseService, it would have to be an integration test!)
  2. Further decouples your UI application from the WCF service, which of course makes it easier for either the UI or the WCF service to change independently.
  3. This is a stretch, but a good example: Say your IDatabaseService exposes both Read() and Update() functions, but you want the UI to be Read Only. With your IDataProvider, you hide those exposed methods.

Here's an example from my app;

public class DataProvider : IDataProvider
{
    private readonly IDataService _service;

    public DataProvider(IDataService _service)
    {
        _service = service;
    }

    public List<Appointments> GetAllAppointments()
    {
        return _service.GetAllAppointments();
    }
}

public interface IDataProvider
{
    List<Appointments> GetAllAppointments();
}
Adam Vincent
  • 3,281
  • 14
  • 38