From 805d384d0d7e1eac02cbca506227f55416dbae8f Mon Sep 17 00:00:00 2001 From: Steve Bohlen Date: Mon, 7 Jan 2013 19:05:17 -0500 Subject: [PATCH] SPRNET-1536 merge SPRNET-CODECONFIG refdocs --- .../src/codeconfig-attribute-reference.xml | 574 +++++++++ doc/reference/src/codeconfig-context.xml | 536 ++++++++ .../src/codeconfig-migration-example.xml | 700 +++++++++++ doc/reference/src/codeconfig-sample-apps.xml | 266 ++++ .../src/images/Migration_App_UML_Diagram.png | Bin 0 -> 28274 bytes doc/reference/src/images/ScreenShot023.png | Bin 0 -> 29993 bytes doc/reference/src/index.xml | 1113 ++++++++++------- doc/reference/src/objects.xml | 13 +- 8 files changed, 2718 insertions(+), 484 deletions(-) create mode 100644 doc/reference/src/codeconfig-attribute-reference.xml create mode 100644 doc/reference/src/codeconfig-context.xml create mode 100644 doc/reference/src/codeconfig-migration-example.xml create mode 100644 doc/reference/src/codeconfig-sample-apps.xml create mode 100644 doc/reference/src/images/Migration_App_UML_Diagram.png create mode 100644 doc/reference/src/images/ScreenShot023.png 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 0000000000000000000000000000000000000000..501f88307833013e27b896935d7407cb48fd5a5d GIT binary patch literal 28274 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⋘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 qzVua5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]> - - - 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.