Welcome Guest, you are in: Login

dbones docs

RSS RSS

Navigation (boxes)




Search the wiki
»

Identity - how to know what to export

RSS
Modified on 2013/10/18 01:35 by Dave Categorized as Uncategorized

When working with packages and modules we most likely need a way to identify which classes should be exported.

Background

We will have seen this behaviour before in other Extensibility frameworks such as MEF:

[Export(typeof(ICalculator))]
public class MySimpleCalculator : ICalculator
{

}

MEF uses attributes (you can configure it to use another way) to identify contracts.

Another example is the Orchard Framework (which contains a module management solution)

public class MySimpleCalculator : ICalculator, IDependency
{

}

Orchard does not just use interfaces for tagging classes as exportable contracts, it also uses the interface to identify the class’s lifestyle (singleton/transient etc…)

The thing to note is both frameworks need to identify which classes are of interest to the internal container, and also how should the class be handled (for example its lifestyle)

Boxes.Integration

Boxes Integration is a unique solution, in which it allows you to choose the way you want, take for example

  • By the classes naming convention
  • By marking it with an attribute
  • By implementing an interface

The above is 3 examples, you may want to combine them together, the Boxes framework does not limit you.
What do you need to do:

  • Define the way to identify your classes
  • Create the modules which will extend boxes

Example

In this sample we want to use interfaces to identify our contracts, and we want to make it so any Package does not need to reference Boxes (unless it is extending it, of course)
To do this we will create 2 packages (both consisting of a single module)

  • Identifiers – this will contain all the interfaces used to tag our classes
  • Identifiers.Windsor – this will be a Boxes extension telling Boxes how to register the classes which implement the interfaces.

You can find the code in this sample app: https://github.com/dbones/Calculator.Boxes.Windsor

Identifiers

Code

namespace Identifiers
{
    /// <summary>
    /// an exportable service (no defined lifestyle)
    /// 
    /// Developer note, try not to create inheritance higherachy with the IDependency
    /// 
    /// Not recommended, ICustomIDependency : ITransientDependency : IDependency 
    /// Recommended, ICustomIDependency : IDependency
    /// 
    /// this will make the registration easier to handle.
    /// </summary>
    public interface IDependency { }

    public interface ISingletonDependency : IDependency { }

    public interface ITransientDependency : IDependency { }
}

manifest.xml

<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns="http://schemas.dbones.co.uk/developer/boxes/2012">
  <name>Identifiers</name>
  <version>1.0.0</version>
  <description>
    Supplies some default ways to identify exported types. 
    Interfaces and Attributes for Singleton and Transient are currently exposed
  </description>
  <exports>
    <assembly name="Identifiers" />
  </exports>
</manifest>

Identifiers.Windsor

Code

public class Extension : ISetupBoxesExtension<IDefaultContainerSetup<IWindsorContainer>>
{
    public bool CanHandle(IDefaultContainerSetup<IWindsorContainer> extension)
    {
        return true;
    }

    public void Configure(IDefaultContainerSetup<IWindsorContainer> containerSetup)
    {
        containerSetup.AddRegistration(new Register()
            .Where(x => typeof(ISingletonDependency).IsAssignableFrom(x))
            .LifeStyle(typeof(SingletonLifestyleManager))
            .AssociateWith(Contracts.SelfAndAllInterfaces));

        containerSetup.AddRegistration(new Register()
            .Where(x => typeof(ITransientDependency).IsAssignableFrom(x))
            .LifeStyle(typeof(TransientLifestyleManager))
            .AssociateWith(Contracts.SelfAndAllInterfaces));

        containerSetup.AddRegistration(new Register()
            .Where(x => x.HasAttribute<SingletonDependencyAttribute>())
            .LifeStyle(typeof(SingletonLifestyleManager))
            .AssociateWith(Contracts.SelfAndAllInterfaces));

        containerSetup.AddRegistration(new Register()
            .Where(x => x.HasAttribute<TransientDependencyAttribute>())
            .LifeStyle(typeof(TransientLifestyleManager))
            .AssociateWith(Contracts.SelfAndAllInterfaces));

        containerSetup.AddPackgeLevelFilter(new Filter(), "Identifiers");
    }
}

public class Filter : IPackageTypesFilter
{
    public IEnumerable<Type> FilterTypes(Package package)
    {
        return Enumerable.Empty<Type>();
    }
}

manifest.xml

<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns="http://schemas.dbones.co.uk/developer/boxes/2012/extension">
  <name>Identifiers.Windsor</name>
  <version>1.0.0</version>
  <description>Extends Boxes.Integration to use Identifiers</description>
  <exports></exports>
  <imports>
    <dependency name="Identifiers" />
  </imports>
  <extends>
    <assembly name="Identifiers.Windsor" />
  </extends>
</manifest>

Usage

In any module which uses this style of tagging, all you need to do is add a reference to the Identifiers package and Identifiers.dll assembly

code

namespace Calc.Commands
{
    using System.Globalization;
    using System.Text.RegularExpressions;
    using Core;
    using Identifiers; //referenced assembly

    /// <summary>
    /// inputs the current value into the formula
    /// </summary>
    public class CurrentValueCommand : ICalculatorCommand, ITransientDependency
    {
        //code
    }
}

manifest

<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns="http://schemas.dbones.co.uk/developer/boxes/2012">
  <name>Calc.Commands</name>
  <version>1.0.0</version>
  <description>
    Some commands for the Calculator
  </description>
  <exports>
    <assembly name = "Calc.Commands" />
  </exports>
  <imports>
    <dependency name = "Calc.Core" />
    <dependency name = "Identifiers" />
  </imports>
</manifest>

Note: there is no direct dependency on Boxes
dbones docs, is a sub-site of dbones.co.uk, all its content belongs to dbones.co.uk, this also includes logo's.