Nested Containers - isolation and performance

Sep 10, 2009 at 12:01 AM

I have a nested container I would like to use on service calls. In order to scope the parts to this context, I'm trying to work out a nested container. I just barely have my head around it, but like some other things in MEF,  it may be partially because the compelxity is in the simplicity.

I have an assembly with shared services and non-shared DTOs. I also have a separate assembly that has the persistence service (shared) and later validation and authorization services (both shared). This design is for deployment/customization reasons.

So persistence, validation and authorization are loaded into the parent container. Got that. So, I planned to put the DTO/service assembly in the nested container.

I have several hundred entities potentially in each of these assemblies.

Question 1: If my nested container uses a shared service in the parent container, will it stay loaded when the nested container is disposed. Who owns its lifetime

Question 2: When I load the child container, it must evaluate the assembly which contains several hundred items. What are the performance implicaitions. I know it just hits the manifest, but it seems an enormous task for every service call

Question 3: If I repeatedly request the service/DTO assembly in various child containers via the assembly/code base name, will MEF sort out that it can only be loaded once?

Question 4: If I take a different approach and load the service/DTO assembly into the parent catalog, and use a filtered catalog, does this save a meaningful amount of load time?

Question 5: If the service/DTO resides in the parent container from a load perspective, but is accessible only through the child container because I set the filter that way, will the shared instances stay loaded or unload when the nested container closes?

Unlike the ecosystem style apps like Visual Studio, I have a business app with hundreds of entities and only a handful active at any time. I am concerned about the shared instances remaining loaded and more concerned about a performance hit if I need to build the catalog for every service call.

It would be really great to have a bit of a walk-through on the implications of nested containers in web/wcf scenarios.

Thanks!
Kathleen

Sep 10, 2009 at 12:12 AM

Hi Kathleen,

1) Yes, it will stay loaded. The parent container owns it.

2) Avoid re-scanning the assemblies for every child container, this will be a significant perf hit.

3) No, MEF will re-load.

4) Yes, this will save scanning time.

5) It sounds like the instances in this scenario will be shared only within the child container, and thus be disposed along with it. Shared means 'shared in the container that accesses the catalog.'

An alternative you might look at (rather than filtered catalogs) is to load separate catalogs for different assemblies/logical groups of components, and keep these handy somewhere.

You can then assemble them into desirable configurations for new containers using AggregateCatalog. Catalogs and the part definitions therein are stateless and thread-safe, so this works well.

Key thing to remember is that the container responsible for instantiating a part will retain ownership of the instance, and if the instance is shared, will share that component only within the context of its creating container and children.

HTH

Nick

Sep 10, 2009 at 12:25 AM

Eleven minutes! Nick, what took you so long to answer  ;-)

3) So, I need to keep track of whether I loaded the assembly before? This pretty much rules out using an Assembly catalog in a nested container doesn't it?

So I need to keep straight that the catalog owns the definition, which does have a minor cost to create, and the container owns the instance (shared or non-shared). Shared is always/only within the ownership/container scope. Lifetime of the instance as well.

Catalogs take the load hit, containers manage lifetime/scope. I wonder if that fits on a bumper sticker?

Question 6: Does building a container from several (say 5) existing pre-loaded catalog take approximately as long as building a container with a single existing catalog and a parent container which contains a the other 4 catalogs?

Thank you for the insight. I really appreciate your quick response.
Kathleen

 

Sep 10, 2009 at 7:38 PM

You're welcome!

3) Perhaps this points to filtered catalogs then? I'm having a bit of trouble understanding your scenario - are the assemblies for child containers found dynamically?

6) Yes, I think these two are equivalent. Once a catalog has been created, constructing a container on top of it is a constant-time operation.

Cheers

Nick

Sep 10, 2009 at 9:26 PM

The assemblies for the child containers are found dynamically.

So, let's make it simple, say a menu option which brings in new functionality. When a particuarly button is pressed, the the system looks for a directory with a specified name and loads it into a child container. The application happily works. When this functionality is complete, the child container closes. MEF is done with these parts.

But, the AppDomain isn't.

So, when the user pushes the button again, the same thing can't happen. The assembly is loaded and you get a load error if you load it again.

Am I right so far?

I've finessed this because I also want to gain the perf of not re-evaluating the assembly for MEF. Thus, I have a catalog dictionary based on the directory requested. If the directory is in the dictionary, I use the previous directory catalog. If the directory is not in the dictionary, I load it.

My previous comment was screwed up. I was seeing that you need to control the loading of the assemblies to keep the loader happy. I've worked out a way to do that that seems to be working for me.

Thank you very much for your time.

Kathleen

Sep 11, 2009 at 10:42 AM

"...
How can I create an object tree per view instance where I have globally scoped, application wide instances and locally scoped instances? Should every dependency be imported or can we use a ServiceLocator for high level dependencies? What is the best approach to hide the CompositeContainer calls?
..."

I think I have raised the same problem here http://mef.codeplex.com/Thread/View.aspx?ThreadId=67572 and it's still not clear to me. It's very simple to understand when you have a couple of parts, but the fun starts when you have lots of parts, lazy loaded DLL's, global instances and scoped instances. Using the PartCreator isn't a nice workaround, since you have to change your code: use the part creator value instead of the part being the value.

The scenario we're describing is like this:

- you have some registry, some mapping between a menu ID/screen name and the concrete class (part)

- a screen can have multiple instances (two versions of the same screen can be opened at the same time)

- it's very different from a screen like Outlook, which has fixed parts (email, tasks, calendar). In data driven applications you have hundreds of screens and you (down)load the context when the user chooses the screen name. There is some sort of menu visualization.

- a screen will have an object tree, some parts are shared within the screen, some are application wide parts

How do you manage such a composition? It's a pitty you can't attach code here, else I would have been interested in Kathleen's example.