Where to keep dictionaries in app using Dependency Injection

881 views Asked by At

I have a legacy code, and I have a problem with reconstructor it.

At start of my application I load from WCF to property on App (this is SL application) list of users.

Then every control (for sending emails, view calendar and assigning tasks) use this property as

(App.Current as App).Users

Now, I'm trying to create Unit Test for one of controls that use this lists, and I'm stuck.

Should I make a Constructor Injection(I'm using Unity) with App as parameter? Or maybe introduce some class to hold this list?

4

There are 4 answers

2
Jimmy On BEST ANSWER

Updated with OP's implementation as the pseudocode was incomplete.

I propose create an interface for all your application services

Inject IApplicationService to your modules.

You can use this interface for all the services the application provides(probably you will need more). Mock the interface for the unit tests

OP's implemantation

 public interface IApplicationService
    {
        List<User> Users{get;set;}
    }

    public class ApplicationService : IApplicationService
    {
        public List<User> Users
        {
            get { return (App.Current as App).Users; }
            set { (App.Current as App).Users = value; }
        }
    }

    public partial class MainWindow : UserControl
    {
        readonly IApplicationService _applicationService
        public MainWindow(IApplicationService applicationService)
        {
            _applicationService=applicationService;
        }
    }
0
Wouter de Kort On

I would create a wrapper class that will expose the list of users. In production code this class will just be a wrapper around your App.Current property and it can be injected in the constructor trough Unity.

In your Unit Tests you can easily mock the App parameter and pass it when constructing a new SUT.

Something like:

public interface IUserList
{
   List<User> Users { get; }
}

public class SUT
{
   private IUserList UserList { get; set; }

   public SUT(IUserList userList)
   {
     this.UserList = userList;
   }
}

public class AppUserList : IUserList
{
   public List<User> Users
   {
      get
      {
         return ((App)App.Current).Users;
      }
   }
}
0
Sebastian Weber On

For Silverlight there is an extension model called Application Extension Services.

For infrastructure purposes that might be a better alternative than adding properties to your app class and casting App.Currentback and forth.

Downside of that model is the creation of a singleton you would have to initialize for your unit tests. It would also hide the dependency on Users in your consuming classes.

Your users seem to be just data. Making that data an ambient context which can be accessed and edited everywhere in your application will bite you. You don't know who does what with that data and when he does it. This is like a session state.

So making the dependency on your data explicit would be a first step to be able to track abuse of that data.

If it makes sense to you to create a "data holder object" that has a property for Users or directly inject that data into your consumers is up to you. If there is more data than just Usersit is tempting to put all of them into the same central data store object, even if your specific consumers don't need them.

0
one.beat.consumer On

Jimmy's answer is great, but can be provide quite a bit, and some errors fixed. Differences are explained at the bottom below the code/instructions:


Create a public interface: IUserService

public interface IUserService
{       
    // Implemented functionality as methods where possible for better
    // extendability (like IoC)
    IEnumerable<User> Users();

    // Add any other user service stuff as you see fit.
    void AddUser(User user);
}

Write a UserService that implements IUserService

public class UserService : IUserService
{
    // If you need DI for this service, follow the same pattern of using 
    // fields and controller injection. I left examples in comment below.

    // private readonly IRepository _repository;

    // Constructor is unnecessary if you do not need DI example.
    public UserService(/* IRepository repository */) 
    {
        // _repository = repository;
    }

    // Methods
    public IEnumerable<User> Users()
    {
        return ((App)App.Current).Users;
    }
    public void AddUser(User user)
    {
        ((App)App.Current).Users.Add(user);
    }

}

Inject IUserService into classes via their Constructor

In this case your MainWindow as an example:

public partial class MainWindow : UserControl
{
    private readonly IUserService _userService;

    public MainWindow(IUserService userService)
    {
        _userService = userService;
    }

    // Example method consuming the service
    public IEnumerable<User> GetUsers()
    {
        return _userService.Users();
    }
}

Differences:

  1. Separate your User Services from a central Application Service

    Better modularity. In addition I use an IApplicationService for more central/global data like Api Keys, Timeouts, cleanup, DB prepping, etc.

  2. Return IEnumerable<T> instead of List<T>

    This is just a golden rule of thumb for keeping things dry and not imposing hard instantiations on your consuming classes. Refactoring is easier/safer, and your code more extensible.

  3. Use methods instead of properties

    This is preference, but I think it smart in a service layer to use methods where possible so that you can introduce filters and overloads or continue to use dependency injection - for example, you could add GetUsers(string lastName), GetUsers(string lastName, string firstName) and maintain a clean interface for your consuming classes.

  4. Cast App.Current without the as keyword

    This is a good practice because using the as keyword means when the cast fails it will return null, rather than throw an exception. I prefer the exception because 99% of the time, if your cast fails, your next operations will too. :)

Enjoy!