When to use ‘Lazy’ programming with circular dependencies in MEF

Background

I have been programming with .NET for some time, but I am relatively new to the practice of dependency injection (often abbreviated as DI). The idea is simple enough: some choices are made at run-time rather than compile time. The Microsoft community has developed a .NET extension for DI called Managed Extensibility Framework (MEF). MEF has some really neat features. For one, I have noticed that it makes mocking for unit tests a breeze (this could be an entirely different topic). It also allows you to design your application in such a way that extensions (new screens, new logic, etc.) can be dropped next to the application without changing the code and, therefore, allowing for application additions without redeploying.

Design

The design of my application isn’t too complex yet. I’ve got a project called Infrastructure that has some common interfaces, classes (models), and services defined. The idea is that all of the modules in the application could reference this Infrastructure project to import / export concrete definitions where necessary.

Here is an example… I have another project in my solution called Navigation (I wanted to wrap the navigation functionality provided by Prism – another entirely different topic) that has a service, view model, and view defined. The view is bound to the view model, and serves up a breadcrumb navigation element. The view model exposes a command for popping back to a previous breadcrumb. To do this, the view model grabs the instance of the BreadcrumbService and asks it to PopTo a specific BreadcrumbItem. Here is a snippet of the constructor for the BreadcrumbViewModel, which sets the command PopTo to a delegate which can be bound to on the view:

Notice the first line (highlighted). The ImportingConstructor tag tells MEF which constructor to call when something asks for a BreadcrumbViewModel. In this case, the BreadcrumbView starts things off: I put the view on a region in the application, the view asks for the view model, then the view model asks for the service. Easy… MEF takes care of DI behind the scenes and we don’t have to worry about instantiating any objects.

Problem: Circular Dependencies

I have a behavior in my application that automatically (read, automagically) adds views to a region on the application shell if they are explicitly declared to belong to that region. For example, I have a region defined for breadcrumb, main, and side. As I define and export (with MEF) my views I can use the custom behavior to add a view to a region if it explicitly declares that it would like to do so:

Now our custom behavior will attempt to automatically add the BreadcrumbView to the TopNavigationRegion.

My custom behavior doesn’t know anything about the breadcrumb. When the breadcrumb is created, it wants to have some top level element. So I add (in the constructor of the BreadcrumbService) a breadcrumb item for the view that occupies my main region. Keep in mind that my custom behavior has already added the main view to the main region because I explicitly defined it that way. F5 and BOOM!

GetExportedValue cannot be called before prerequisite import ‘MySolution.Modules.Navigation.Services.BreadcrumbService..ctor (Parameter=”breadcrumb”, ContractName=”MySolution.Infrastructure.Interfaces.IBreadcrumb”)’ has been set.

Exceptions are fun… After a little bit of digging, I found that this was due to a circular dependency. The way I designed my dependencies with MEF was as follows:

  1. My custom behavior adds the main view to the main region.
  2. My main view asks for a view model.
  3. The view model asks for a BreadcrumbService (so that it can easily bind navigation commands).
  4. When the BreadcrumbService is constructed, if it has no breadcrumbs (true) it tries to add one for the main view.
So in step 4, MEF works with Prism to import the exported main view and add it to our main region. The problem is that MEF hasn’t yet finished constructing (and therefore, exporting) that view from step 1 due to the circular dependency.

One (acceptable) Solution: Be Lazy

After some quick Googling for the above exception I found a quick workaround. In my ImportingConstructor for my MainViewModel, I could declare the BreadcrumbService to be Lazy. The basic idea of Lazy is that the requested object will not be initialized until it is needed (more information here). The BreadcrumbService is not actually being used in the constructor of my MainViewModel, instead I am just creating a command for the view to bind to so that certain buttons can navigate to a different portion of the application. So instead of asking MEF to initialize the BreadcrumbService in the constructor of my MainViewModel, .NET will tell MEF to wait until someone presses that button to then initialize the BreadcrumbService (if it hasn’t already been initialized):

Now it works! But is there a price for this ‘lazy’ initialization?

Another Solution: Improve the Design?

After another few hours of coding, I went back to the Lazy solution and didn’t like what I had done. There was a code-smell somewhere and it stunk. Why did I even have this circular dependency? Was it due to bad design? Initially, I thought so…

The custom behavior that I defined very early on sort of threw things off. If I took it out of the picture (or better yet, integrated its concepts into the breadcrumb) then there would be no problem, right? The application would start by adding the BreadcrumbView and MEF would get all the way to adding the MainView (because the breadcrumb wants at least one element – the main view). But since the MainView needed the view model, which needed a BreadcrumbService, I ran into the same problem.

Turns out that Lazy was necessary in this instance. After some refactoring I ended up all the way back where I started. I’m sure that all the developers out there know how that feels…

I was told by many professors in school that the best programmers are the lazy ones… Ha! I learned that Lazy isn’t all bad, and that maybe it is needed sometimes. I’m sure that the design could be changed so that there is no longer a circular dependency, but I haven’t spent too much time thinking about it yet.

As always, thanks for the read! Any thoughts about how the design could be improved?

Posted in Professional Tagged with: , , , , ,
2 comments on “When to use ‘Lazy’ programming with circular dependencies in MEF
  1. Justin says:

    Thanks a ton for this. This was the most helpful solution I was able to find regarding my issue! Props

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Subscribe to my Insights via Email

Join 61 other subscribers

%d bloggers like this: