3

I'm currently using Castle Windsor v2.5.1 and running into a few issues. I have a list where users select an item of their choice and begin working on the item selected. When an item is selected I inject the built item in my editor view model and display it to the end user. I've set all of my dependencies to have a transient lifestyle, which is causing me to deal with getting singleton dependencies injected, leaving me with stale data from a previously loaded item instead of a new object.

Here is what my view model constructor looks like:

public TabViewModel(
    IRepository repository 
    IEditorViewModelFactory editorViewModelFactory)
{

Only one instance of this class is ever created within the lifetime of this application which is fine. But since users can (and do) select many different items throughout the lifetime of the application I end up using the same dependencies. Everytime a new item is selected inside the TabViewModel view I call editorViewModelFactory.Create(the id of the item selected). Since only one instance of IEditorViewModelFactory is created it makes sense that Windsor isn't injection fresh dependencies.

How do I force Windsor to inject a fresh set of dependencies whenever a new item is loaded?

Edit

The application works as follows. When the application loads it opens up it opens the view associated to the TabViewModel class and injects both of it's dependencies. Only one instance of TabViewModel is ever created. Inside this TabViewModel object I hook into the IsSelected property from TreeViewItem (all items are stored in a tree view. Once an item is selected the following event from TabViewModel is fired. I get the item that was selected and load the appropriate editor from my injected IEditorViewModelFactory.

private void OnItemSelected(object sender, PropertyChangedEventArgs e)
{
    const string isSelected = "IsSelected";
    var selectedItem = sender as ItemViewModelTiny;

    if (e.PropertyName == isSelected && selectedItem.IsSelected)
    {
        _editorViewModelFactory.Create(selectedItem.Id);
    }
}

Since only one TabViewModel is ever created then it makes sense that only one IEditorViewModelFactory is created. Thus, even though I keep calling Create() when an item is selected it's using the same dependencies created from when the first item was loaded.

My factory looks as follows:

public class EditorViewModelFactory : IEditorViewModelFactory
{
    private readonly IRepository _repository;

    public EditorViewModelFactory(IRepository repository)
    {
        _repository = repository;
    }

    public LocateEditorViewModel Create(int itemId)
    {
        var fullItem = _repository.GetFullItem(itemId);

        return new EditorViewModel(_repository, fullItem.MapTo<ItemViewModel>());
    }
}

Hope this clarifies my question.

Edit 2

Every time an item is selected I use my reviewing service to determine the users eligibility. While determining the eligibility I retrieve all current reviews for the selected item. When an item is reviewed it gets processed by my review processor with the reviews gathered from determining the users eligibility. This means that by always having the same instance of the reviewing service all previously retrieved reviews from other items are lingering in the system. I was able to fix this problem by simply clearing my list of reviews when finding the users eligibility. This works because when the editor is loaded the first thing that happens is determine if the user is eligible.

Here are both of the interfaces I refer to:

public interface IReviewingService
{
    ReviewEligibilityResult GetReviewEligibility(ItemViewModel itemViewModel);
    void Save(UserReview userReview);
}

public interface IReviewProcessor
{
    void Process(UserReview userReview, IList<ReviewDto> reviews);
}

Hope that makes sense.

gcso
  • 2,315
  • 3
  • 28
  • 50
  • You write that *all* of you dependencies are transient, yet you have to deal with singletons. It sounds to me like not all of them are transient after all. Can you elaborate? – Mark Seemann Sep 01 '11 at 12:31
  • I've elaborated more on the question. My choice of words regarding the singleton was poor. – gcso Sep 01 '11 at 12:53

1 Answers1

3

There's only one instance of EditorViewModelFactory in memory because it's configured as a Singleton. Thus, because it holds on to the IRepository instance by the _repository field, there's also only one of those instances in memory, no matter how its lifetime is configured.

However, the Create method returns a new instance of EditorViewModel every time, but the _repository instance is still the same, and is being passed into the EditorViewModel instance.

If you need a new instance of IRepository every time you create an instance of EditorViewModel you could use an Abstract Factory.

Community
  • 1
  • 1
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • I don't follow. Isn't my `IEditorViewModelFactory` an abstract factory. Looking at your example they look to do the same thing. – gcso Sep 01 '11 at 13:07
  • Yes, but if you want a new instance of `IRepository` you need a factory that produces those. – Mark Seemann Sep 01 '11 at 13:22
  • Ah, I understand what you mean now. Is it possible to have a new editor factory created every time an item is selected? I'm not a very big fan of creating a factory for each dependency that my editor takes (I had omitted 2 of the dependencies for brevity in my example). – gcso Sep 01 '11 at 14:16
  • Then you'd need a FactoryFactory, which is probably not a good idea :) When things become difficult like it seems they currently are, it's better to reflect on that feedback and see if you can make the design simpler. The first thing which comes to my mind here is the requirement each `EditorViewModel` requires a separate `IRepository`. Why is that? Usually, a Repository is a service so conceptually, you shouldn't need a new instance for every consuming instance. – Mark Seemann Sep 01 '11 at 14:29
  • Yes, I do agree that creating a `FactoryFactory` is not a good idea. Once again I provided a bad example when using `IRepository` for my factory. You are right in saying that `IRepository` doesn't need to be created every time. I actually have a `IReviewingService` that also gets injected into my editor factory. This service is responsible for determining if the current user is eligible for reviewing the current item. This service also acts as a gateway to process (`IReviewProcessor`) reviews. This is where the problem lies. Please see my second edit. – gcso Sep 01 '11 at 15:17
  • Could you possibly have a leaky abstraction at hand? Perhaps this is of any help: http://stackoverflow.com/questions/4648318/dependency-injection-new-instance-required-in-several-of-a-classes-methods/4650050#4650050 – Mark Seemann Sep 01 '11 at 15:20