diff --git a/doc/reference/src/codeconfig-attribute-reference.xml b/doc/reference/src/codeconfig-attribute-reference.xml new file mode 100644 index 00000000..2d6fcf5b --- /dev/null +++ b/doc/reference/src/codeconfig-attribute-reference.xml @@ -0,0 +1,574 @@ + + + Attribute Reference + + In this chapter, we will explore the attributes that are the essential + components for declaring Object Definitions with Spring CodeConfig. These + attributes have a corresponding representation in Spring XML so should be + very familiar to current Spring.NET users. + + + [Configuration] Attribute + + The [Configuration] + attribute is applied to classes that contain one or more [ObjectDef] + attributed-methods. During scanning by the + CodeConfigApplicationContext, only types having the + [Configuration] + attribute will be considered candidates to contain Object Definition + configurations. + + + Using the Configuration Attribute + + + + + Simple Usage + + The most common usage of the [Configuration] + attribute simply applies the attribute to a class without any + attribute parameters. The name of the of the type, once registered + with the CodeConfigApplicationContext, will be the + name of the class itself. Note that it is not a common use-case to ask + the container for this configuration class.[Configuration] +public class MyConfigurationClass +{ + //[ObjectDef] methods here +} + + + + Controlling the Name of the Configuration Class + + While not a common use-case, if you need fine-grained control + over the name of the type registered with the + CodeConfigApplicationContext, the [Configuration] + attribute accepts a Name parameter which will be + applied to the registered Object Definition in the + CodeConfigApplicationContext.[Configuration("MySpecialConfigurationClass")] +public class MyConfigurationClass +{ + //[ObjectDef] methods here +} + + + + + + [ObjectDef] Attribute + + The [ObjectDef] + attribute is applied to one or more methods within any class to which the + [Configuration] + attribute has been applied. During scanning, any public + virtual method having the [ObjectDef] + attribute is considered to contain Object Definition metadata. + + + Using the ObjectDef Attribute + + + + + Simple Usage + + The first usage of the [ObjectDef] + attribute simply applies the attribute to the method. The name of the + of the Object to be registered with the + CodeConfigApplicationContext, will be the name of + the method itself.[Configuration] +public class MyConfigurationClass +{ + [ObjectDef] + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + + + + Controlling the Name and Aliases of the Defined Object + + If you need to control the name of the Object registered with + the CodeConfigApplicationContext, the + [ObjectDef] + attribute accepts one or more comma-delimited names as aliases for the + Object when registered. + + [Configuration] +public class MyConfigurationClass +{ + [ObjectDef(Names="TheHomeController")] + public virtual HomeController HomeController() + { + return new HomeController(); + } + + [ObjectDef(Names="TheSpecialNameForAboutController,AliasForAboutController")] + public virtual AboutController AboutController() + { + return new AboutController(); + } +} + + + + Setting an Init Method for the Object + + If you need to declare an Initialization Method for the object + definition, the [ObjectDef] + attribute accepts a method name to be invoked at the appropriate stage + in the object's creation by the + CodeConfigApplicationContext. + + [Configuration] +public class MyConfigurationClass +{ + [ObjectDef(InitMethod="AfterCreation")] //assumes a public method on the HomeController type named 'AfterCreation()' + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + + + You can just also call the method 'AfterCreation' inside the + body of the HomeController implementation itself. + + + + + Setting a Destroy Method for the Object + + If you need to declare a Destroy Method for the object + definition, the [ObjectDef] + attribute accepts a method name to be invoked at the appropriate stage + in the object's destruction by the + CodeConfigApplicationContext. + + [Configuration] +public class MyConfigurationClass +{ + [ObjectDef(DestroyMethod="CleanupResources")] //assumes a public method on the HomeController type named 'CleanupResources()' + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + + + + + + [DependsOn] Attribute + + The [DependsOn] attribute can be applied to any + [ObjectDef]-attributed + method to declare a construction sequence dependency upon one or more + objects that the CodeConfigApplicationContext will + ensure are created prior to the creation of the current object. This is + only required if there is a hidden depedency between the two classes that + isn't exposed via constructor or setter properties. + + + Using the DependsOn Attribute + + + + + Controlling Creation Dependencies + + The [DependsOn] attribute accepts one or more + comma-delimited strings representing the names of the objects upon + which the current object will depend. + + [Configuration] +public class MyConfigurationClass +{ + [ObjectDef] + [DependsOn("Dependency1")] //HomeController requires "Dependency1" to be created first + public virtual HomeController HomeController() + { + return new HomeController(); + } + + [ObjectDef] + [DependsOn("Dependency1", "Dependency2")] //AboutController requires "Dependency1" and "Dependency2" to be created first + public virtual AboutController AboutController() + { + return new AboutController(); + }b +} + + + + + + [Import] Attribute + + The [Import] attribute allows you to identify one + or more additional types that will also be scanned when the current type + is scanned. + + + Using the Import Attribute + + + + + Specifying Additional Types to Scan + + To support your specifying additional types to scan, the + [Import] attribute accepts one or more + comman-delimited Types to scan as well. To be candidates for scanning, + the types listed in this array must also have the [Configuration] + attribute applied to them. Note that no error is reported if these + types lack the[Configuration] attribute, but + without it they will not satisfy the scanner's requirements for + Configuration candidates. + + [Configuration] +[Import(typeof(MySecondConfiguration), typeof(MyThirdConfiguration))] +public class MyConfigurationClass +{ + [ObjectDef] + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + +[Configuration] +public class MySecondConfiguration +{ + [ObjectDef] + public virtual AboutController AboutController() + { + return new AboutController(); + } +} + +[Configuration] +public class MyThirdConfiguration +{ + [ObjectDef] + public virtual SomeOtherController SomeOtherController() + { + return new SomeOtherController(); + } +} + + + + Chaining [Import] Directives + + Types pointed to by one [Import] attribute + may in turn have their own [Import] attributes + pointing to yet more types to scan. Using this approach, its possible + to specify perhaps only a single 'root' class from which to 'begin' + the scan and leverage the [Import] attribute to + 'chain' successive types into the scanning scope, transitively + pointing from one [Configuration]-attributed + type to the next as in the following example where + MyConfigurationClass has an + [Import] attribute pointing to the + MySecondConfiguration class which in turn has an + [Import] attribute pointing to the + MyThirdConfiguration class. + + [Configuration] +[Import(typeof(MySecondConfiguration))] +public class MyConfigurationClass +{ + [ObjectDef] + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + +[Configuration] +[Import(typeof(MyThirdConfiguration))] +public class MySecondConfiguration +{ + [ObjectDef] + public virtual AboutController AboutController() + { + return new AboutController(); + } +} + +[Configuration] +public class MyThirdConfiguration +{ + [ObjectDef] + public virtual SomeOtherController SomeOtherController() + { + return new SomeOtherController(); + } +} + + Given this series of transitive or 'chained' + [Import]attributes, the + CodeConfigApplicationContext would only need to be + told to scan the single MyConfigurationClass type + in order to effectively scan and discover the [ObjectDef] + methods contained all three [Configuration] + types. Using this approach, its possible to use a compositional + approach to segregate [ObjectDef] + methods into multiple [Configuration] + classes and then chain them together just as one might do with XML + based configuration files for many of the other + IApplicationContext implementations. + + + + + + [ImportResource] Attribute + + Just as the [Import] attribute provides the + ability to reference and import additional types attributed with the + [Configuration] + attribute, the [ImportResrource] attribute + permits referencing and importing Object Defintions from any + IResource implementation including those defined + natively in Spring.NET ("file://", + "assembly://", etc.). + + + Using the ImportResourceAttribute + + + + + Specifying an IResource + + To import an IResource, simply reference its + path in the [ImportResource] attribute. In the + following example, the embedded assembly resource + ObjectDefinitions.xml is being imported into the + process of scanning and parsing the + MyConfigurationClass type. This makes all of the + object definitions present in the embedded + ObjectDefinitions.xml file available to the + CodeConfigApplicationContext as it builds its + Object Defintions. + + [Configuration] +[ImportResource("assembly://MyApplication.Config/MyCompany.MyApplication.Config/ObjectDefinitions.xml")] +public class MyConfigurationClass +{ + [ObjectDef] + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + + + + Specifying Multiple IResources + + To import multiple IResources, simply provide + multiple [ImportResource] attributes, each with the + single resource to import. The following example demonstrates + importing an embedded assembly resource as well as two XML files on + disk. + + [Configuration] +[ImportResource("assembly://MyApplication.Config/MyCompany.MyApplication.Config/ObjectDefinitions.xml")] +[ImportResource("file://ServiceObjectDefinitions.xml")] +[ImportResource("file://c:/MySpecialConfigLocation/Deployment/SiteB/RepositoryObjectDefinitions.xml")] +public class MyConfigurationClass +{ + [ObjectDef] + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + + + + Specifying a specific IObjectDefintionReader to Parse the + IResource + + By default, the [ImportResource] attribute + will use the Spring.NET provided + XmlObjectDefinitionReader to parse the imported + IResource. If your imported resource cannot be + parsed with the XmlObjectDefinitionReader then you + can provide the type of the specific implementation of + IObjectDefinitionReader that the + [ImportResource] process should use. Note that this provided + type must implement the IObjectDefinitionReader + interface or an Exception will be thrown when the + [ImportResource] attribute is evaluated. + + [Configuration] +[ImportResource("assembly://MyApplication.Config/MyCompany.MyApplication.Config/ObjectDefinitions.CSV", DefinitionReader = typeof(MyCommaSeparatedValueObjectDefinitionReader))] +public class MyConfigurationClass +{ + [ObjectDef] + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + + + + + + [Lazy] Attribute + + The [Lazy] attribute allows you to specify that + the object described by the [ObjectDef] + should either be be lazily or eagerly instantiated. + + + Using the Lazy Attribute + + + + + Specifying Lazy Instantiation + + To specify Lazy Instantiation of any singleton object by the + CodeConfigApplicationContext, apply the + [Lazy] attribute to any [ObjectDef]-attributed + method as in the following example. Note that the default usage of + the[Lazy] attribute sets Lazy = true and so + [Lazy] and [Lazy(true)] are + considered functionally equivalent. Also note that specification of + lazy instantiation is only valid for Singleton-scoped objects; any + attempt to apply the [Lazy] attribute to a + non-singleton-scoped [ObjectDef] + method will result in an exception thrown by the underlying + ApplicationContext. + + [Configuration] +public class MyConfigurationClass +{ + [ObjectDef] + [Lazy] //functionally equivalent to [Lazy(true)] + public virtual HomeController HomeController() + { + return new HomeController(); + } + + [ObjectDef] + [Lazy] //invalid here because the scope is non-Singleton + [Scope(ObjectScope.Prototype)] + public virtual InvalidController InvalidController() + { + return new InvalidController(); + } +} + + + + Specifying Non-Lazy (eager) Instantiation + + As the default instantiation behavior for the + CodeConfigApplicationContext is to perform eager + instantiation, no special attribute needs to be applied to achieve + eager instantiation of the object. However, the + [Lazy] attribute will accept a + bool value of false if you + desire to be explicit about the [Lazy] setting for + the [ObjectDef] + as shown in the following code snippet. + + [Configuration] +public class MyConfigurationClass +{ + [ObjectDef] + [Lazy(false)] //functionally equivalent to simply not applying the [Lazy] attribute at all + public virtual HomeController HomeController() + { + return new HomeController(); + } +} + + + + + + [Scope] Attribute + + The [Scope] attribute permits you to declare the lifetime of the + object managed by the CodeConfigApplicationContext for + each [ObjectDef]-attributed + method. + + + Scope Attribute Usage + + The [Scope] attribute accepts a single + ObjectScope enum argument as + defined by Spring.NET and demonstrated in the following snippet: + + [Configuration] +public class MyConfigurationClass +{ + [ObjectDef] + [Scope(ObjectScope.Prototype)] + public virtual HomeController HomeController() + { + return new HomeController(); + } + + [ObjectDef] + [Scope(ObjectScope.Singleton)] //technically redundant since all types default to Singleton ObjectScope + public virtual CustomerRepository CustomerRepository() + { + return new CustomerRepository(); + } + + [ObjectDef] + [Scope(ObjectScope.Session)] + public virtual UserSettings UserSettings() + { + return new UserSettings(); + } +} + + + diff --git a/doc/reference/src/codeconfig-context.xml b/doc/reference/src/codeconfig-context.xml new file mode 100644 index 00000000..723b3b35 --- /dev/null +++ b/doc/reference/src/codeconfig-context.xml @@ -0,0 +1,536 @@ + + + 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: + + + + Instantiate an instance of the + CodeConfigApplicationContext + + + + [optional] Provide one ore more filtering + constraints to control the Assemblies and/or Types to participate in + the scanning + + + + Perform the actual scanning + + + + 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> +
+
diff --git a/doc/reference/src/codeconfig-migration-example.xml b/doc/reference/src/codeconfig-migration-example.xml new file mode 100644 index 00000000..5d726095 --- /dev/null +++ b/doc/reference/src/codeconfig-migration-example.xml @@ -0,0 +1,700 @@ + + + Introducing CodeConfig + + + A Dependency Injection Example + + We will introduce the new code based approach by working with a very + simple application that will provide us the context to understand the + concepts of CodeConfig. We start by examining a sample application that + uses Spring.NET configured via ‘traditional’ XML configuration files. Then + we show how CodeConfig can be used to achieve the same results without any + XML configuration files at all. + + To begin with, let’s explore the sample application that we will be + working with. This sample app is included in the Spring.NET CodeConfig + download package in the + /examples/Spring.CodeConfig.Migration folder. + + To keep things simple, it’s just a .NET console application designed + to calculate and display the prime numbers between zero and an arbitrary + maximum number. There are four classes that must collaborate together to + do the work: ConsoleReporter, + PrimeGenerator, + PrimeEvaluationEngine, and + OutputFormatter. ConsoleReporter + depends on the PrimeGenerator which in turn depends on + the PrimeEvaluationEngine to calculate the prime + numbers. ConsoleReporter also depends on + OutputFormatter to format the results. The main console + application then simply asks ConsoleReporter to write + its report and ConsoleReporter goes to work. The + following Figure is a UML class diagram showing a simple way to visualize + the dependencies between these objects. + + + + + + + + + + + + + + + + + + A simple Main() method that would do this without + the Spring.NET container could look something like Listing 1. Note the + in-line injection of dependencies via constructor arguments that builds up + the collaborating objects. + + //Listing 1 (sample Main method not using Spring.NET) +static void Main(string[] args) +{ + ConsoleReport report = new ConsoleReport( + new OutputFormatter(), + new PrimeGenerator(new PrimeEvaluationEngine())); + + report.MaxNumber = 1000; + report.Write(); + + Console.WriteLine("--- hit enter to exit --"); + Console.ReadLine(); +} + + Using Spring.NET, as opposed to manually injecting dependencies as + in Listing 1, the collaborating objects are composed together with their + dependencies injected by the Spring.NET container at run-time. Initially, + the configuration of these objects is controlled from a Spring.NET XML + configuration file (see Listing 2). + + <!-- Listing 2 (Spring.NET XML Configuration file, application-context.xml) --> +<?xml version="1.0" encoding="utf-8" ?> +<objects xmlns="http://www.springframework.net"> + + <object name="ConsoleReport" type="Primes.ConsoleReport, Primes"> + <constructor-arg ref="PrimeGenerator"/> + <constructor-arg ref="OutputFormatter"/> + <property name="MaxNumber" value="1000"/> + </object> + + <object name="PrimeGenerator" type="Primes.PrimeGenerator, Primes"> + <constructor-arg> + <object type="Primes.PrimeEvaluationEngine, Primes"/> + </constructor-arg> + </object> + + <object name="OutputFormatter" type="Primes.OutputFormatter, Primes"/> + +</objects> + + In Listing 2 you can also see the use of “ref” + element to refer to collaborating objects and the property + “MaxNumber” being set to “1000” on + the ConsoleReport object after it’s constructed. This + is the maximum number up to which we want the software to calculate prime + numbers. In Listing 3 we see the construction of the + XmlApplicationContext which is initialized by passing + it the name of the XML Configuration file. This container is then used to + resolve the ConsoleReport object with all of its + dependencies properly satisfied and its MaxNumber + property assigned the value of 1000. + + //Listing 3 (initializing the XmlApplicationContext container) +static void Main(string[] args) +{ + IApplicationContext ctx = CreateContainerUsingXML(); + + ConsoleReport report = ctx["ConsoleReport"] as ConsoleReport; + report.Write(); + + ctx.Dispose(); + + Console.WriteLine("--- hit enter to exit --"); + Console.ReadLine(); +} + +private static IApplicationContext CreateContainerUsingXML() +{ + return new XmlApplicationContext("application-context.xml"); +} + + While this XML-based configuration is well-understood by Spring.NET + users and others alike as a common method for expressing configuration + settings, it suffers from several challenges common to all XML file + including being overly-verbose and full of string-literals that are + unfriendly to most of the modern refactoring tools. + + + + Migration to CodeConfig + + To reduce or even eliminate the use of XML for configuring the + Spring.NET DI container, let’s look at how we can express the same + configuration metadata in code using Spring.NET CodeConfig. There are + several steps to using CodeConfig. We will look at each of them in the + likely sequence that one would follow to convert an existing XML-based + configuration for Spring.NET over to use the CodeConfig approach. + + + The CodeConfig Classes + + + Creating the CodeConfig Classes + + First, we need to construct one or more classes to contain our + configuration metadata and attribute them properly. Spring.NET + CodeConfig relies upon attributes applied to classes and methods to + convey its metadata. Shown in Listing 4 is the CodeConfig class + (PrimesConfiguration) for our sample application. + // Listing 4, (Spring.NET Configuration Class, PrimesConfiguration.cs) +using System; +using System.Configuration; +using Primes; +using Spring.Context.Attributes; + +namespace SpringApp +{ + [Configuration] + public class PrimesConfiguration + { + [ObjectDef] + public virtual ConsoleReport ConsoleReport() + { + ConsoleReport report = new ConsoleReport(OutputFormatter(), PrimeGenerator()); + + report.MaxNumber = Convert.ToInt32(ConfigurationManager.AppSettings.Get("MaximumNumber")); + return report; + } + + [ObjectDef] + public virtual IOutputFormatter OutputFormatter() + { + return new OutputFormatter(); + } + + [ObjectDef] + public virtual IPrimeGenerator PrimeGenerator() + { + return new PrimeGenerator(new PrimeEvaluationEngine()); + } + } +} + + + + Elements of the CodeConfig Classes + + Let’s explore the important elements of the CodeConfig file in + Listing 4 to understand how it can convey the same information to the + Spring.NET container as the XML file in Listing 2. + + + The Class + + At the class level, you will notice the + PrimesConfiguration class has the[Configuration] + attribute applied to it. During the initialization phase of the DI + container, Spring.NET CodeConfig reads classes with these + attributes. Note that there is no specific inheritance hierarchy + required of a configuration class: no special base class or + interface implementation is required, leaving you free to leverage + inheritance and polymorphism to achieve some interesting + configuration and composition scenarios. Also note these special + identifying attributes are only applied to your CodeConfig classes, + not the types for which they are providing object definition + metadata. This means that your classes that do the work of your + application (e.g., ConsoleReport, + PrimeGenerator, etc.) are free to remain + undiluted POCO (Plain-Old-CLR-Object) classes that have themselves + no direct dependency on the Spring.NET framework. + + + + The Methods + + At the member level of the + PrimesConfiguration class, you will notice + several methods having the [ObjectDef] + attribute. This attribute identifies the method to which it is + applied as being the logical representation of a single object + definition for the Spring.NET container. + + To begin understanding how this works let’s look at the + simplest of the definitions, that of the OutputFormatter. Let’s + start with the method visibility: all [ObjectDef] + methods must be declared both public and virtual. + + + Why must the [ObjectDef] methods be virtual? + + The requirement for the [ObjectDef] + methods being virtual comes from the need when using CodeConfig + for the container to proxy [ObjectDef] + methods on the [Configuration] + classes. When the container is asked for an object, this proxy + intercepts the invocation of the [ObjectDef] + methods and ensures that requests for objects respect object + scoping rules like singleton and prototype. Singleton scope + ensures that if you ask the container multiple times for the same + named object, it will always return the same instance rather than + a new one each time. Singleton scope is common in server-side + programming and is the default lifecycle in Spring.NET. + + + The method return type, IOutputFormatter, + becomes the type that the DI container will be configured to + register. The method name itself, + OutputFormatter, is the equivalent of the id or + name that will be assigned to the object in the container. This name + can also be controlled by setting the Names + property on the [ObjectDef] + attribute itself. + + The body of the OutputFormatter() method + simply creates a new instance of the + OutputFormatter and returns it. In simple terms, + we can think of the OutputFormatter() method as a + factory method that knows how to construct and return an instance of + something that implements the IOutputFormatter + interface (in this case, the concrete + OutputFormatter class). + + + + More Complex Methods + + To understand a slightly more complex [ObjectDef] + method, let’s now examine the PrimeGenerator() + method. Given what we already know about CodeConfig, it’s easy to + see that the PrimeGenerator() method describes an + Object Definition that will be registered with the container under + the name “PrimeGenerator” (the method name) and + the type IPrimeGenerator (the return type of the + method). + + The method needs to return a new + PrimeGenerator but unlike the + OutputFormater class that offers an empty default + constructor, the PrimeGenerator class’ only + public constructor requires an instance of the + PrimeEvaluationEngine class be passed to it. To + satisfy this constructor dependency, we simply create a new + PrimeEvaluationEngine object in-line and pass it + to the new PrimeGenerator class. In this way, the + dependency between PrimeGenerator and + PrimeEvaluationEngine is satisfied in much the + same way as when coded ‘by hand’ as shown in Listing 1. + + As a slightly more complex [ObjectDef] + example, let’s examine the ConsoleReport() method + next. This method needs to return a new + ConsoleReport instance, but as with the + PrimeGenerator class we lack a zero-argument + public constructor. The only public constructor of the + ConsoleReport class requires an + IOutputFormatter instance and an + IPrimeGenerator instance be provided. In our call + to new up an instance of the ConsoleReport class + in the ConsoleReport() [ObjectDef] + method, we are invoking the other [ObjectDef] + methods themselves to return these types. Since these other methods + in turn return IOutputFormatter and + IPrimeGenerator instances respectively, calls to + these other methods will satisfy the constructor dependency of the + ConsoleReport class and thus permit us to create + a new ConsoleReport to return at the end of the + ConsoleReport() method itself. In this manner, we + are delegating from one [ObjectDef] method to + the other [ObjectDef] + methods to create the object graph that we seek to return from the + call to the ConsoleReport() method. + + + + Controlling Properties on Objects + + But what about the “MaxNumber” property + that is set for the ConsoleReport object in the + XML file in Listing 2? As you can see from Listing 4, setting this + property on our ConsoleReport object is as simple + as…well, setting the property on our + ConsoleReport object! Since our + ConsoleReport() method merely has to return a new + ConsoleReport instance, we are completely free to + use any approach (in code) we choose to modify the + ConsoleReport instance before we return it. In + this case, it’s a simple matter of reading the value out of the + App.Config file and then setting the property to + the desired value before we return the instance of the + ConsoleReport object from the method. + + + + + + Creating and Initializing the Application Context + + Once we have translated the XML configuration file in Listing 2 + into the CodeConfig class in Listing 4, we need to tell our application + to use it. For that, we need to switch from encapsulating our container + in the Spring.NET XmlApplicationContext to + encapsulating it in the CodeConfigApplicationContext + instead. Just as the XmlApplicationContext is + designed to use XML as the initial entry point to its configuration + settings, the CodeConfigApplicationContext is + designed to scan assemblies for [Configuration] + classes and [ObjectDef] + methods as the initial entry point to its configuration settings. + Listing 5 shows the CreateContainerUsingCodeConfig() + method from the Program.cs file in the sample + application that demonstrates this process. + + //Listing 5 (bootstrapping the CodeConfigApplicationContext from Program.cs) +private static IApplicationContext CreateContainerUsingCodeConfig() +{ + CodeConfigApplicationContext ctx = new CodeConfigApplicationContext(); + ctx.ScanAllAssemblies(); + ctx.Refresh(); + return ctx; +} + + After instantiating the + CodeConfigApplicationContext, we next invoke the + ScanAllAssemblies() method to perform the scanning + for the [Configuration]-attributed + classes and [ObjectDef]-attributed + methods within our project. Lastly, the container is initialized by + calling the Refresh() method and then the + ready-to-use context is returned from the method. In the invocation of + the ScanAllAssemblies() method, we are asking the + CodeConfigApplicationContext to scan the current + AppDomain’s root folder and all subfolders recursively for all + assemblies that might contain CodeConfig classes (classes having the + [Configuration] + attribute). + + + + + More Granular Control Using CodeConfig + + The example in Listing 4 and Listing 5 demonstrates only the most + basic use-cases for CodeConfig. More granular control over each of the + definitions is provided by applying additional attributes to the [Configuration] + classes and [ObjectDef] + methods and by setting various values on these attributes. Among these are + the following: + + + + [Scope] for + controlling object lifecycle settings on a [ObjectDef] + such as singleton, prototype, etc. + + + + [Import] for + chaining [Configuration] + classes together so that you can logically divide your [ObjectDef] + methods among multiple classes in much the same way you may do so with + multiple XML files that provide pointers to other XML files + + + + [ImportResource] + for combining [Configuration] + classes with any of Spring.NET’s many implementations of its + IResource abstraction (file://, assembly://, etc.), + the most common one being an XML resource so that you can define part + of your configuration metadata in [Configuration] + classes and other parts of it in XML files as either embedded + resource(s) in your assemblies or as file(s) on disk. + + + + [Lazy] for + controlling lazy instantiation of singleton objects + + + + If you require aliases (additional, multiple names) for the Type + in the container, the [ObjectDef] + attribute also accepts an array of strings that if provided will be + registered as aliases for the Type registration. + + + + In addition, finer-grained control of the specific assemblies to + scan, and specific [Configuration] + classes to include and/or exclude is supported by the scanning API. It is + also possible to compose configurations by dividing your [ObjectDef] + methods into multiple different [Configuration] + classes and then to assemble them as building blocks to configure your + container as it is initialized. + + The CodeConfig approach enables us to express the same configuration + metadata to our Dependency Injection container as the XML file in Listing + 2 had provided, but in a form that is at once both significantly more + powerful and flexible as well as more resilient to the refactoring our + container-managed application objects. + + To address additional common non-XML configuration scenarios, such + as the XML schemas for AOP and Transaction management, Spring.NET is also + evolving a more fluent-style configuration API that will build upon + CodeConfig in even more flexible ways in the near future including + convention-based registration of objects. + + + + Organizing and Composing Multiple [Configuration] Classes + + The examples referenced in this + document and provided in this distribution almost all employ merely a + single [Configuration] class + from which their ApplicationContext is to be configured. For these simple + examples this approach is viable but just as is the case when configuring + the ApplicationContext via XML, any significantly complex solution is + likely to require separating your [ObjectDef] methods into + multiple [Configuration] + classes. + + Just as there are several strategies for effectively managing + multiple XML configuration files, so too are there many options available + to the developer to organize and compose multiple [Configuration] classes + together in a larger solution. This section doesn't attempt to cover all + of the available options in deep detail, but is intended to provide a + high-level understanding of some of the techniques that can be combined + together to help manage multiple such classes. Users familair with the + common techniques for composing together multiple XML configuration files + for Spring.NET will recognize some of these same patterns applied to [Configuration] classes + in the following sections as well. + + + Multiple Stand-Alone Configuration Classes + + The simplest organization approach is providing multiple + stand-alone [Configuration] + classes. In this scenario, [ObjectDef] methods are + organized into separate [Configuration] + classes but each of the [Configuration] + classes is entirely self-contained and unrealted to the others. The + decomposition principles can of course be anything of your choosing. One + simple possibility might be to divide your configuration data between + different kinds of services as in the following example: + + [Configuration] +public class WcfServicesConfigurations +{ + [ObjectDef] + public virtual IWebService MySpecialService() + { + //construct and return a IWebService implementation here + } +} + +[Configuration] +public class RepositoryServicesConfigurations +{ + [ObjectDef] + public virtual ICustomerRepository MyCustomerRepository() + { + //construct and return a ICustomerRepository implementation here + } + + [ObjectDef] + public virtual IShippingRepository MyShippingRepository() + { + //construct and return a IShippingRepository implementation here + } +} + + In this example, both of these [Configuration] + classes would need to be explicitly scanned and registered with the + CodeConfigApplicationContext + since they each are completely stand-alone and both are needed for the + proper configuration of the ApplicationContext. Since these two classes + in this example have no interdependencies between them, each class may + be placed into a different file or even assembly. + + + + High-Level [Configuration] Classes that [Import] Others + + Another strategy for composing multiple [Configuration] + classes together is to devise one or more 'high-level entry-point' + classes and leverage the [Import] attribute + so that the scanning of the high-level class automatically imports one + or more lower-level classes. The high-level classes may contain + [ObjectDef] methods of their own or merely hold reference to one or + more [Import] classes as needed. + + [Configuration] +[Import(typeof(MyWebServicesConfigurations))] +[Import(typeof(MyMessagingServicesConfigurations))] +[Import(typeof(MyPersistenceServicesConfigurations))] +public class ServicesConfigurations +{ + //rest of class here as needed +} + + In this example, only the + ServicesConfigurations class needs to be scanned + because the [Import] + attributes point directly to the other classes to scan for + [Configuration] + and [ObjectDef] + metadata. + + + + Referencing [ObjectDef]s from one [Configuration] Class in + Another + + Once you decompose your [ObjectDef] + methods into separate classes, often you will find that you have a need + to reference the objects defined in one [Configuration] + class when coding the [ObjectDef] + methods in another [Configuration] + class. The architecture of Spring CodeConfig for .NET makes it simple to + address this need: you can simply ask the ApplicationContext to resolve + the needed Type. + + To understand how this works, its first important to understand + that [Configuration] + classes are themselves registered as types in the ApplicationContext + in addition to the types defined in their [ObjectDef] + methods. Combining that knowledge with the special + IApplicationContextAware interface in Spring.NET + allows us to ask the ApplicationContext to inject + itself into our [Configuration] + classes. This ApplicationContext is then available to us to resolve + requests for needed types that may be defined elsewhere, whether in + other [Configuration] + classes or perhaps even other XML files. + + Let's explore the following example where the + SecondConfiguration class needs access to the + TransactionManager that is defined in the + FirstConfiguration class in order to properly build + and configure a CustomerRepository instance: + + [Configuration] +public class FirstConfiguration +{ + [ObjectDef] + public virtual TransactionManager MySpecialTransactionManager() + { + return new TransactionManager(); + } +} + +[Configuration] +public class SecondConfiguration : IApplicationContextAware //note the interface implementation +{ + //field to hold the injected context + private IApplicationContext _context; + + //property setter defined by the IApplcationContextAware interface + // so that the context can inject itself into the class + public IApplicationContext ApplicationContext { set { _context = value; } } + + [ObjectDef] + public virtual ICustomerRepository CustomerRepository() + { + //to construct the CustomerRepository, we need a TransactionManager instance + // as a constructor argument so let's ask the injected context to resolve one for us + return new CustomerRepository(_context.GetObject<TransactionManager>()); + } +} + +//somewhere else in your solution the CustomerRepository class is defined as follows... +public class CustomerRespository : ICustomerRespository +{ + private TransactionManager _transactionManager; + + public CustomerRespository(TransactionManager transactionManager) + { + _transactionManager = transactionManager; + } +} + + In this way, there is no direct coupling between [Configuration] + classes and the SecondConfiguration class is only aware of the + ApplicationContext itself and the actual Types it needs to construct the + Types described in its [ObjectDef] + methods. + + + diff --git a/doc/reference/src/codeconfig-sample-apps.xml b/doc/reference/src/codeconfig-sample-apps.xml new file mode 100644 index 00000000..c0703b95 --- /dev/null +++ b/doc/reference/src/codeconfig-sample-apps.xml @@ -0,0 +1,266 @@ + + + Sample Applications + +
+ Overview + + The Spring CodeConfig for .NET project includes three sample + applications: + + + + Spring.IoCQuickStart.MovieFinder + + + + Spring.MvcQuickStart + + + + Spring.CodeConfig.Migration + + +
+ +
+ Spring.IoCQuickStart.MovieFinder + + The Spring.IoCQuickStart.MovieFinder sample application is the same + fundamental code as provided in the sample app by the same name that is + provided with the main Spring.NET + Framework download package. This section assumes you are already + familiar with the sample application as provided in that download package. + This version of this sample application has been modified to rely upon + CodeConfig for its Object Definitions. + +
+ Modifying App.config + + The first modification to the existing sample application involves + changes to the <spring> element in the + App.config file: + + <spring> + + <parsers> + <!-- Equivalent to 'NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));' --> + <parser type="Spring.Context.Config.ContextNamespaceParser, Spring.Core.Configuration" /> + </parsers> + + <context> + <!-- using embedded assembly configuration file --> + <resource uri="assembly://Spring.IocQuickStart.MovieFinder/Spring.IocQuickStart.MovieFinder/CodeConfigBootstrap.xml"/> + </context> + + </spring> + + The important changes here are the introducton of the + <parsers> section (to register the + ContextNamespaceParser required for CodeConfig) and + the change of the <resource> element to point + to the CodeConfigBootstrap.xml file instead of the + Appcontext.xml file as before. +
+ +
+ Replacing Appcontext.xml with CodeConfigBootstrap.xml + + Where before the Appcontext.xml contained all + of the XML-based object definitions for the application, in this case + the CodeConfigBootstrap.xml merely contains the + single instruction telling the context to use CodeConfig: + + <?xml version="1.0" encoding="utf-8" ?> +<objects xmlns="http://www.springframework.net" + xmlns:context="http://www.springframework.net/context"> + + <description>An example that demonstrates code based configuration for object definitions.</description> + + <context:code-config/> + +</objects> + + + In this case, the single + <context:code-config/> element is sufficient to + tell the context to perform scanning for its object definition + metadata. +
+ +
+ Introducing the MovieFinderConfiguration CodeConfig class + + The final modification needed to migrate the sample application to + rely upon CodeConfig is to author the classes that will provide the + Object Definitions for the Application Context to discover when + performing the scan. In the case of this simple application, this is + encapsulated in the single new + MovieFinderConfiguration class as shown in the + following: + + [Configuration] + public class MovieFinderConfiguration + { + + [ObjectDef] + public virtual MovieLister MyMovieLister() + { + MovieLister movieLister = new MovieLister(); + movieLister.MovieFinder = FileBasedMovieFinder(); + return movieLister; + + } + + [ObjectDef] + public virtual IMovieFinder FileBasedMovieFinder() + { + return new ColonDelimitedMovieFinder(new FileInfo("movies.txt")); + } + } + + Using a combination of [Configuration] + and [ObjectDef] + attributes, this class faithfully reproduces the same Object Definition + configuration as had been described by the + Appcontext.xml file in the iniitial sample + application as delivered with the main Spring.NET Framework + download. +
+
+ +
+ Spring.MvcQuickStart + + The Spring.MvcQuickStart sample application is the same fundamental + code as provided in the sample app by the same name that is provided with + the main + Spring.NET Framework download package. This section assumes you are + already familiar with the sample application as provided in that download + package. This version of this sample application has been modified to rely + upon CodeConfig for its Object Definitions. + +
+ Modifying Web.config + + The first modification to the existing sample application involves + changes to the <spring> element in the + Web.config file: + + <spring> + <parsers> + <!-- Equivalent to 'NamespaceParserRegistry.RegisterParser(typeof(ContextNamespaceParser));' --> + <parser type="Spring.Context.Config.ContextNamespaceParser, Spring.Core.Configuration" /> + </parsers> + + <context> + <resource uri="~/Config/CodeConfigBootsrap.xml"/> + </context> + </spring> + + The important changes here are the introducton of + the<parsers> section (to register the + ContextNamespaceParser required for CodeConfig) and + the change of the <resource> element to point + to the CodeConfigBootstrap.xml file instead of the + controllers.xml file as before. + + In addition, the section name for the + <parsers> element must be registered with the + <spring> sectionGroup as shown here so that the + element can be properly interpreted: + + <configSections> + <sectionGroup name="spring"> + <section name="context" type="Spring.Context.Support.MvcContextHandler, Spring.Web.Mvc"/> + <section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/> + </sectionGroup> + + <!-- + remainder of configSections element here... + --> + + </configSections> +
+ +
+ Replacing controllers.xml with CodeConfigBootstrap.xml + + Where before the controllers.xml file contained + all of the XML-based object definitions for the controllers for our MVC + application, in this case the CodeConfigBootstrap.xml + merely contains the single instruction telling the context to use + CodeConfig: + + <?xml version="1.0" encoding="utf-8" ?> +<objects xmlns="http://www.springframework.net" + xmlns:context="http://www.springframework.net/context"> + + <context:code-config/> + +</objects> + + In this case, the single + <context:code-config/> element is sufficient to + tell the context to perform scanning for its object definition + metadata. +
+ +
+ Introducing the ControllerConfiguration CodeConfig class + + The final modification needed to migrate the sample application to + rely upon CodeConfig is to author the classes that will provide the + Object Definitions for the Application Context to discover when + performing the scan. In the case of this simple application, this is + encapsulated in the single new + ControllerConfiguration class as shown in the + following: + + [Configuration] + public class ControllerConfiguration + { + [ObjectDef] + [Scope(ObjectScope.Prototype)] + public virtual HomeController HomeController() + { + HomeController controller = new HomeController(); + controller.Message = "Welcome to ASP.NET MVC powered by Spring.NET (Code-Config)!"; + return controller; + } + } + + Using a combination of [Configuration] + and [ObjectDef] + attributes, this class faithfully reproduces the same Object Definition + configuration as had been described by the + controllers.xml file in the iniitial sample + application as delivered with the main Spring.NET Framework + download. +
+
+ +
+ Spring.CodeConfig.Migration + + This sample demonstates a step-by-step detailed examination of the + process of migrating an XML-configuration based solution to use CodeConfig + exclusively and is described in detail in the Introduction section of the + reference documents. +
+
diff --git a/doc/reference/src/images/Migration_App_UML_Diagram.png b/doc/reference/src/images/Migration_App_UML_Diagram.png new file mode 100644 index 00000000..501f8830 Binary files /dev/null and b/doc/reference/src/images/Migration_App_UML_Diagram.png differ diff --git a/doc/reference/src/images/ScreenShot023.png b/doc/reference/src/images/ScreenShot023.png new file mode 100644 index 00000000..41c76525 Binary files /dev/null and b/doc/reference/src/images/ScreenShot023.png differ diff --git a/doc/reference/src/index.xml b/doc/reference/src/index.xml index 78a9b353..2ffd0ce3 100644 --- a/doc/reference/src/index.xml +++ b/doc/reference/src/index.xml @@ -1,478 +1,645 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]> - - - The Spring.NET Framework - Reference Documentation - Version 1.3.2 - Last Updated August 1, 2011 (Latest documentation) - - - Mark - Pollack - - - Rick - Evans - - - Aleksandar - Seovic - - - Bruno - Baia - - - Erich - Eichinger - - - Federico - Spinazzi - - - Rob - Harrop - - - Griffin - Caprio - - - Ruben - Bartelink - - - Choy - Rim - - - Erez - Mazor - - - Stephen - Bohlen - - - The Spring - Java Team - - - - - Copies of this document may be made for your own use and for - distribution to others, provided that you do not charge any fee for such - copies and further provided that each copy contains this Copyright - Notice, whether distributed in print or electronically. - - - - - &preface; - &overview; - &background; - &migration; - - Core Technologies + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + The Spring.NET Framework + + Reference Documentation + + Version 2.0.0 + + Last Updated January 11, 2013 (Latest + documentation) + + + + Mark + + Pollack + + + + Rick + + Evans + + + + Aleksandar + + Seovic + + + + Bruno + + Baia + + + + Erich + + Eichinger + + + + Federico + + Spinazzi + + + + Rob + + Harrop + + + + Griffin + + Caprio + + + + Ruben + + Bartelink + + + + Choy + + Rim + + + + Erez + + Mazor + + + + Stephen + + Bohlen + + + + The Spring + + Java Team + + + + + Copies of this document may be made for your own use and for + distribution to others, provided that you do not charge any fee for such + copies and further provided that each copy contains this Copyright + Notice, whether distributed in print or electronically. + + + + + + &preface; + + &overview; + + &background; + + &migration; + + + Core Technologies + + + This initial part of the reference documentation covers all of + those technologies that are absolutely integral to the Spring + Framework. + + Foremost amongst these is the Spring Framework's Inversion of + Control (IoC) container. A thorough treatment of the Spring Framework's + IoC container is closely followed by comprehensive coverage of Spring's + Aspect-Oriented Programming (AOP) technologies. The Spring Framework has + its own AOP framework, which is conceptually easy to understand, and + which successfully addresses the 80% sweet spot of AOP requirements in + enterprise programming. + + The core functionality also includes an expression language for + lightweight scripting and a ui-agnostic validation framework. + + Finally, the adoption of the test-driven-development (TDD) + approach to software development is certainly advocated by the Spring + team, and so coverage of Spring's support for integration testing is + covered (alongside best practices for unit testing). The Spring team + have found that the correct use of IoC certainly does make both unit and + integration testing easier (in that the presence of properties and + appropriate constructors on classes makes them easier to wire together + on a test without having to set up service locator registries and + suchlike)... the chapter dedicated solely to testing will hopefully + convince you of this as well. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &objects; + + &objects-misc; + + &resources; + + &threading; + + &pool; + + &misc; + + &expressions; + + &validation; + + + + &aop; + + &aop-aspect-library; + + &logging; + + &testing; + + + + Middle Tier Data Access + + + This part of the reference documentation is concerned with othe + middle tier, and specifically the data access responsibilities of said + tier. + + Spring's comprehensive transaction management support is covered + in some detail, followed by thorough coverage of the various middle tier + data access frameworks and technologies that the Spring Framework + integrates with. + + + + + + + + + + + + + + + + + + + + + + + + + &transaction; + + &dao; + + &dbprovider; + + &ado; + + &orm; + + + + The Web + + + This part of the reference documentation covers the Spring + Framework's support for the presentation tier, specifically web-based + presentation tiers. + + + + + + + + + + + + + + + + + + + + + &web; + + &ajax; + + &web-mvc; + + &web-mvc3; + + + + Services + + + This part of the reference documentation covers the Spring + Framework's integration with .NET distributed technologies such as .NET + Remoting, Enterprise Services, Web Services. Integration with WCF + Services is forthcoming. Please refer to the introduction chapter for + more details. + + + + + + + + + + + + + + + + + + + + + + + + + &psa-intro; + + &remoting; + + &services; + + &webservices; + + &wcf; + + + + Integration + + + This part of the reference documentation covers the Spring + Framework's integration with a number of related enterprise .NET + technologies. + + + + + + + + + + + + + + + + + + + + + + + + + &messaging; + + &messaging-ems; + + &msmq; + + &scheduling; + + &templating; + + + + Code-Based Configuration - - This initial part of the reference documentation covers - all of those technologies that are absolutely integral - to the Spring Framework. - - - Foremost amongst these is the Spring Framework's - Inversion of Control (IoC) container. A thorough treatment - of the Spring Framework's IoC container is closely followed - by comprehensive coverage of Spring's Aspect-Oriented - Programming (AOP) technologies. The Spring Framework has - its own AOP framework, which is conceptually easy to understand, - and which successfully addresses the 80% sweet spot of AOP - requirements in enterprise programming. - - - The core functionality also includes an expression language - for lightweight scripting and a ui-agnostic validation framework. - - - Finally, the adoption of the test-driven-development (TDD) - approach to software development is certainly advocated by - the Spring team, and so coverage of Spring's support for - integration testing is covered (alongside best practices for - unit testing). The Spring team have found that the correct - use of IoC certainly does make both unit and integration - testing easier (in that the presence of properties and - appropriate constructors on classes makes them - easier to wire together on a test without having to set up - service locator registries and suchlike)... the chapter - dedicated solely to testing will hopefully convince you of - this as well. - + In this reference document, we’ll explore the newest addition to + the configuration story for the Spring.NET Dependency Injection + container: code-based configuration, or simply CodeConfig, intended to + begin to address many of the shortcomings of the XML-based configuration + approach. + + At the core of Spring.NET is a powerful and flexible dependency + injection container, offering object assembly and construction services + atop which the remainder of the Spring.NET Framework is based. + Historically, the primary manner of configuring this dependency + injection container has been XML configuration files. Object + definitions, essentially recipes to be used by the container when + constructing objects of various types, are expressed in XML and then + parsed and interpreted by the container as it is initialized at + run-time. + + While there are several positive aspects to expressing + configuration metadata in XML files, there are also many problems with + this approach including the verbosity of XML and its heavy dependence on + string-literals which are both prone to typing errors and unusually + resistant to most modern refactoring tools in use today. The CodeConfig + approach removes these problems by providing a type safe, code-based, + approach to dependency injection. It keeps the configuration metadatda + external to your class so your class can be a POCO, free of any DI + related annotations. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - &objects; - &objects-misc; - &resources; - &threading; - &pool; - &misc; - &expressions; - &validation; - - &aop; - &aop-aspect-library; - &logging; - &testing; - - - Middle Tier Data Access - - - This part of the reference documentation is concerned - with othe middle tier, and specifically the data access - responsibilities of said tier. - - - Spring's comprehensive transaction management support is - covered in some detail, followed by thorough coverage of - the various middle tier data access frameworks and - technologies that the Spring Framework integrates with. - - - - - - - - - - - - - - - - - - - - &transaction; - &dao; - &dbprovider; - &ado; - &orm; - - - The Web - - - This part of the reference documentation covers the - Spring Framework's support for the presentation tier, - specifically web-based presentation tiers. - - - - - - - - - - - - - - - - - &web; - &ajax; - &web-mvc; - &web-mvc3; - - - Services - - - This part of the reference documentation covers - the Spring Framework's integration with .NET distributed - technologies such as .NET Remoting, Enterprise Services, - Web Services. Integration with WCF Services is forthcoming. - Please refer to the introduction chapter for more details. - - - - - - - - - - - - - - - - - - - - &psa-intro; - &remoting; - &services; - &webservices; - &wcf; - - - Integration - - - This part of the reference documentation covers - the Spring Framework's integration with a number of - related enterprise .NET technologies. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - &messaging; - &messaging-ems; - &msmq; - &scheduling; - &templating; - - - VS.NET Integration - - - This part of the reference documentation covers - the Spring Framework's integration with VS.NET - - - - - - - - &vsnet; - - - Quickstart applications - - - This part of the reference documentation covers - the quickstart applications included with - Spring that demonstrate features in a code centric - manner. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - &quickstarts; - &aop-quickstart; - &remoting-quickstart; - &web-quickstart; - &springair; - &data-quickstart; - &tx-quickstart; - &nh-quickstart; - &quartz-quickstart; - &nms-quickstart; - &ems-quickstart; - &msmq-quickstart; - &wcf-quickstart; - - - Spring.NET for Java developers - - - This part of the reference documentation - is for Java developers who would like a quick - orientation to what is different between - the Java and .NET versions of the framework. - - - - - - - - &javadevelopers; - - - - - Appendices - &classic-spring; - &xsd-configuration; - &xml-custom; - &xsd; - - - + + + &codeconfig-migration-example; + &codeconfig-context; + &codeconfig-attribute-reference; + &codeconfig-sample-apps; + + + + VS.NET Integration + + + This part of the reference documentation covers the Spring + Framework's integration with VS.NET + + + + + + + + + &vsnet; + + + + Quickstart applications + + + This part of the reference documentation covers the quickstart + applications included with Spring that demonstrate features in a code + centric manner. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &quickstarts; + + &aop-quickstart; + + &remoting-quickstart; + + &web-quickstart; + + &springair; + + &data-quickstart; + + &tx-quickstart; + + &nh-quickstart; + + &quartz-quickstart; + + &nms-quickstart; + + &ems-quickstart; + + &msmq-quickstart; + + &wcf-quickstart; + + + + Spring.NET for Java developers + + + This part of the reference documentation is for Java developers + who would like a quick orientation to what is different between the Java + and .NET versions of the framework. + + + + + + + + + &javadevelopers; + + + + + + Appendices + + &classic-spring; + + &xsd-configuration; + + &xml-custom; + + &xsd; + + diff --git a/doc/reference/src/objects.xml b/doc/reference/src/objects.xml index c135e961..e258ceef 100644 --- a/doc/reference/src/objects.xml +++ b/doc/reference/src/objects.xml @@ -6392,17 +6392,8 @@ ctx.Refresh(); RootObjectDefinition, etc. Note a web version of this application class has not yet been implemented. - An example, with a yet to be created DLL - scanner, that would get configuration metadata from the .dll named - MyAssembly.dll located in the runtime path, would look something like - this - - GenericApplicationContext ctx = new GenericApplicationContext(); -ObjectDefinitionScanner scanner = new ObjectDefinitionScanner(ctx); -scanner.scan("MyAssembly.dll"); -ctx.refresh(); - - Refer to the Spring API documentation for more information. + For a an even richer XML-free configuration experience, refer + instead to the Spring CodeConfig approach.