Showing posts with label MEF. Show all posts
Showing posts with label MEF. Show all posts

Tuesday, October 28, 2014

Onion application architecture and web deploy packaging

A principle of Onion architecture is the inner layers cannot have dependencies on outer layers (i.e. dependencies are inward only). This implies that dependency inversion is key to ensure this principle is not broken.

This does not play nicely with Web Deploy and packaging out of the box. The dependency inward only principle results in outer layer libraries referencing the inner layer libraries. This means when you build the inner layer libraries, the outer layer libraries won't be built (because there is no reference to them). An option to get around this issue is to perform a post build action for the outer libraries to copy the dll to a location that the inner library can resolve an instance of the concrete dependency at runtime (e.g. using MEF). If you use Web Deploy you will need another solution...

Long story short, Web Deploy won't include extra files without some customization. By extra files I mean files that the project / library is not aware of (or in other words is not referencing) - which ties in with the above problem where inner projects don't reference outer projects - when when publishing a web project, extra files / outer layer projects will not be included in the publishing process. 

You can instruct MSBuild / Web Deploy to include extra files by adding the following to your web project file:

  <PropertyGroup>

    <CopyAllFilesToSingleFolderForMsdeployDependsOn>

      ExternalDependencies;

      $(CopyAllFilesToSingleFolderForMsdeployDependsOn);

    </CopyAllFilesToSingleFolderForMsdeployDependsOn>

  </PropertyGroup>

And,

  <Target Name="ExternalDependencies">

    <ItemGroup>

      <_CustomFiles Include="..\ExternalDependencies\*" />

      <FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">

        <DestinationRelativePath>bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>

      </FilesForPackagingFromProject>

    </ItemGroup>

  </Target>

This blog post has a great summary on these statements. However I'll summarize the highlighted parts above:

  • CopyAllFilesToSingleFolderForMsdeployDependsOn: Pretty descriptive, and will add the ExternalDependencies target to the packaging process.
  • ExternalDependencies: Custom target added will will define where the additional file (external dependencies) are located.
  • ..\ExternalDependencies\*: Actual location of the additional files to be included in the packaging process, i.e. the outer layer libraries. So typically I would have my external / out layer libraries have their build output copied to this location (e.g. post build action). And then when a publish is kicked off, these libraries would be picked up, and copied to the bin folder (bin\%(RecursiveDir)%(Filename)%(Extension), the last highlight part) of the web app. 

Monday, July 14, 2014

Onion architecture and MEF

Correctly applying Onion architecture results in stable application concerns being protected from volatile application concerns.

Volatile concerns / responsibilities are coupled with specific frameworks, platforms or tools. For example, persistence is volatile because over time the platform used may change (e.g. Oracle to SQL Server). Another example is UI.

Stable concerns / responsibilities of an application remain the same over time, regardless of the latest technology trends. In other words, business / application functionality is not driven by how a particular platform or framework is used, the requirements for what business functions the application should implement don't change (i.e. stable). In Onion architecture, this would be defined as the Application Core. This is very similar to a fundamental goal of SOA - protecting client applications from volatile provider applications by using stable abstract business services. 

A principle of Onion architecture is the inner layers cannot have dependencies on outer layers (i.e. dependencies are inward only). As you move further into the center, the concerns become more stable - where the domain is the center and most stable part of the application. This implies that dependency inversion is key to ensure this principle is not broken.

MEF can resolve these dependencies (e.g. act as an IOC container) dynamically. In other words, MEF can discover concrete dependencies at runtime. This has the huge advantage of allowing the Application Core (stable concerns) not needing explicit registration of available components. The Application Core can be completely clean of any knowledge of components that implement volatile responsibilities. This results in the volatile responsibilities being pluggable. The below diagram illustrates this concept, where the library responsible for implementing the volatile responsibility (in this example it is persistence) references the Application Core library. It is referencing the Application Core library because it needs to be able to implement IOrderRepository.

Application Core has an abstract dependency on an order repository - IOrderRepository - and needs somehow to resolve a concrete implementation of this interface (i.e. resolve the concrete implementation defined in the SqlPersistence library). With the appropriate usage of MEF (Export, Import attributes etc), this can easily be achieved. It's important to point out again, that nothing is referencing the volatile library. You could easily swap in another library which is implementing IOrderRepository, and the Application Core would require no changes - i.e. pluggable. 

Tuesday, November 19, 2013

MEF and deciding which export instance to use

Having used MEF in the past, I was really keen to use more extensively in a up coming project, which will involve extending 'core' functionality with customer extensions (i.e. overriding) . I'm enjoying the simplicity of MEF in regards to resolving dependencies, and the lack of configuration required / setup code when comparing with IOC containers. With the amount of customers extensions that will be implemented eventually, the amount of configuration required to wire these up won't scale (like it didn't for the previous version of the product where Unity was used).

So essentially, if I drop an assembly into the bin folder with customer extensions on base functionality, then the derived Exports would be used over the 'base' Exports. If the customer extension is not present, (i.e. just the base Export is), then just use this one.

In code this would look like:

public class CoreApplicationQueryService : IApplicationQueryService

public class CustomerApplicationQueryService : CoreApplicationQueryService

If CustomerApplicationQueryService is present, use that, if not, default to CoreApplicationQueryService.

[Import] won't suffice because there will be multiple Exports that match if the Customer version is present, therefore an exception will be thrown. Therefore [ImportMany] will have to be used. But, once the multiple Exports have been picked up, I need a way of deciding which instance to use. That is where [ExportMetadata] comes in.

I've used [ExportMetadata] to indicate is the Export is defined as an (Customer) extension of not:

[ExportMetadata("Extension", false)]
public class CoreApplicationQueryService : IApplicationQueryService

[ExportMetadata("Extension", true)]
public class CustomerApplicationQueryService : CoreApplicationQueryService

... where true ("Extension", true) indicates that this instance is a extension instance.

There is a little bit of magic where you then need to create an interface to match the parameters in the ExportMetadata attribute - e.g:

public interface IExportMetaData
{
bool Extension { get; }
}

The next step is to import the parts, e.g. set this property. IExportMetaData is part of the property definition as part of the Lazy type:

[ImportMany(typeof(IApplicationQueryService))]
public IEnumerable<Lazy<IApplicationQueryService, IExportMetaData>> ApplicationQueryServices { get; set; }

Next compose the parts, and then cycle through the instances resolved to find the extended instance (if there). An example is below:

var directoryCatalog = new DirectoryCatalog("bin");
var compositionContainer = new CompositionContainer(directoryCatalog);
compositionContainer.ComposeParts(this);
foreach (var item in ApplicationQueryServices)
{
   if(item.Metadata.Extension)
{
var message = item.Value.GenerateMessage();
}
}

Wednesday, April 10, 2013

MEF 101

A new project that I've been working on involved separating customer extensions into their own assemblies. More specifically, a WCF service has a dependency on types within an assembly, however these types may be extended in a customer specific library/assembly depending on the customer we are building the solution for.

WCF Service --> Library with Interface / Base classes etc <-- Client extensions library implementing interfaces, and extending base classes

However I didn't want the WCF service to have a reference to all of the client extension assemblies and use Unity for example to resolve the concrete dependency at runtime through config - this will grow over time so won't scale, and is clumsy. Its worth pointing out that Unity won't load the assembly into the AppDomain by it's self - so another mechanism is needed (eg. project reference)
Never used MEF before, but it's perfect for this scenario - dynamic application composition.
Continuing with the WCF service example, I create a property which is the dependency I want to 'import' - below example is a logger dependency, where the ILogger interface is defined in the base library (i.e. what the WCF service is referencing), I have also decorated the property with the MEF Import attribute:

[Import(typeof(ILogger))]
public ILogger Logger { get; set; }

A customer wants to log in a particular way, so we'll create a specific implementation by implementing the ILogger interface in a customer specific assembly. This class has been decorated with the MEF Export attribute - which indicates it available as a composable part:

Export(typeof(ILogger))]
public class FlatFileLogger : ILogger

The next step is to build up the type with the dependencies / needs to composed using parts (i.e. needs to 'import' an implementation of ILogger). To do this you need to use the CompositionContainer, AggregateCatalog and the ComposablePartCatalog types. In my example, I just wanted to drop an assembly in a specified folder, and MEF would pick it when attempting to compose, so the DirectoryCatalog is the catalog type (there are others) that will allow me to do this.

new DirectoryCatalog("bin")

In the above snippet, I've created a Directory Catalog where MEF will evaluate all the assemblies in the bin folder - relative to the root folder of the AppDomain. Next I need to add this catalog instance to the AggregateCatalog, and then add the AggregateCatalog to the CompositionContainer.

var aggregationCatalog = new AggregateCatalog();
var compositionContainer = new CompositionContainer(aggregationCatalog);

So, assuming I've copied the customer extension assembly into the bin folder (i.e. the FlatFileLogger), I can then compose the parts for my instance the needs to be built up - so in the below example, instance that is passed into ComposeParts, is an instance of my type that needs to be composed with a ILogger (decorated with the Import attribute). Using the configured catalogs, MEF will then try and compose the instance. So since in this example a DirectoryCatalog is used (for the bin folder) - MEF will evaluate all the assemblies in that folder to determine if there are any types that are defined as being a composable part (i.e. decorated with Export). If so, MEF will instantiate the part - e.g. the Logger property will be instantiated as a FlatFileLogger.

compositionContainer.ComposeParts(instance);