Friday, January 27, 2012

Using IoC for Extensibility

MEF is probably a better choice if you know up front there is a good likelihood of consumers wanting to extend your application by injecting their own types.  However, I think there are a few exceptions to this rule.

Firstly, most modern software applications make extensive use of IoC to loosely couple dependencies and allow easy unit testing.  Also, sometimes you don't think it is likely someone will want to swap out a class, but don't want to rule it out either.  Building in MEF support for unlikely cases is a waste of time in my opinion, especially if there are ways to override behaviour using the IoC mechanisms you're already using. In these cases I prefer to allow consumers to override the IoC registered types.

I did a post some time ago on how to prevent IoC configuration chaos (refering to the explosion in size of your app.config if you put all registrations in it). This post discusses using code registrations and a mechanism to automatically run the registration code for each assembly on start-up.

This idea can be extended to allow custom extensions to be added.

By default Unity doesn't allow types to be registered that are not referenced by the application (I think Structure Map doesn't allow this either).

Scenario 1)
A consumer of an application that is already fully completed wants to change some behaviour in that application, and they do not have the source code, just the binaries. The application uses the IoC pattern referenced by the blog post above.
The consumer can create a new application project that references everything the original application and basically wraps around it. The new application includes any new  references required to new assemblies containing classes you want to use in IoC registration.  On start-up the new application simply delegates into the original. Now you can customise the IoC mappings in the App.Config of the new application. This works great for windows services, web services, console applications, and some UI applications. This is the preferable scenario.

Scenario 2)
Another option is to customise the IoC pattern described in the blog post mentioned above. When the initialisation process is looking referenced assemblies in the AppDomain, you can add some IO code to scan for assemblies in a folder.  These new assemblies can be loaded with reflection and added into the AppDomain. Once this initialisation process is complete the App.Config can be applied. This is less desirable because the author of the original application has little control over how customisation are used by the original system. Potentially a security risk.
You could modify the reflection assembly loading mechanism to only allow assemblies with a certain signing key for example to mitigate this security concern.

No comments:

Post a Comment