Dependency Injection – Abstract Factory Patterns in C#

Architecturecdependency-injectiondesign-patterns

Given a project architecture as follows, where each box represents an assembly (all are class libraries), and each arrow stands for a dependency:

architecture

Might be worth nothing that this project is massive (well, it will become!), the complexity incurred by such decoupling is absolutely warranted.

Business Logic Layer

The BLL library defines and organizes various sets of POCO interfaces in its Abstract namespaces, and implements various functionality logic in its Concrete namespaces; the functionality logic refers to and uses the abstract POCO interfaces.

Data Access Layer

The DAL library implements the POCO interfaces from the BLL using partial classes that "extend" Linq to SQL (dbml) classes, so if there's a Customer L2S class, it implements the BLL ICustomer interface. Sometimes the L2S class has different types, or the BLL abstraction uses enum types, but most often the partial class code looks like this:

public partial class SomeEntity : ISomeEntity { }

This assembly provides the Model, by exposing classes named "xxxxModel", which are constructor-injected with repositories regrouped into services, but there's a twist: the "xxxxxModel" classes implement an interface called IUnitOfWork which encapsulates a database transaction that must be able to operate on all repositories at its disposal… possibly with a dynamic (runtime-determined) connection string. To achieve this, I created "model factories" which create a single DataContext of the appropriate type, and inject the same instance in each repository.

Presentation Logic Layer

Some of the BLL POCO interfaces need a "ViewModel" implementation (e.g. to display as items in a list) – the PLL library defines them; however the goal of this library is more focused around, well, the actual presentation logic, although there is no reference to WPF whatsoever (other than a single reference to WindowBase but I'll get to that). So this assembly provides the ViewModel.

One thing to note is that the ViewModel here, completely controls the View – each ViewModel is injected with an implementation of IViewFactory that creates an IView implementation – technically the ViewModel is blissfully unaware of the implementations, so I'm not sure how deeply it violates MVVM (to be honest I don't really care about that point – especially after reading a blog post like this one), but the thing to point out is that it's the ViewModel that litterally creates the View and assigns the DataContext. This makes it very simple to deal with things that should be simple, such as showing and closing a window.

So all ViewModel classes inherit ViewModelBase, which is an abstract class that takes a IViewFactory in its protected constructor, effectively instantiating the View. Here's the offending code:

/// <summary>
/// An interface for a ViewModel.
/// </summary>
public interface IViewModel : INotifyPropertyChanged
{
    /// <summary>
    /// Notifies listener that the value of the specified property has changed.
    /// </summary>
    void NotifyPropertyChanged<TProperty>(Expression<Func<TProperty>> property);

    /// <summary>
    /// Notifies listener that the value of the specified property has changed.
    /// </summary>
    void NotifyPropertyChanged(string propertyName);

    /// <summary>
    /// Closes the view.
    /// </summary>
    void Close();

    /// <summary>
    /// Displays the view.
    /// </summary>
    void Show();

    /// <summary>
    /// Displays the view (modal) and returns a <see cref="DialogResult"/> value indicating how the view was closed.
    /// </summary>
    DialogResult ShowDialog();
}

So a ViewModel essentially controls a View up to the point of encapsulating it, which makes it easy to implement my own DialogResult enumeration (much closer to the way WinForms had it).

Views Assembly

Because this library references and consumes ViewModels from the PLL assembly which implement interfaces defined in the BLL assembly, an arrow is missing here – there's also a dependency upon the BLL, but it's only used indirectly. This library provides the View, by defining WPF/XAML windows and controls.

Apart from IValueConverter and other MarkupExtension implementations, there's not much C# code in this library, the hard references to ViewModel implementations are all in XAML d:DataContext {d:DesignInstance...} declarations.

So, what's wrong?

I definitely like the direction of the dependencies, including the PLL/Views one. The fact that the BLL has zero dependencies mean I can reuse that library and come up with a WebUI if I ever need one (and that WILL happen… eventually!), and the DAL/BLL decoupling means parts of the data model could be coming from Web services, some cloud, or whatever – business logic couldn't care less and that's good.

The main issue I'm having, is that I find myself writing LOTS of abstract factories, and implementing even more of them, and I'm not always reusing these abstractions (hence the smell), but it seems to me like whenever I ask myself how I can inject a "dynamic" dependency, the answer is almost automatically – "an abstract factory will do!"… which is probably right, it's just that I don't think it's right that pretty much everything is a "dynamic" dependency!

public class SomeViewFactory : IViewFactory
{
    public IView Create(IViewModel viewModel)
    {
        return new SomeWindow {DataContext = viewModel};
    }
}

public class SomeRepositoryFactory : DataRepositoryFactory<SomeEntity>
{
    public IRepository<SomeEntity> Create(DataContext context)
    {
        return new SomeRepository(context);
    }
}

I even have an abstract IFunctionalityFactory:

public interface IFunctionalityFactory
{
    IFunctionality Create();
}

public class SomeFunctionalityFactory : IFunctionalityFactory
{
    private readonly IFunctionalityAuth _auth;
    private readonly ISomeBusinessLogic _logic;

    public SomeFunctionalityFactory(IFunctionalityAuth auth, ISomeBusinessLogic logic)
    {
        _auth = auth;
        _logic = logic;
    }

    public IFunctionality Create()
    {
        var canExecute = auth.IsCurrentUserAuthorised(typeof(SomeFunctionality).FullName);
        return new SomeFunctionality(canExecute, _logic);
    }
}

Is it normal to have factories for almost everything – from repositories to services and models in the DAL, to Views and ViewModels in the PLL/View library? For now the project is rather small and I'm still the only programmer working on it; I'd like to have an architecture as SOLID and simple as possible when it comes to implementing new functionalities.

This is only my 2nd project implementing DI/IoC, needless to say I'm trying to run (and swim, and perhaps even fly) before I can walk…

Any tips or issues I'm not seeing? Am I abusing Abstract Factory? How else could I instantiate a View? How else could I have a data model that could connect to any of a given set of [almost] identical databases, at the user's discretion? I know I'm breaking MVVM, have I overlooked anything in the pattern that could simplify my existence?

Best Answer

It seems you're struggling trying to create objects that create objects... wouldn't you be better off just creating objects ?

Ninject allows you to do so in a very simple way :

// Ninject module
Bind<IRepository<SomeEntity>>().To<SomeEntityRepository>();

// injected class
public class SomeService
{
  public SomeService(IRepository<SomeEntity> repository)
  {
    // ...
  }
}

// get instance of injected class
var someService = kernel.Get<SomeService>();

I can't see the benefit of an abstract factory in addition to an IoC container when you're creating objects based on basic, compile-time-known constraints such as in your SomeViewFactory and SomeRepositoryFactory examples.

The dynamic nature of SomeFunctionalityFactory would be more debatable, but when you think of it, do you really need to instantiate an object with the built-in notion that it will never be able to be used by the current user ? Wouldn't it make more sense to have the object evaluate user authorization when the functionality is called ?