# CodeConfigApplicationContext Reference

The `CodeConfigApplicationContext` is an implementation of `IApplicationContext` designed to gather its configuration from code-based sources as opposed to XML-based sources as is the common case with most other `IApplicationContext` implementations provided by Spring.NET.

This chapter introduces the CodeConfigApplicationContext and how you can use .NET code to configure the Spring.NET container instead of XML files. For a general overview on the design of the Spring.NET container please see container overview. The distribution includes three sample applications, two console applications (the familiar MovieFinder and a prime number generator) and a ASP.NET MVC web application. Refer to the examples section for more information.

The code-based configuration support requires .NET 2.0 or higher and solutions that depend upon CodeConfig must be compiled with Visual Studio 2008 or later.

## Concepts

Internally, Spring.NET has a metadata model around the classes it is responsible for managing, the main abstraction in this metadata model is the interface IObjectDefinition. The IObjectDefinition serves as the 'recipie' that Spring.NET uses to perform dependency injection. In the case of XML-based configuration sources, XmlApplicationContext parses XML files to populate the metadata model. In the case of CodeConfig, the `CodeConfigApplicationContext` scans one or more assemblies containing one or more types attributed with the `[Configuration]` attribute, parses them to construct appropriate `ObjectDefinition` instances, and registers those Object Definitions with the `IApplicationContext` for use. You can also mix-and-match configuration sources, with some object definitions originating in XML and others in code.

### Using the CodeConfigApplicationContext

The `CodeConfigApplicationContext` usage pattern consists of the following high-level steps:

1. Instantiate an instance of the `CodeConfigApplicationContext`

2. [optional] Provide one ore more filtering constraints to control the Assemblies and/or Types to participate in the scanning

3. Perform the actual scanning

4. Initialize (refresh) the `CodeConfigApplicationContext` which creates the object definition and eagerly instantiates singleton objects.

### Mixing and matching configuration metadata formats

You can also use a combination of XML and Code base configuration metadata to configure the Spring.NET container. If you are an existing user of Spring.NET, incrementally adopting the code base configuration model will be a common use-case. In this scenario you should use the component-scan XML namespace to reference configuration metadata. Using the component-scan namespace requires you to register a custom namespace parser in App.config. Below is an example showing the use of the code config namespace

    <objects xmlns="http://www.springframework.net"
             xmlns:context="http://www.springframework.net/context">

      <context:component-scan base-assemblies=""/>

      <!-- <object/> definitions here -->

    </objects>

The base-assemblies attribute allows you to express limitations of Assemblies to scan via a comma seperated list of assembly names. The filter is a StartsWith filter

You will also need to configure the context namespace parser in the main .NET application configuraiton file as shown below

    <configuration>

      <configSections>
        <sectionGroup name="spring">
          <!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity -->
          <section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
         </sectionGroup>
      </configSections>

      <spring>
        <parsers>
          <parser type="Spring.Context.Config.ContextNamespaceParser, Spring.Core.Configuration" />
        </parsers>
      </spring>

    </configuration>

You can also start from a CodeConfig class and import XML based object defintions. The example below shows loading of an embedded XML resource file using the `[ImportResource]` attribute.

    [Configuration]
    [ImportResource("assembly://MyApp/MyApp.MyNamespace.MyConfig/ObjectDefinitions.xml"))]
    public class DataModuleConfigurationClass
    {
        [ObjectDef]
        public virtual SomeType SomeType()
        {
            return new SomeType();
        }
    }

## Scanning Basics

The behavior of the `CodeConfigApplicationContext` scanning operation can be controlled by the following constraints:

- Assembly Inclusion Constraint

  Only assemblies matching this contraint will be scanned; defaults to 'all assemblies'.

- Type Inclusion Contraint

  Only types matching this contraint in assemblies matching the Assembly Inclusion Constraint will be scanned; defaults to 'all types'.

### Scaning all assemblies

The simplest way to get started using code-based configuration is to instruct the context to scan all assemblies, as shown below

    var ctx = new CodeConfigApplicationContext();
    ctx.ScanAllAssemblies();
    ctx.Refresh();

Despite the name of the method 'ScanAllAssemblies', not all assemblies need to be scanned for [Configuraiton] attributes. There is an implicit filter that exclude the .NET BCL libraries as well as the Spring.NET assemblies since these will never contain any [Configuration] attributed classes. The name 'ScanAllAssemblies' should be interpreted as scanning all of the other assemblies you reference in your application.

### Scanning specific assemblies and types

While the scanning process is very rapid (as compared to the overhead of parsing XML files) you may want to control the scope of the scanning operations to match your deployment or other usage models. To facilitate control of the scope of the scanning operation, the `CodeConfigApplicationContext` provides several `.ScanXXX()` methods that accept constraints to be applied to the assemblies and types during the scanning process. The format of these constraints is that of `Predicate<T>` where `T` is either `System.Reflection.Assembly` or `System.Type`, respectively. Recall that `Predicate<T>` is any method that accepts a single parameter of `Type T` and returns a `bool`.

The list of scan methods and brief description is shown below

#### Description

`ScanAllAssemblies()` | Scans all assemblies, except those in the .NET BCL and Spring distribution
`ScanWithTypeFilter(Predicate<Type> typePredicate)` | Scans only those types that match the `typePredicate`
`ScanWithAssemblyFilter(Predicate<Assembly> assemblyPredicate)` | Scans only those assemblines that match the `assemblyPredicate`
`Scan(Predicate<Assembly> assemblyPredicate, Predicate<Type> typePredicate)` | Scans the AppDomain root path for assemblies that match the `assemblyPredicate` and types that match the `typePredicate`
`Scan(AssemblyObjectDefinitionScanner scanner)` | Performs the scan using the settings encapsulated in the provided `ObjectDefintionScanner`

Other sections below provide a more detailed description and usage examples for the scan methods.

Note that as with any `Predicate<T>` construct, the `Predicate<Assembly>` and `Predicate<Type>` constraints may be of arbitrary complexity, formulated using any combination of standard C# AND (`&&`), OR (`||`), and NOT (`!`) operators.

The following example matches assemblies with names containing "Config" but NOT containing "Configuration" OR containing "Services":

    var ctx = new CodeConfigApplicationContext();
    ctx.ScanWithAssemblyFilter(assy => (assy.Name.FullName.Contains("Config") && !assy.Name.FullName.Contains("Configuration")) || assy.Name.FullName.Contains("Services");

Because its merely a .NET delegate, note that it is also possible to pass any arbitrary method that satisfies the contract (`Predicate<T>`), so assuming that the method `IsOneOfOurConfigAssemblies` is defined elsewhere as follows...

    private bool IsOneOfOurConfigAssemblies(Assembly assy)
    {
        return (assy.Name.FullName.Contains("Config") && !assy.Name.FullName.Contains("Configuration")) || assy.Name.FullName.Contains("Services");
    };

...its possible to express the constraint in the call to .Scan(...) much more succinctly as follows:

    var ctx = new CodeConfigApplicationContext();
    ctx.ScanWithAssemblyFilter(IsOneOfOurConfigAssemblies);

None of this is anything other than simple .NET Delegate handling, but its important to take note that the full flexibility of .NET Delegates and lambda expressions is at your disposal for formulating and passing scanning constraints.

### Assembly Inclusion Constraints

To facilitate limiting the scope of scanning at the Assembly level, the `CodeConfigApplicationContext` provides several `.ScanXXX()` method signatures that accept a constraint to be applied to the assemblies at scan time. The format of this constraint matches `Predicate<System.Reflection.Assembly>` (e.g. any delegate method that accepts a single `System.Reflection.Assembly` param and returns a `bool`).

As an example, the following snippet demonstrates the invocation of the scanning operation such that it will only scan assemblies whose filename begins with the string "`MyCompany.MyApplication.Config.`" and so would match assemblies like `MyCompany.MyApplication.Config.Services.dll` and `MyCompany.MyApplication.Config.Infrastructure.dll` but would not match an assembly named `MyCompany.MyApplication.Core.dll`.

    var ctx = new CodeConfigApplicationContext();
    ctx.ScanWithAssemblyFilter(assy => assy.Name.FullName.StartsWith("MyCompany.MyApplication.Config."));

Because the `Predicate<System.Reflection.Assembly>` has access to the full reflection metadata of each assembly, it is also possible to indicate assemblies to scan based on properties of one or more contained types as in the following example that will scan any assembly that contains at least one `Type` whose name ends in "`Config`". Note that even though this constraint is dependent upon `Type` metadata, it is still a functional `Assembly` contraint, resulting in filtering only at the Assembly level.

    var ctx = new CodeConfigApplicationContext();
    ctx.ScanWithAssemblyFilter(a => a.GetTypes().Any(assy => assy.GetTypes().Any(type => type.FullName.EndsWith("Config"))));

### Type Inclusion Constraints

To limit the scope of scanning of types within assemblies, the `CodeConfigApplicationContext` provides several `.ScanXXX()` method signatures that accept a constraint to be applied to include types within assemblies at scan time. The format of this contraint matches `Predicate<System.Type>` (e.g. any delegate method that accepts a single `System.Type` param and returns a `bool`).

As an example, the following snippet demonstrates the invocation of the scanning operation such that it will only scan types whose names contain the string "Config" and so would match types named "`MyConfiguration`", "`ServicesConfiguration`", and "`ConfigurationSettings`" but not "`MyClass`".

    var ctx = new CodeConfigApplicationContext();
    ctx.ScanWithTypeFilter(type => type.FullName.Contains("Config");

There are two important aspects to take note of in re: the behavior of the `CodeConfigApplicationContext` with regards to Type Inclusion Constraints

- Type Inclusion Constraints are applied only to types defined in assemblies that also satisfy the Assembly Inclusion Constraint

  No matter whether any given `Type` satisfies the Type Inclusion Contstraint, if the `Type` is defined in an assembly that fails to satisfy the Assembly Inclusion Constraint, the `Type` will not be scanned for Object Defintions.

- There is always an implicit additional Type Inclusion Constraint of "...and the `Type` must have the `[Configuration]` attribute applied to it"

  No Type that does not have the `[Configuration]` attribute applied to its declaration will ever be scanned regardless of any Type Inclusion Constraint.

## Advanced Scanning Behavior

In some cases, you may want more fine-grained control of the scanning behavior the `CodeConfigApplicationContext`. In this section, we explore the various techniques for achieving this level of control.

### Combining Root Path, Assembly Constraints, and Type Constraints

The `CodeConfigApplicationContext` provides several `.ScanXXX(...)` method overloads that accept both an Assembly Constraint and a Type Constraint. These may be combined as in the following example:

    var ctx = new CodeConfigApplicationContext();
    ctx.Scan(assy => assy.FullName.Name.BeginsWith("Config"), type => type.Name.Contains("Infrastructure"));

Note that it is not possible to exclude specific types from the scanning process using these overloads of the `.Scan(...)` method. To get type-exclusion control, you must instantiate and pass in your own instance of the `AssemblyObjectDefinitionScanner` as described in the following section(s).

### Using your own AssemblyObjectDefintionScanner Instance

If you need more fine-grained control of the scanning behavior of the `CodeConfigApplicationContext`, you can instantiate and configure your own instance of the `AssemblyObjectDefinitionScanner` and pass it to the `.Scan(...)` method directly. The `AssemblyObjectDefinitonScanner` provides many methods for defining the contraints that will control the scanning process.

#### Scanning Specific Assemblies and Types

The `AssemblyObjectDefinitionScanner` provides methods that permit specific assemblies or types to be included or excluded.

    var scanner = new AssemblyObjectDefinitionScanner();

    scanner.AssemblyHavingType<MyConfigurations>(); //add the assembly containing this type to the list of assemblies to be scanned
    scanner.IncludeType<MySpecialConfiguration>(); //add this specific type the list of types to be scanned
    scanner.ExcludeType<MyConfigurationToBeIgnored>(); //exclude this specific type from the list of types to be scanned

    var ctx = new CodeConfigApplicationContext();
    ctx.Scan(scanner);

For those that prefer a more fluent feel to the `AssemblyObjectDefinitionScanner` API, there are methods that permit successive filter criteria to be strung together in a sequence as in the following example:

    var scanner = new AssemblyObjectDefinitionScanner();

    scanner
      .WithAssemblyFilter(assy => assy.FullName.Name.StartsWith("Config"))
      .WithIncludeFilter(type => type.Name.Contains("MyApplication"))
      .WithExcludeFilter(type => type.Name.EndsWith("Service"))
      .WithExcludeFilter(type => type.Name.StartsWith("Microsoft"));

    var ctx = new CodeConfigApplicationContext();
    ctx.Scan(scanner);

## Use of XML Namespace and scanning

By default, classes attributed with [Component] , [Repository] , [Service] , [Controller] , [Configuration] or a custom attribute that extends [Component] are the only detected candidate components. However, you can modify and extend this behavior simply by applying custom filters. Add them as include-filter or exclude-filter sub-elements of the component-scan element. Each filter element requires the type and expression attributes. The following table describes the filtering options.

### Table Filter Types

Filter Type | Example Expression | Description
--- | --- | ---
attribute | `Spring.Stereotype.RepositoryAttribute, Spring.Core` | An attribute to be present at the type level in target components.
assignable | `My.Namespace.IFoo, My.Assembly` | A class (or interface) that the target components are assignable to (extend/implement).
regex | `My.NameSpace.*.*Dao` | A regex expression to be matched by the target components class names.
custom | `My.Namespace.MyTypeFilter, My.Assembly` | A custom implementation of the `Spring.Context.Attributes.TypeFilters.ITypeFilter` interface.

The following example shows the XML configuration ignoring all [Repository] attributed classes and only scanning types with names that end with Dao using "stub" repositories instead.

    <objects>

       <context:component-scan base-assemblies="My.Namespace">
          <context:include-filter type="regex" expression=".*Dao"/>
          <context:exclude-filter type="annotation" expression="Spring.Stereotype.RepositoryAttribute, Spring.Core"/>
       </context:component-scan>

    </beans>