Question

Background

I'm using Castle Windsor as my IOC container in a WPF application. In this application, the user can open a single project file, which is modeled using a concrete version of an IProjectModel interface. So, at any given time there is zero or one instance(s) of IProjectModel available. I'm currently defining the lifestyle of its implementor as transient, and this implementor expects in its constructor a filename as a string which is chosen by the user (from a dialog). The IProjectModel instance is resolved via a typed factory interface, e.g.:

public interface IProjectModelFactory
{
    IProjectModel Create(string fileName);
}

Question

I initially figured it was bad to treat it as a singleton since:

  1. it is transient with respect to the application lifetime;
  2. it has dependencies of its own, i.e. the filename (string) to open, that I don't think I could specify if it had singleton/scoped lifestyle;
  3. passing it around keeps open the option of having multiple projects open at once.

However, now that I'm creating factory after factory in order to pass the current IProjectModel instance around I'm somewhat regretting that decision. It'd be much easier to have the container hand my objects the current project model, rather than pass it down from way up the object chain.

How is a situation like this supposed to be handled using Castle Windsor?

It seems like the Scoped Lifestyle is built for this (the scope is the currently open project/file name), but I can't figure out how to get information about the opened file into the IScopeAccessor since I can't inject anything into that.

Was it helpful?

Solution

IProjectModel sounds like it contains data--i.e. it's not a pure service.

Consider modeling it like you would model a service that was backed by a database, but instead of connecting to a database, use some in-memory construct. It's probably as simple as a static member variable on your service implementation. Something like:

public class ProjectDataService : IProjectDataService
{
    private static IProjectModel _projectModel;

    public IProjectModel Create(string fileName)
    {
        if (_projectModel == null)
        {
            //create it
        }
        return _projectModel;
      }
 }

(Note that you you may have to do some locking of the member variable.)

Now if you need to switch to having multiple projects open at once, change your member variable to a list structure (IList, Dictionary, etc.).


Edit based on your comment.

I'm referring to once it's already been created. The big idea behind IOC seems to be "let the container handle the dependencies", and it seems Windsor could support this, I just don't see how. I'd like to specify IProjectModel in a transient object's constructor, and have the container resolve the current IProjectModel, if there is one. Your answer is a lazy singleton, which isn't what I was asking for.

What I'm saying is IProjectModel is not really a service--it's state/data. So injecting it directly doesn't make sense (at least not to me). Wrapping it in a IProjectModel data service or IProjectModel "state manager" is more in line with injecting services, which is what DI frameworks generally do.

Can you register an IProjectModel? Yes. However, container registration is generally done at application bootstrap time, not based on user input. Also, from your description, you may need to support multiple instances of IProjectModel. How would the container know which instance to give to you when you ask for it?

As a more obvious example: would you consider injecting a string or an int in your constructor?

Let the container handle the dependencies is not exactly how I would describe the "big idea" behind IOC. It's about decoupling from (or handling) service dependencies. So if you want to inject something that is stateful, I'm suggesting you wrap that state in a class that can be injected like a service.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top