From 22724a7122727e942c5ea018ed503e09ced54f29 Mon Sep 17 00:00:00 2001 From: markpollack Date: Tue, 14 Oct 2008 05:26:44 +0000 Subject: [PATCH] update product version numbers and dates in readme.txt etc update docs update to ActiveMQ NMS svn revision 704303 Add missing code xml docs. --- Spring.build | 4 +- changelog.txt | 56 + doc/reference/src/aop-aspect-library.xml | 280 ++-- doc/reference/src/index.xml | 4 +- doc/reference/src/messaging.xml | 385 ++--- doc/reference/src/objects.xml | 1233 +++++++++-------- doc/reference/src/orm.xml | 409 +++--- doc/reference/src/wcf.xml | 176 +-- doc/reference/src/web.xml | 472 ++++--- doc/reference/src/webservices.xml | 72 +- readme.txt | 2 +- src/Spring/CommonAssemblyInfo.cs | 2 +- src/Spring/Spring.Aop/Spring.Aop.2005.csproj | 1 + .../Spring.Core/Spring.Core.2005.csproj | 1 + .../Nms/Connections/CachedSession.cs | 10 + .../Connections/SingleConnectionFactory.cs | 16 +- .../Nms/Support/Converter/ITypeMapper.cs | 16 +- .../Nms/Support/Converter/TypeMapper.cs | 60 +- .../Support/Converter/XmlMessageConverter.cs | 53 +- .../Spring.Messaging.Nms.2005.csproj | 3 + .../Spring.Messaging.2005.csproj | 1 - 21 files changed, 1865 insertions(+), 1391 deletions(-) diff --git a/Spring.build b/Spring.build index 710f4781..5e279850 100644 --- a/Spring.build +++ b/Spring.build @@ -14,10 +14,10 @@ - + - + diff --git a/changelog.txt b/changelog.txt index c0949f50..cc221f8f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,61 @@ SPRING.NET FRAMEWORK CHANGELOG ============================== http://www.springframework.net +Release Version 1.2.0 RC1, October 15, 2008 + + +Bug +[SPRNET-899] - HttpContext.CurrenHandler returns Spring's internal PageHandler instead of real Page +[SPRNET-923] - Spring.Services generated proxies should not use explicitly ContextRegistry.GetContext or WebApplicationContext.Current direclty +[SPRNET-967] - SaoFactoryObject should cast TransparentProxies to the interface it implements before to return +[SPRNET-1008] - Add check for [Serializable] in SimpleMessageConverter +[SPRNET-1017] - Apache.NMS.ActiveMQ.ConnectionClosedException when using CachingConnectionFactory +[SPRNET-1020] - Consumer caching was not taking place for queues. +[SPRNET-1023] - Problems performing DI with Telerik RAD controls +[SPRNET-1027] - Spring Page Handler Factory does not respect EnableSessionState="ReadOnly", page setting cached until app pool reload +[SPRNET-1028] - DefaultListableObjectFactory.IsAutowireCandidate(string , DependencyDescriptor) does not search parent container +[SPRNET-1032] - elements to not append values for same key value +[SPRNET-1047] - ObjectPostProcessors order isn't respected when mixing and ObjectFactory.AddObjectPostProcessor() registrations + +Improvement +[SPRNET-547] - Add Unsubscribe functionality to IEventRegistry +[SPRNET-567] - Allow parameters to be passed to Spring.Web.UI.Page.SetResult() +[SPRNET-784] - WebServiceProxyFactory support for SoapHeaderAttribute with Direction=SoapHeaderDirection.In +[SPRNET-795] - Change TransactionStatus Rollback setter property to Rollback() method so the contract of setting it to true is more explicit +[SPRNET-840] - Reduce PageHandlerFactory complexity +[SPRNET-958] - Result mapping doesn't support expressions for TargetPage +[SPRNET-960] - Allow for selection of logging level when using exception handling advice for logging +[SPRNET-995] - IsValid state of AbstractBinding should not be stored in LogicalThreadContext +[SPRNET-1016] - Apply local transaction to DataSet operations in AdoTemplate. +[SPRNET-1019] - Messaging namespace parser should support use of PropertyPlaceholderConfigurer +[SPRNET-1021] - Avoid antlr exception thrown for internal flow control when selecting handler method in MessageListenerAdapter +[SPRNET-1024] - Add AutoStartup as an attribute of the element +[SPRNET-1025] - Make GetObject virtual in MethodInvokingJobDetailFactoryObject and provide protected access to JobDetail object. +[SPRNET-1038] - Eliminate storing binding state to TLS in Spring.DataBinding.AbstractBinding +[SPRNET-1056] - Provide easier configuration of exception handlers in ExceptionTranslationAdvice. + +New Feature +[SPRNET-711] - Add generic DI support for IHttpHandlers +[SPRNET-713] - Add support for custom .ashx IHttpHandler implementations +[SPRNET-815] - Add Sql Server Compact Edition 3.5 database provider +[SPRNET-883] - Add support for translation of exceptions using PersistenceExceptionTranslationInterceptor. +[SPRNET-936] - Add message converter to/from XML (NMS) +[SPRNET-1039] - Add support for Sybase ADO.NET 2.0 provider +[SPRNET-1040] - Support encrypting url parameters when using Page.SetResult() +[SPRNET-1046] - Move hardcoded, Spring.Web specific ISharedStateAware handling to generic SharedStateAwareObjectPostProcessor +[SPRNET-1055] - Provide ability to easily register to MessageQueueFactoryObject definitions with the container at runtime +[SPRNET-1057] - Add new 'execute' action for ExceptionTranslationAdvice +[SPRNET-1058] - Provide WCF Service export akin to those for Remoting and .asmx WebServices + +Refactoring +[SPRNET-1052] - Extract "SetResult" related code into a reusable ResultNavigator component + +Task +[SPRNET-1045] - Colorize code listings (XML/C#) in reference documentation +[SPRNET-1048] - Drop IProcess support from Spring.Web +[SPRNET-1050] - Provide sample configuration for using MultiDelegatingDbProvider + + Release 1.2.0 M1, August 15, 2008 @@ -40,6 +95,7 @@ Improvement [SPRNET-999] - Add DefaultDbProvider property to MultiDelegatingDbProvider. New Feature +[SPRNET-753] - Add ILifecycle interface [SPRNET-896] - Allow registering custom ICollectionProcessors in SpEL MethodNode [SPRNET-922] - NHibernate 2.0 RC1 Support [SPRNET-953] - Allow for circular dependencies of web-scoped singletons diff --git a/doc/reference/src/aop-aspect-library.xml b/doc/reference/src/aop-aspect-library.xml index a7d9a9b2..449dc45f 100644 --- a/doc/reference/src/aop-aspect-library.xml +++ b/doc/reference/src/aop-aspect-library.xml @@ -16,7 +16,13 @@ * limitations under the License. */ --> - + Aspect Library @@ -54,8 +60,8 @@ implement is Spring.Caching.ICache located in Spring.Core. Two implementations are provided, Spring.Caching.AspNetCache located in - Spring.Web which stores cache entries within an - ASP.NET cache and a simple implementation, + Spring.Web which stores cache entries within an ASP.NET + cache and a simple implementation, Spring.Caching.NonExpiringCache that stores cache entries in memory and never expires these entries. Custom implementations based on 3rd party implementations, such as Oracle Coherence, or @@ -81,8 +87,8 @@ - CacheResultItems - used when returning a collection as - a return value + CacheResultItems - used when returning a + collection as a return value @@ -97,9 +103,8 @@ Each CacheResult, - CacheResultItems, and - CacheParameter attributes define the following - properties. + CacheResultItems, and CacheParameter + attributes define the following properties. @@ -125,14 +130,14 @@ - The InvalidateCache attribute has properties - for the CacheName, the Key as well as the Condition, with the same - meanings as listed previously. + The InvalidateCache attribute has properties for + the CacheName, the Key as well as the Condition, with the same meanings as + listed previously. - Each ICache implementation will have - properties that are specific to a caching technology. In the case of - AspNetCache, the two important properties to - configure are: + Each ICache implementation will have properties + that are specific to a caching technology. In the case of + AspNetCache, the two important properties to configure + are: @@ -202,32 +207,32 @@ public Airport GetAirport(long id) The configuration to enable the caching aspect is shown below - + <object" id="CacheAspect" type="Spring.Aspects.Cache.CacheAspect, Spring.Aop"/> - - - - - +<object id="AspNetCache" type="Spring.Caching.AspNetCache, Spring.Web"> + <property name="SlidingExpiration" value="true"/> + <property name="Priority" value="Low"/> + <property name="TimeToLive" value="00:02:00"/> +</object> - - - - - *Dao - - - - - CacheAspect - - -]]> +<!-- Apply aspects to DAOs --> +<object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop"> + <property name="ObjectNames"> + <list> + <value>*Dao</value> + </list> + </property> + <property name="InterceptorNames"> + <list> + <value>CacheAspect</value> + </list> + </property> +</object> - in this example an ObjectNameAutoProxyCreator - was used to apply the cache aspect to objects that have Dao in their name. - The AspNetCache setting for TimeToLive will override the TimeToLive value - set at the method level via the attribute. + in this example an ObjectNameAutoProxyCreator was + used to apply the cache aspect to objects that have Dao in their name. The + AspNetCache setting for TimeToLive will override the TimeToLive value set + at the method level via the attribute. @@ -251,6 +256,11 @@ public Airport GetAirport(long id) swallow - the exception is ignored. + + + execute - Execute an abritrary Spring Expression Language (SpEL + expression) + The applicability of general exception handling advice depends @@ -268,13 +278,13 @@ public Airport GetAirport(long id) could be referred to as a Domain Specific Language (DSL). Here is a simple example, which should hopefully be self explanatory. - - - - on exception name ArithmeticException wrap System.InvalidOperationException - - -]]>What this is instructing the advice to do is + <object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop"> + <property name="exceptionHandlers"> + <list> + <value>on exception name ArithmeticException wrap System.InvalidOperationException</value> + </list> + </property> +</object>What this is instructing the advice to do is the following bit of code when an ArithmeticException is thrown, throw new System.InvalidOperationException("Wrapped ArithmeticException", e), where e is the original ArithmeticException. The default message, "Wrapped @@ -356,19 +366,19 @@ on exception name ArithmeticException return 12 action, i.e. log(Debug,"LoggerName"). Multiple exception handling statements can be specified within the - list shown above. The processing flow is on exception, the name of - the exception listed in the statement is compared to the thrown exception - to see if there is a match. A comma separated list of exceptions can be - used to group together the same action taken for different exception - names. If the action to take is logging, then the logging action is - performed and the search for other matching exception names continues. For - all other actions, namely translate, wrap, replace, swallow, return, once - an exception handler is matched, those in the chain are no longer - evaluated. Note, do not confuse this handler chain with the general advice - AOP advice chain. For translate, wrap, and replace actions a SpEL - expression is created and used to instantiate a new exception (in addition - to any other processing that may occur when evaluating the expression) - which is then thrown. + list shown above. The processing flow is on exception, the name of the + exception listed in the statement is compared to the thrown exception to + see if there is a match. A comma separated list of exceptions can be used + to group together the same action taken for different exception names. If + the action to take is logging, then the logging action is performed and + the search for other matching exception names continues. For all other + actions, namely translate, wrap, replace, swallow, return, once an + exception handler is matched, those in the chain are no longer evaluated. + Note, do not confuse this handler chain with the general advice AOP advice + chain. For translate, wrap, and replace actions a SpEL expression is + created and used to instantiate a new exception (in addition to any other + processing that may occur when evaluating the expression) which is then + thrown. The exception handling DSL also supports the ability to provide a SpEL boolean expression to determine if the advice will apply instead of @@ -393,23 +403,55 @@ on exception name ArithmeticException return 12 likely be better off creating your own custom aspect class instead of a scripting approach. - You can also configure ExceptionHandlerAdvice to use an instance of - IExceptionHandler, for example to access more sophisticated logging - functionality than is available with the current log action in the DSL, - for example setting the logging level and pass the exception into the - logging subsystem + You can also configure the each of the Handlers individually based + on the action keyword. For example, to configure the logging properties on + the LogExceptionHandler. - - - - - - - - - - -]]> + <object name="logExceptionHandler" type="Spring.Aspects.Exceptions.LogExceptionHandler, Spring.Aop"> + <property name="LogName" value="Cms.Session.ExceptionHandler" /> + <property name="LogLevel" value="Debug"/> + <property name="LogMessageOnly" value="true"/> +</object> + +<object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop"> + <property name="ExceptionHandlerDictionary"> + <dictionary> + <entry key="log" ref="logExceptionHandler"/> + </dictionary> + </property> + + <property name="ExceptionHandlers"> + <list> + <value>on exception name ArithmeticException,ArgumentException log 'My Message, Method Name ' + #method.Name</value> + </list> + </property> +</object> + + + You can also configure ExceptionHandlerAdvice to + use an instance of IExceptionHandler by specifing it as + an entry in the ExceptionHandlers list. This gives you complete control + over all properties of the handler but you must set + ConstraintExpressionText and ActionExpressionText which are normally + parsed for you from the string. To use the case of configuring the + LogExceptionHandler, this approach also lets you specify advanced logging + functionality, but at a cost of some additional complexity. For example + setting the logging level and pass the exception into the logging + subsystem + + <object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop"> + <property name="exceptionHandlers"> + <list> + <object type="Spring.Aspects.Exceptions.LogExceptionHandler"> + <property name="LogName" value="Cms.Session.ExceptionHandler" /> + <property name="ConstraintExpressionText" value="#e is T(System.Threading.ThreadAbortException)" /> + <property name="ActionExpressionText" value="#log.Fatal('Request Timeout occured', #e)" /> + </object> + </list> + </property> +</object> + + The configuration of the logger name, level, and weather or not to pass the thrown exception as the second argument to the log method will be @@ -455,6 +497,10 @@ on exception name ArithmeticException return 12 swallow + + + execute + The form of the expression depends on the action. For logging, the @@ -476,9 +522,10 @@ on exception name ArithmeticException return 12 The logging advice lets you log the information on method entry, exit and thrown exception (if any). The implementation is based on the - logging library, Common.Logging, that provides - portability across different logging libraries. There are a number of - configuration options available, listed below + logging library, Common.Logging, that + provides portability across different logging libraries. There are a + number of configuration options available, listed below @@ -510,19 +557,19 @@ on exception name ArithmeticException return 12 XML fragment. Alternatively, you can use the class SimpleLoggingAdvice programatically. - - - - - + <object name="loggingAdvice" type="Spring.Aspects.Logging.SimpleLoggingAdvice, Spring.Aop"> + <property name="logUniqueIdentifier" value="true"/> + <property name="logExecutionTime" value="true"/> + <property name="logMethodArguments" value="true"/> + <property name="LogReturnValue" value="true"/> - - + <property name="Separator" value=";"/> + <property name="LogLevel" value="Info"/> - - -]]> + <property name="HideProxyTypeNames" value="true"/> + <property name="UseDynamicLogger" value="true"/> +</object> The default values for LogUniqueIdentifier, LogExecutionTime, LogMethodArguments and LogReturnValue are false. The default separator @@ -568,8 +615,8 @@ on exception name ArithmeticException return 12 use a GUID. You can alter this behavior by overriding the method string CreateUniqueIdentifier(). The SimpleLoggingAdvice class inherits from - AbstractLoggingAdvice, which has the abstract - method object InvokeUnderLog(IMethodInvocation invocation, ILog + AbstractLoggingAdvice, which has the abstract method + object InvokeUnderLog(IMethodInvocation invocation, ILog log) and you can also override the method ILog GetLoggerForInvocation(IMethodInvocation invocation) to customize the logger instance used for logging. Refer to the SDK @@ -675,9 +722,9 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)

RetryAdvice
class programatically.
- - -]]> + <object name="exceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop"> + <property name="retryExpression" value="on exception name ArithmeticException retry 3x delay 1s"/> +</object> Language Reference @@ -721,13 +768,13 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)

To address some of the common needs for validation on the server side, Spring provides parameter validation advice so that applies Spring's validation rules to the method parameters. The class - ParameterValidationAdvice is used in conjunction - with the Validated attribute to specify which - validation rules are applied to method parameters. For example, to apply - parameter validation to the method SuggestFlights in the BookingAgent - class used in the SpringAir sample - application, you would apply the Validated - attribute to the method parameters as shown below. + ParameterValidationAdvice is used in conjunction with + the Validated attribute to specify which validation + rules are applied to method parameters. For example, to apply parameter + validation to the method SuggestFlights in the BookingAgent class used in + the SpringAir sample application, you + would apply the Validated attribute to the method + parameters as shown below. public FlightSuggestions SuggestFlights( [Validated("tripValidator")] Trip trip) { @@ -736,30 +783,29 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)

The Validated attribute takes a string name that specifies the name of the validation rule, i.e. the name of the IValidator - object in the Spring application context. The - Validated attribute is located in the namespace - Spring.Validation of the Spring.Core - assembly. + object in the Spring application context. The Validated + attribute is located in the namespace Spring.Validation + of the Spring.Core assembly. The configuration of the advice is to simply define the an instance of the ParameterValidationAdvice class and apply the advice, for example based on object names using an ObjectNameAutoProxyCreator, as shown below, - + <object id="validationAdvice" type="Spring.Aspects.Validation.ParameterValidationAdvice, Spring.Aop"/> - - - - bookingAgent - - - - - validationAdvice - - -]]> +<object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop"> + <property name="ObjectNames"> + <list> + <value>bookingAgent</value> + </list> + </property> + <property name="InterceptorNames"> + <list> + <value>validationAdvice</value> + </list> + </property> +</object> When the advised method is invoked first the validation of each method parameter is performed. If all validation succeeds, then the method @@ -768,4 +814,4 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)

ValidationErrors. See the SDK documentation for details.
- \ No newline at end of file + diff --git a/doc/reference/src/index.xml b/doc/reference/src/index.xml index 1312c3c1..7fdabcb7 100644 --- a/doc/reference/src/index.xml +++ b/doc/reference/src/index.xml @@ -60,8 +60,8 @@ The Spring.NET Framework Reference Documentation - Version 1.2.0 M1 - Last Updated August 15,2008 + Version 1.2.0 RC1 + Last Updated October 15,2008 Mark diff --git a/doc/reference/src/messaging.xml b/doc/reference/src/messaging.xml index 23a8558b..3fd13468 100644 --- a/doc/reference/src/messaging.xml +++ b/doc/reference/src/messaging.xml @@ -16,8 +16,13 @@ * limitations under the License. */ --> - - Message Oriented Middleware + + Message Oriented Middleware - Apache ActiveMQ
Introduction @@ -50,25 +55,27 @@ - Apache NMS in namespace Spring.Messaging.Nms. - 'Nms' is sometimes used as the class prefix + Apache ActiveMQ (NMS) in namespace + Spring.Messaging.Nms. 'Nms' is sometimes used as + the class prefix TIBCO EMS in namespace Spring.Messaging.Ems. - 'Ems' is sometimes used as the class prefix + 'Ems' is sometimes used as the class prefix (to becommerically + available ) SonicMQ in namespace Spring.Messaging.Sonic, - 'Jms' is sometimes used as the class prefix. (available 1.2 - RC1) + 'Jms' is sometimes used as the class prefix. (to be commercially + available) Websphere MQ in namespace Spring.Messaging.Xms, 'Xms' is sometimes used as - the class prefix (available 1.2 RC1) + the class prefix (to be commerically available) @@ -78,11 +85,11 @@ NmsTemplate, EmsTemplate (etc.) is used. Asynchronous message consumption is performed though a multi-threaded message listener container, - SimpleMessageListenerContainer. This message - listener container is used to create Message-Driven PONOs (MDPs) which - refer to a messaging callback class that consists of just 'plain .NET - object's and is devoid of any specific messaging types or other artifacts. - The IMessageConverter interface is used by both the + SimpleMessageListenerContainer. This message listener + container is used to create Message-Driven PONOs (MDPs) which refer to a + messaging callback class that consists of just 'plain .NET object's and is + devoid of any specific messaging types or other artifacts. The + IMessageConverter interface is used by both the template class and the message listener container to convert between provider message types and PONOs. @@ -211,7 +218,12 @@ even with the option of using WCF, many people prefer to sit 'closer to the metal' when using messaging middleware, to access specific features and functionality not available in WCF, or simply because they are more - comfortable with that programming model. + comfortable with that programming model. + + A WCF binding for Apache NMS is being developed as a separate + project under the Spring + Extensions umbrella project. Stay tuned for details.
@@ -222,16 +234,16 @@ Messaging Template overview Code that uses the messaging template classes - (NmsTemplate, EmsTemplate, - etc) only needs to implement callback interfaces giving them a clearly + (NmsTemplate, EmsTemplate, etc) + only needs to implement callback interfaces giving them a clearly defined contract. The IMessageCreator callback interface creates a message given a Session provided by the calling code in NmsTemplate. In order to allow for more complex usage of the provider messaging API, the callback - ISessionCallback provides the user with the - provider specific messaging Session and the callback - IProducerCallback exposes a provider specific - Session and MessageProducer pair. + ISessionCallback provides the user with the provider + specific messaging Session and the callback + IProducerCallback exposes a provider specific Session + and MessageProducer pair. Provider messaging APIs typically expose two types of send methods, one that takes delivery mode, priority, and time-to-live as @@ -250,8 +262,8 @@ NmsTemplate and then safely inject this shared reference into multiple collaborators. To be clear, the NmsTemplate is stateful, in that it maintains a - reference to a ConnectionFactory, but this - state is not conversational state. + reference to a ConnectionFactory, but this state is + not conversational state. @@ -321,11 +333,10 @@ session and also take into account the unique properties of the producers and consumers when caching. - MessageProducers are cached based on - their destination. MessageConsumers are cached - based on a key composed of the destination, selector, noLocal delivery - flag, and the durable subscription name (if creating durable - consumers). + MessageProducers are cached based on their + destination. MessageConsumers are cached based on a + key composed of the destination, selector, noLocal delivery flag, and + the durable subscription name (if creating durable consumers). @@ -349,13 +360,12 @@ unique to the messaging provider. Examples of such advanced destination management would be the creation of dynamic destinations or support for a hierarchical namespace of destinations. The - NmsTemplate delegates the resolution of a - destination name to a destination object by delegating to an - implementation of the interface - IDestinationResolver. + NmsTemplate delegates the resolution of a destination + name to a destination object by delegating to an implementation of the + interface IDestinationResolver. DynamicDestinationResolver is the default - implementation used by NmsTemplate and - accommodates resolving dynamic destinations. + implementation used by NmsTemplate and accommodates + resolving dynamic destinations. Quite often the destinations used in a messaging application are only known at runtime and therefore cannot be administratively created @@ -412,17 +422,15 @@ possibly responding to it), and delegates boilerplate messaging infrastructure concerns to the framework. - A subclass of - AbstractMessageListenerContainer is used to - receive messages from JMS and drive the Message-Driven PONOs (MDPs) that - are injected into it. There are one subclasses of - AbstractMessageListenerContainer packaged with - Spring - SimpleMessageListenerContainer. - Additional subclasses, in particular to participate in distributed - transactions (if the provider supports it), will be provided in future - releases. SimpleMessageListenerContainer creates a fixed number of JMS - sessions at startup and uses them throughout the lifespan of the - container. + A subclass of AbstractMessageListenerContainer + is used to receive messages from JMS and drive the Message-Driven PONOs + (MDPs) that are injected into it. There are one subclasses of + AbstractMessageListenerContainer packaged with Spring + - SimpleMessageListenerContainer. Additional + subclasses, in particular to participate in distributed transactions (if + the provider supports it), will be provided in future releases. + SimpleMessageListenerContainer creates a fixed number of JMS sessions at + startup and uses them throughout the lifespan of the container.
@@ -471,14 +479,14 @@ the JMS Destination object is specified directly. The second case specifies the destination using a string that is then resolved to a messaging Destination object using the - IDestinationResolver associated with the template. - The last method sends the message to the destination specified by - NmsTemplate''s - DefaultDestination property. + IDestinationResolver associated with the template. The + last method sends the message to the destination specified by + NmsTemplate''s DefaultDestination + property. All methods take as an argument an instance of - IMessageCreator which defines the API contract for - you to create the JMS message. The interface is show below + IMessageCreator which defines the API contract for you + to create the JMS message. The interface is show below public interface IMessageCreator { IMessage CreateMessage(ISession session); @@ -554,23 +562,21 @@ Using MessageConverters In order to facilitate the sending of domain model objects, the - NmsTemplate has various send methods that take a - .NET object as an argument for a message's data content. The overloaded + NmsTemplate has various send methods that take a .NET + object as an argument for a message's data content. The overloaded methods ConvertAndSend and - ReceiveAndConvert in - NmsTemplate delegate the conversion process to an - instance of the IMessageConverter - interface. This interface defines a simple contract to convert between - .NET objects and JMS messages. The default implementation - SimpleMessageConverter supports conversion - between String and TextMessage, byte[] and BytesMesssage, and - System.Collections.IDictionary and MapMessage. By using the converter, - you and your application code can focus on the business object that is - being sent or received via messaging and not be concerned with the - details of how it is represented as a JMS message. - - The sample applications contains a XmlMessageConverter that - converts objects to an XML string and vice-versa for sending via a + ReceiveAndConvert in NmsTemplate + delegate the conversion process to an instance of the + IMessageConverter interface. This interface defines a + simple contract to convert between .NET objects and JMS messages. The + default implementation SimpleMessageConverter + supports conversion between String and TextMessage, byte[] and + BytesMesssage, and System.Collections.IDictionary and MapMessage. By + using the converter, you and your application code can focus on the + business object that is being sent or received via messaging and not be + concerned with the details of how it is represented as a JMS message. + There is also an XmlMessageConverter that converts + objects to an XML string and vice-versa for sending via a TextMessage. The family of ConvertAndSend messages are @@ -619,13 +625,13 @@ template.ConvertAndSend("APP.STOCK.MARKETDATA", marketData); }To accommodate the setting of message's properties, headers, and body that can not be generally encapsulated inside a converter - class, the IMessageConverterPostProcessor - interface gives you access to the message after it has been converted - but before it is sent. The example below demonstrates how to modify a - message header and a property after a Hashtable is converted to a - message using the IMessagePostProcessor. The methods - ConvertAndSendUsingDelegate allow for the use of - a delegate to perform message post processing. This family of methods is + class, the IMessageConverterPostProcessor interface + gives you access to the message after it has been converted but before + it is sent. The example below demonstrates how to modify a message + header and a property after a Hashtable is converted to a message using + the IMessagePostProcessor. The methods + ConvertAndSendUsingDelegate allow for the use of a + delegate to perform message post processing. This family of methods is listed below @@ -734,8 +740,8 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ available. This can be a dangerous operation since the calling thread can potentially be blocked indefinitely. The property ReceiveTimeout on - NmsTemplate specifies how long the receiver - should wait before giving up waiting for a message. + NmsTemplate specifies how long the receiver should + wait before giving up waiting for a message. The Receive methods are listed below @@ -774,8 +780,8 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ The Receive method without arguments will use the DefaultDestination. The ReceiveSelected methods apply the provided - message selector string to the MessageConsumer - that is created. + message selector string to the MessageConsumer that + is created. The ReceiveAndConvert methods apply the template's message converter when receiving a message. The message @@ -832,10 +838,9 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ Other vendors may provide a delegate based version of this callback or even both a delegate and interface options. Apache ActiveMQ supports only the use of delegates for message reception callbacks. As a - programming convenience in - Spring.Messaging.Nms.Core is an interface - IMessageListener that can be used with - NMS. + programming convenience in Spring.Messaging.Nms.Core + is an interface IMessageListener that can be used + with NMS. Below is a simple implementation of the IMessageListener interface that processing a message. @@ -879,11 +884,10 @@ namespace MyApp specifies various messaging configuration parameters, such as the ConnectionFactory, and the number of concurrent consumers to create. There is an abstract base class for message listener containers, - AbstractMessageListenerContainer, and one - concrete implementation, - SimpleMessageListenerContainer. - SimpleMessageListenerContainer creates a fixed - number of JMS Sessions/MessageConsumer pairs as set by the property + AbstractMessageListenerContainer, and one concrete + implementation, SimpleMessageListenerContainer. + SimpleMessageListenerContainer creates a fixed number + of JMS Sessions/MessageConsumer pairs as set by the property ConcurrentConsumers. Here is a sample configuration @@ -933,13 +937,12 @@ namespace MyApp to an implementation of IExceptionHandler and registered with the container via the property ExceptionListener. The registered - IExceptionHandler will be invoked if the - exception is of the type NMSException (or the - equivalent root exception type for other providers). The - SimpleMessageListenerContainer will logs the exception at error level - and not propagate the exception to the provider. All handling of - acknowledgement and/or transactions is done by the listener container. - You can override the method + IExceptionHandler will be invoked if the exception is + of the type NMSException (or the equivalent root + exception type for other providers). The SimpleMessageListenerContainer + will logs the exception at error level and not propagate the exception + to the provider. All handling of acknowledgement and/or transactions is + done by the listener container. You can override the method HandleListenerException to change this behavior. @@ -951,12 +954,11 @@ namespace MyApp
The ISessionAwareMessageListener interface - The ISessionAwareMessageListener interface - is a Spring-specific interface that provides a similar contract to the - messaging provider's IMessageListener interface - or Listener delegate/event, but also provides the message handling - method with access to the Session from which the Message was - received. + The ISessionAwareMessageListener interface is a + Spring-specific interface that provides a similar contract to the + messaging provider's IMessageListener interface or + Listener delegate/event, but also provides the message handling method + with access to the Session from which the Message was received. public interface ISessionAwareMessageListener { @@ -976,9 +978,8 @@ namespace MyApp of course some constraints). Consider the following interface definition. Notice that although - the interface extends neither the - IMessageListener nor - ISessionAwareMessageListener interfaces, it can + the interface extends neither the IMessageListener + nor ISessionAwareMessageListener interfaces, it can still be used as a Message-Driven PONOs (MDP) via the use of the MessageListenerAdapter class. Notice also how the various message handling methods are strongly typed according to the @@ -1042,8 +1043,7 @@ namespace MyApp } The configuration of the attendant - MessageListenerAdapter would look like - this + MessageListenerAdapter would look like this <object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/> @@ -1058,12 +1058,11 @@ namespace MyApp Please note that if the above 'MessageListener' receives a Message of a type other than ITextMessage, a - ListenerExecutionFailedException will be thrown - (and subsequently handled by the container by logging the - exception). + ListenerExecutionFailedException will be thrown (and + subsequently handled by the container by logging the exception). - If your IMessageConverter implementation - will return multiple object types, overloading the handler method is + If your IMessageConverter implementation will + return multiple object types, overloading the handler method is perfectly acceptable, the most specific matching method will be used. A method with an object signature would be consider a 'catch-all' method of last resort. For example, you can have an handler interface as shown @@ -1173,72 +1172,83 @@ namespace MyApp id - A object name for the hosting listener container. - If not specified, a object name will be automatically - generated. + + A object name for the hosting listener container. If not + specified, a object name will be automatically + generated. + destination (required) - The destination name for this listener, resolved - through the IDestinationResolver - strategy. + + The destination name for this listener, resolved through + the IDestinationResolver strategy. + ref (required) - The object name of the handler - object. + + The object name of the handler object. + method - The name of the handler method to invoke. If the - ref points to a - IMessageListener or Spring - ISessionAwareMessageListener, - this attribute may be omitted. + + The name of the handler method to invoke. If the + ref points to a + IMessageListener or Spring + ISessionAwareMessageListener, this + attribute may be omitted. + response-destination - The name of the default response destination to - send response messages to. This will be applied in case of a - request message that does not carry a "NMSReplyTo" field. The - type of this destination will be determined by the - listener-container's "destination-type" attribute. Note: This - only applies to a listener method with a return value, for which - each result object will be converted into a response - message. + + The name of the default response destination to send + response messages to. This will be applied in case of a + request message that does not carry a "NMSReplyTo" field. The + type of this destination will be determined by the + listener-container's "destination-type" attribute. Note: This + only applies to a listener method with a return value, for + which each result object will be converted into a response + message. + subscription - The name of the durable subscription, if - any. + + The name of the durable subscription, if any. + selector - An optional message selector for this - listener. + + An optional message selector for this listener. + pubsub-domain - An optional boolean value. Set to true for the - publish-subscribe domain (Topics) or false (the default) for - point-to-point domain (Queues). This is useful when using the - default implementation for destination resolvers. - + + An optional boolean value. Set to true for the + publish-subscribe domain (Topics) or false (the default) for + point-to-point domain (Queues). This is useful when using the + default implementation for destination resolvers. + @@ -1264,8 +1274,8 @@ namespace MyApp The following table describes all available attributes. Consult the class-level SDK documentation of the AbstractMessageListenerContainer and its subclass - SimpleMessageListenerContainer for more detail on - the individual properties. + SimpleMessageListenerContainer for more detail on the + individual properties. Attributes of the NMS @@ -1288,86 +1298,97 @@ namespace MyApp <row> <entry>connection-factory</entry> - <entry><para>A reference to the NMS - <literal>ConnectionFactory</literal> object (the - default object name is - <literal>'ConnectionFactory'</literal>).</para></entry> + <entry> + <para>A reference to the NMS + <literal>ConnectionFactory</literal> object (the default + object name is <literal>'ConnectionFactory'</literal>).</para> + </entry> </row> <row> <entry>destination-resolver</entry> - <entry><para>A reference to the - <literal>IDestinationResolver</literal> strategy for - resolving JMS - <literal>Destinations</literal>.</para></entry> + <entry> + <para>A reference to the + <literal>IDestinationResolver</literal> strategy for resolving + JMS <literal>Destinations</literal>.</para> + </entry> </row> <row> <entry>message-converter</entry> - <entry><para>A reference to the - <literal>IMessageConverter</literal> strategy for - converting NMS Messages to listener method arguments. Default is - a <literal>SimpleMessageConverter</literal>.</para></entry> + <entry> + <para>A reference to the <literal>IMessageConverter</literal> + strategy for converting NMS Messages to listener method + arguments. Default is a + <literal>SimpleMessageConverter</literal>.</para> + </entry> </row> <row> <entry>destination-type</entry> - <entry><para>The NMS destination type for this listener: - <literal>queue</literal>, <literal>topic</literal> or - <literal>durableTopic</literal>. The default is - <literal>queue</literal>.</para></entry> + <entry> + <para>The NMS destination type for this listener: + <literal>queue</literal>, <literal>topic</literal> or + <literal>durableTopic</literal>. The default is + <literal>queue</literal>.</para> + </entry> </row> <row> <entry>client-id</entry> - <entry><para>The NMS client id for this listener container. - Needs to be specified when using durable - subscriptions.</para></entry> + <entry> + <para>The NMS client id for this listener container. Needs to + be specified when using durable subscriptions.</para> + </entry> </row> <row> <entry>acknowledge</entry> - <entry><para>The native NMS acknowledge mode: - <literal>auto</literal>, <literal>client</literal>, - <literal>dups-ok</literal> or <literal>transacted</literal>. A - value of <literal>transacted</literal> activates a locally - transacted <literal>Session</literal>. As an - alternative, specify the <literal>transaction-manager</literal> - attribute described below. Default is - <literal>auto</literal>.</para></entry> + <entry> + <para>The native NMS acknowledge mode: + <literal>auto</literal>, <literal>client</literal>, + <literal>dups-ok</literal> or <literal>transacted</literal>. A + value of <literal>transacted</literal> activates a locally + transacted <literal>Session</literal>. As an alternative, + specify the <literal>transaction-manager</literal> attribute + described below. Default is <literal>auto</literal>.</para> + </entry> </row> <row> <entry>concurrency</entry> - <entry><para>The number of concurrent sessions/consumers to - start for each listener. Default is 1; keep concurrency limited - to 1 in case of a topic listener or if queue ordering is - important; consider raising it for general - queues.</para></entry> + <entry> + <para>The number of concurrent sessions/consumers to start for + each listener. Default is 1; keep concurrency limited to 1 in + case of a topic listener or if queue ordering is important; + consider raising it for general queues.</para> + </entry> </row> <row> <entry>recovery-interval</entry> - <entry><para>The time interval between connection recovery - attempts. The default is 5 seconds. Specify as a TimeSpan value - using Spring's TimeSpanConverter (e.g. 10s, 10m, 3h, etc) - </para></entry> + <entry> + <para>The time interval between connection recovery attempts. + The default is 5 seconds. Specify as a TimeSpan value using + Spring's TimeSpanConverter (e.g. 10s, 10m, 3h, etc)</para> + </entry> </row> <row> <entry>max-recovery-time</entry> - <entry><para>The maximum time try reconnection attempts. The - default is 10 minutes. Specify as a TimeSpan value using - Spring's TimeSpanConverter (e.g. 10s, 10m, 3h, etc) - </para></entry> + <entry> + <para>The maximum time try reconnection attempts. The default + is 10 minutes. Specify as a TimeSpan value using Spring's + TimeSpanConverter (e.g. 10s, 10m, 3h, etc)</para> + </entry> </row> <row> @@ -1425,4 +1446,4 @@ namespace MyApp EmsTemplate</para> </section> </section> -</chapter> \ No newline at end of file +</chapter> diff --git a/doc/reference/src/objects.xml b/doc/reference/src/objects.xml index a7f02cc1..dae287b8 100644 --- a/doc/reference/src/objects.xml +++ b/doc/reference/src/objects.xml @@ -16,7 +16,12 @@ * limitations under the License. */ --> -<chapter xml:id="objects" xmlns="http://docbook.org/ns/docbook" version="5"> +<chapter version="5" xml:id="objects" xmlns="http://docbook.org/ns/docbook" + xmlns:ns6="http://www.w3.org/1999/xlink" + xmlns:ns5="http://www.w3.org/1998/Math/MathML" + xmlns:ns4="http://www.w3.org/1999/xhtml" + xmlns:ns3="http://www.w3.org/2000/svg" + xmlns:ns="http://docbook.org/ns/docbook"> <title>The IoC container @@ -34,11 +39,11 @@ interface provides an advanced configuration mechanism capable of managing objects of any nature. The IApplicationContext - interface builds on top of the IObjectFactory (it - is a sub-interface) and adds other functionality such as easier - integration with Spring.NET's Aspect Oriented Programming (AOP) features, - message resource handling (for use in internationalization), event - propagation and application layer-specific context such as + interface builds on top of the IObjectFactory (it is a + sub-interface) and adds other functionality such as easier integration + with Spring.NET's Aspect Oriented Programming (AOP) features, message + resource handling (for use in internationalization), event propagation and + application layer-specific context such as WebApplicationContext for use in web applications. @@ -47,9 +52,9 @@ IApplicationContext adds more enterprise-centric functionality to it. The IApplicationContext is a complete superset of the IObjectFactory, and any - description of IObjectFactory capabilities and - behavior should be considered to apply to - IApplicationContexts as well. + description of IObjectFactory capabilities and behavior + should be considered to apply to IApplicationContexts + as well. This chapter is divided into two parts, with the first part covering the basic principles @@ -75,9 +80,9 @@ The container - The IObjectFactory is the actual - representation of the Spring IoC container that is responsible for - instantiating, configuring, and managing a number of objects. + The IObjectFactory is the actual representation + of the Spring IoC container that is responsible for instantiating, + configuring, and managing a number of objects. The IObjectFactory interface is the central IoC container interface in Spring. Its responsibilities include @@ -85,11 +90,11 @@ and assembling the dependencies between these objects. There are a number of implementations of the - IObjectFactory interface that come supplied - straight out-of-the-box with Spring. The most commonly used + IObjectFactory interface that come supplied straight + out-of-the-box with Spring. The most commonly used IObjectFactory implementation is the - XmlObjectFactory class. This implementation - allows you to express the objects that compose your application, and the + XmlObjectFactory class. This implementation allows + you to express the objects that compose your application, and the doubtless rich interdependencies between such objects, in terms of XML. The XmlObjectFactory takes this XML configuration metadata and uses it to create a fully configured system or application. @@ -97,12 +102,12 @@ discussed in . Additional features offered by another implementation of IObjectFactory, the - IApplicationContext, are discussed in section - . + IApplicationContext, are discussed in section . - + @@ -186,10 +191,10 @@ IObjectFactory factory = context; url="http://www.springframework.net/doc/api/html/Spring.Core.IO.IResource.html">IResource abstraction. The IResource interface provides a simple and uniform interface to a wide array of IO resources - that can represent themselves as - System.IO.Stream. An example for a file based - resource, not using the URL syntax but an implementation of the - IResource interface for file is shown below.[C#] + that can represent themselves as System.IO.Stream. An + example for a file based resource, not using the URL syntax but an + implementation of the IResource interface for file is shown + below.[C#] IResource input = new FileSystemResource ("objects.xml"); IObjectFactory factory = new XmlObjectFactory(input); @@ -223,9 +228,9 @@ IObjectFactory factory = new XmlObjectFactory(input); </spring> The context type (specified as the value of the type attribute of the context element) is wholly optional, and defaults to the - Spring.Context.Support.XmlApplicationContext - class, so the following XML snippet is functionally equivalent to the - first. <spring> + Spring.Context.Support.XmlApplicationContext class, + so the following XML snippet is functionally equivalent to the first. + <spring> <context> <resource uri="file://services.xml"/> <resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/> @@ -234,15 +239,16 @@ IObjectFactory factory = new XmlObjectFactory(input); To acquire a reference to an IApplicationContext using a custom configuration - section, one simply uses the following code; IApplicationContext ctx = ContextRegistry.GetContext(); - The ContextRegistry is used to both instantiate - the application context and to perform service locator style access to - other objects. (See for more + section, one simply uses the following code; IApplicationContext ctx = ContextRegistry.GetContext(); + The ContextRegistry is used to both instantiate the + application context and to perform service locator style access to other + objects. (See for more information). The glue that makes this possible is an implementation of the Base Class Library (BCL) provided - IConfigurationSectionHandler interface, namely - the Spring.Context.Support.ContextHandler class. - The handler class needs to be registered in the + IConfigurationSectionHandler interface, namely the + Spring.Context.Support.ContextHandler class. The + handler class needs to be registered in the configSections section of the .NET configuration file as shown below. <configSections> <sectionGroup name="spring"> @@ -254,12 +260,11 @@ IObjectFactory factory = new XmlObjectFactory(input); In some usage scenarios, user code will not have to explicitly instantiate an appropriate implementation of the - IObjectFactory interface, since Spring.NET code - will do it. For example, the ASP.NET web layer provides support code to - load a Spring.NET IApplicationContext - automatically as part of the normal startup process of an ASP.NET web - application. Similar support for WinForms applications is being - investigated. + IObjectFactory interface, since Spring.NET code will + do it. For example, the ASP.NET web layer provides support code to load + a Spring.NET IApplicationContext automatically as + part of the normal startup process of an ASP.NET web application. + Similar support for WinForms applications is being investigated. While programmatic manipulation of IObjectFactory instances will be described later, the @@ -279,9 +284,9 @@ IObjectFactory factory = new XmlObjectFactory(input); Your XML object definitions can also be defined within the standard .NET application configuration file by registering the - Spring.Context.Support.DefaultSectionHandler - class as the configuration section handler for inline object - definitions. This allows you to completely configure one or more + Spring.Context.Support.DefaultSectionHandler class as + the configuration section handler for inline object definitions. This + allows you to completely configure one or more IApplicationContext instances within a single standard .NET application configuration file as shown in the following example. <configuration> @@ -311,8 +316,8 @@ IObjectFactory factory = new XmlObjectFactory(input); described in and . - The IApplicationContext can be configured - to register other resource handlers, custom parsers to integrate + The IApplicationContext can be configured to + register other resource handlers, custom parsers to integrate user-contributed XML schema into the object definitions section, type converters, and define type aliases. These features are discussed in section @@ -525,7 +530,7 @@ IObjectFactory factory = new XmlObjectFactory(input); Aliasing objects - + In an object definition itself, you may supply more than one name for the object, by using a combination of the id and name attributes as discussed in . @@ -620,8 +625,8 @@ IObjectFactory factory = new XmlObjectFactory(input); constructor (i.e. a constructor that has no parameters) in the source code definition of your class. - The XmlObjectFactory implementation of - the IObjectFactory interface can consume object + The XmlObjectFactory implementation of the + IObjectFactory interface can consume object definitions that have been defined in XML, for example... <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/> @@ -631,16 +636,15 @@ IObjectFactory factory = new XmlObjectFactory(input); This XML fragment describes an object definition that will be identified by the exampleObject name, instances - of which will be of the Examples.ExampleObject - type that has been compiled into the - ExamplesLibrary assembly. Take special note of the - structure of the type attribute's value... the - namespace-qualified name of the class is specified, followed by a - comma, followed by (at a bare minimum) the name of the assembly that - contains the class. In the preceding example, the - ExampleObject class is defined in the - Examples namespace, and it has been compiled into - the ExamplesLibrary assembly. + of which will be of the Examples.ExampleObject type + that has been compiled into the ExamplesLibrary + assembly. Take special note of the structure of the + type attribute's value... the namespace-qualified + name of the class is specified, followed by a comma, followed by (at a + bare minimum) the name of the assembly that contains the class. In the + preceding example, the ExampleObject class is + defined in the Examples namespace, and it has been + compiled into the ExamplesLibrary assembly. The name of the assembly that contains the type must be specified in the type @@ -660,8 +664,8 @@ IObjectFactory factory = new XmlObjectFactory(input); If you have defined nested classes use the addition symbol, +, to reference the nested class. For example, if the class Examples.ExampleObject had a nested class - Person the XML declaration would be - <object id="exampleObject" type="Examples.ExampleObject+Person, ExamplesLibrary"/> + Person the XML declaration would be <object id="exampleObject" type="Examples.ExampleObject+Person, ExamplesLibrary"/> If you are defining classes that have been compiled into assemblies that are available to your application (such as the @@ -716,7 +720,8 @@ IObjectFactory factory = new XmlObjectFactory(input); an object in the current (or parent/ancestor) container that contains the instance method that is to be invoked to create the object. The name of the factory method itself should still be set via the - 'factory-method' attribute.<!-- the factory object, which contains an instance method called 'CreateInstance' --> + 'factory-method' attribute.<!-- the factory object, which contains an instance method called 'CreateInstance' --> <object id="exampleFactory" type="..."> <!-- inject any dependencies required by this object --> </object> @@ -797,7 +802,8 @@ IObjectFactory factory = new XmlObjectFactory(input); <alias name="GenericDictionary" type=" System.Collections.Generic.Dictionary&lt;,>" /> <alias name="myDictionary" type="System.Collections.Generic.Dictionary&lt;int,string>" /> </typeAliases> - So that instead of something like this <object id="myGenericObject" + So that instead of something like this <object id="myGenericObject" type="GenericsPlay.ExampleGenericObject&lt;System.Collections.Generic.Dictionary&lt;int , string>>, GenericsPlay" /> It can be shortened to <object id="myOtherGenericObject" type="GenericsPlay.ExampleGenericObject&lt;GenericDictionary&lt;int , string>>, GenericsPlay" /> @@ -836,7 +842,8 @@ IObjectFactory factory = new XmlObjectFactory(input); set { someStringKeyedDictionary = value; } } -} The accompanying factory class is +} The accompanying factory class is public class TestGenericObjectFactory { public static TestGenericObject<V, W> StaticCreateInstance<V, W>() @@ -851,7 +858,8 @@ public class TestGenericObjectFactory } The XML snippet to create an instance of TestGenericObject where V is a List of integers and - W is an integer is shown below <object id="myTestGenericObject" + W is an integer is shown below <object id="myTestGenericObject" type="GenericsPlay.TestGenericObjectFactory, GenericsPlay" factory-method="StaticCreateInstance&lt;System.Collections.Generic.List&lt;int>,int>" /> The StaticCreateInstance method is responsible for @@ -878,9 +886,9 @@ public class TestGenericObjectFactory Using the container - An IApplicationContext is essentially - nothing more than the interface for an advanced factory capable of - maintaining a registry of different objects and their dependencies. The + An IApplicationContext is essentially nothing + more than the interface for an advanced factory capable of maintaining a + registry of different objects and their dependencies. The IApplicationContext enables you to read object definitions and access them. You create one and read in some object definition in the XML format as follows: @@ -891,10 +899,10 @@ public class TestGenericObjectFactory Basically that is all there is to it. Using GetObject(string) or the indexer [string], you can retrieve instances of your object; - the client-side view of the IApplicationContext - is simple. The IApplicationContext interface has - just a few other methods related to finding objects in the contianer, - but ideally your application code should never use them... indeed, your + the client-side view of the IApplicationContext is + simple. The IApplicationContext interface has just a + few other methods related to finding objects in the contianer, but + ideally your application code should never use them... indeed, your application code should have no calls to the GetObject(string) method at all, and thus no dependency on Spring APIs at all. @@ -1268,8 +1276,8 @@ namespace SimpleApp initialized with a configuration which describes all the objects. Most Spring.NET users use an IObjectFactory or - IApplicationContext variant that supports - XML format configuration files. + IApplicationContext variant that supports XML + format configuration files. @@ -1294,16 +1302,16 @@ namespace SimpleApp Each property - or constructor argument which is a value must be able to be - converted from whatever format it was specified in, to the + id="object-factory-collaborators-typeconverter">Each + property or constructor argument which is a value must be able + to be converted from whatever format it was specified in, to the actual System.Type of that property or constructor argument. By default Spring.NET can convert a value supplied in string format to all built-in types, such as int, long, string, bool, etc. - Spring.NET uses TypeConverter definitions - to be able to convert string values to other, arbitrary types. + Spring.NET uses TypeConverter definitions to + be able to convert string values to other, arbitrary types. Refer to for more information regarding type conversion, and how you can design your classes to be convertible by Spring.NET. @@ -1316,11 +1324,11 @@ namespace SimpleApp However, the object properties themselves are not set until the object is actually created. For those object that defined as singletons and set to be pre-instantiated (such as singleton object in an - IApplicationContext), creation happens at the - time that the container is created, but otherwise this is only when - the object is requested. When an object actually has to be created, - this will potentially cause a graph of other objects to be created, as - its dependencies and its dependencies' dependencies (and so on) are + IApplicationContext), creation happens at the time + that the container is created, but otherwise this is only when the + object is requested. When an object actually has to be created, this + will potentially cause a graph of other objects to be created, as its + dependencies and its dependencies' dependencies (and so on) are created and assigned. @@ -1362,12 +1370,12 @@ namespace SimpleApp that object or one of its dependencies. This could happen if the object throws an exception as a result of a missing or invalid property, for example. This potentially delayed visibility of some - configuration issues is why IApplicationContext - by default pre-instantiates singleton objects. At the cost of some + configuration issues is why IApplicationContext by + default pre-instantiates singleton objects. At the cost of some upfront time and memory to create these objects before they are actually needed, you find out about configuration issues when the - IApplicationContext is created, not later. If - you wish, you can still override this default behavior and set any of + IApplicationContext is created, not later. If you + wish, you can still override this default behavior and set any of these singleton objects to lazy-load (not be preinstantiated) If no circular dependencies are involved (see sidebar for a @@ -1381,8 +1389,8 @@ namespace SimpleApp configure' to mean that the object will be instantiated (if not a pre-instantiated singleton), all of its dependencies will be set, and the relevant lifecycle methods (such as a configured init - method or the IIntializingObject callback - method) will all be invoked. + method or the IIntializingObject callback method) + will all be invoked. @@ -1390,7 +1398,8 @@ namespace SimpleApp First, an example of using XML-based configuration metadata for setter-based DI. Find below a smallpart of a Spring XML configuration - file specifying some object definitions. <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"> + file specifying some object definitions. <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"> <!-- setter injection using the ref attribute --> <property name="objectOne" ref="anotherExampleObject"/> @@ -1554,10 +1563,10 @@ public class MixedIocObject The <value/> element specifies a property or constructor argument as a human-readable string representation. As mentioned previously, - TypeConverter instances are used to convert - these string values from a System.String to the - actual property or argument type. Custom - TypeConverter implementations in the + TypeConverter instances are used to convert these + string values from a System.String to the actual + property or argument type. Custom TypeConverter + implementations in the Spring.Objects.TypeConverters namespace are used to augment the functionality offered by the .NET BCL's default TypeConverter implementations. @@ -1615,7 +1624,8 @@ public class MixedIocObject actual XML file, and the object name is the object id, the local attribute may be used, which will allow the XML parser itself to validate the - object name even earlier, at parse time. <property name="targetName"> + object name even earlier, at parse time. <property name="targetName"> <idref local="theTargetObject"/> </property> @@ -1629,9 +1639,9 @@ public class MixedIocObject set the value of the specified property to be a reference to another object managed by the container, a collaborator, so to speak. As you saw in the previous example to set collection properties, we used the - SqlConnection instance from the initial example - as a collaborator and specified it using a <ref object/> - element. As mentioned in a previous section, the referred-to object is + SqlConnection instance from the initial example as + a collaborator and specified it using a <ref object/> element. + As mentioned in a previous section, the referred-to object is considered to be a dependency of the object who's property is being set, and will be initialized on demand as needed (if it is a singleton object it may have already been initialized by the container) before @@ -1644,8 +1654,8 @@ public class MixedIocObject object attribute of the ref tag is the most general form, and will allow creating a reference to any object in the same IObjectFactory / - IApplicationContext (whether or not in the same - XML file), or parent IObjectFactory / + IApplicationContext (whether or not in the same XML + file), or parent IObjectFactory / IApplicationContext. The value of the object attribute may be the same as either the id attribute of the target object, or one of the @@ -1673,11 +1683,11 @@ public class MixedIocObject values in the name attribute of the target object, and the target object must be in a parent IObjectFactory or - IApplicationContext of the current one. The - main use of this object reference variant is when there is a need to - wrap an existing object in a parent context with some sort of proxy - (which may have the same name as the parent), and needs the original - object so it may wrap it. + IApplicationContext of the current one. The main + use of this object reference variant is when there is a need to wrap + an existing object in a parent context with some sort of proxy (which + may have the same name as the parent), and needs the original object + so it may wrap it. <ref parent="someObject"/> @@ -1781,25 +1791,24 @@ public class MixedIocObject Spring supports setting values for classes that expose properties based on the generic collection interfaces - IList<T> and - IDictionary<TKey, TValue>. The type - parameter for these collections is specified by using the XML - attribute element-type for - IList<T> and the XML attributes + IList<T> and IDictionary<TKey, + TValue>. The type parameter for these collections is + specified by using the XML attribute element-type + for IList<T> and the XML attributes key-type and value-type for - IDictionary<TKey, TValue>. The values of - the collection are automaticaly converted from a string to the - appropriate type. If you are using your own user-defined type as a - generic type parameter you will likely need to register a custom type - converter. Refer to for - more information. The implementations of - IList<T> and - IDictionary<TKey, TValue> that is created + IDictionary<TKey, TValue>. The values of the + collection are automaticaly converted from a string to the appropriate + type. If you are using your own user-defined type as a generic type + parameter you will likely need to register a custom type converter. + Refer to for more + information. The implementations of IList<T> + and IDictionary<TKey, TValue> that is created are System.Collections.Generic.List and System.Collections.Generic.Dictionary. The following class represents a lottery ticket and demonstrates - how to set the values of a generic IList. public class LotteryTicket { + how to set the values of a generic IList. public class LotteryTicket { List<int> list; @@ -1833,10 +1842,11 @@ public class MixedIocObject demonstrates the use of generics using the Spring.Expressions.IExpression interface as the generic type parameter for the IList element-type and the value-type - for IDictionary. Spring.Expressions.IExpression - has an associated type converter, + for IDictionary. Spring.Expressions.IExpression has + an associated type converter, Spring.Objects.TypeConverters.ExpressionConverter - that is already pre-registered with Spring. public class GenericExpressionHolder + that is already pre-registered with Spring. public class GenericExpressionHolder { private System.Collections.Generic.IList<IExpression> expressionsList; @@ -2001,7 +2011,8 @@ public class MixedIocObject <entry key="myKey"> <value>hello</value> -</entry> are equivalent to:<property name="myProperty" value="hello"/> +</entry> are equivalent to:<property name="myProperty" value="hello"/> <constructor-arg value="hello"/> @@ -2019,7 +2030,8 @@ public class MixedIocObject <constructor-arg index="0"> <ref object="anotherObject"/> -</constructor-arg> is equivalent to... <property name="myProperty" ref="anotherObject"/> +</constructor-arg> is equivalent to... <property name="myProperty" ref="anotherObject"/> <constructor-arg index="0" ref="anotherObject"/> @@ -2031,12 +2043,14 @@ public class MixedIocObject Finally, the entry element allows a shortcut form the specify the key and/or value of a dictionary, in the form of key/key-ref and - value/value-ref attributes. Therefore, the following <entry> + value/value-ref attributes. Therefore, the following <entry> <key> <ref object="MyKeyObject"/> </key> <ref object="MyValueObject"/> -</entry> Is equivalent to: <entry key-ref="MyKeyObject" value-ref="MyValueObject"/> +</entry> Is equivalent to: <entry key-ref="MyKeyObject" value-ref="MyValueObject"/> As mentioned previously, the equivalence is to <ref object="xxx"> and not the local or parent forms of object references. @@ -2087,7 +2101,8 @@ public class MixedIocObject attribute may be used to explicitly force one or more objects to be initialized before the object using this element is initialized. Find below an example of using the 'depends-on' attribute - to express a dependency on a single object.. <object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager"> + to express a dependency on a single object.. <object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager"> <property name="manager" ref="manager"/> </object> @@ -2119,20 +2134,20 @@ public class MixedIocObject Lazily-instantiated objects - The default behavior for - IApplicationContext implementations is to eagerly - pre-instantiate all singleton objects at startup. Pre-instantiation - means that an IApplicationContext will eagerly - create and configure all of its singleton objects as part of its - initialization process. Generally this is a good thing, because it means - that any errors in the configuration or in the surrounding environment - will be discovered immediately (as opposed to possibly hours or even - days down the line). + The default behavior for IApplicationContext + implementations is to eagerly pre-instantiate all singleton objects at + startup. Pre-instantiation means that an + IApplicationContext will eagerly create and configure + all of its singleton objects as part of its initialization process. + Generally this is a good thing, because it means that any errors in the + configuration or in the surrounding environment will be discovered + immediately (as opposed to possibly hours or even days down the + line). However, there are times when this behavior is not what is wanted. If you do not want a singleton object to be pre-instantiated when using - an IApplicationContext, you can selectively - control this by marking an object definition as lazy-initialized. A + an IApplicationContext, you can selectively control + this by marking an object definition as lazy-initialized. A lazily-initialized object indicates to the IoC container whether or not an object instance should be created at startup or when it is first requested. @@ -2155,13 +2170,13 @@ public class MixedIocObject though an object definition may be marked up as being lazy-initialized, if the lazy-initialized object is the dependency of a singleton object that is not lazy-initialized, when the - IApplicationContext is eagerly pre-instantiating - the singleton, it will have to satisfy all of the singletons - dependencies, one of which will be the lazy-initialized object! So don't - be confused if the IoC container creates one of the objects that you - have explicitly configured as lazy-initialized at startup; all that - means is that the lazy-initialized object is being injected into a - non-lazy-initialized singleton object elsewhere. + IApplicationContext is eagerly pre-instantiating the + singleton, it will have to satisfy all of the singletons dependencies, + one of which will be the lazy-initialized object! So don't be confused + if the IoC container creates one of the objects that you have explicitly + configured as lazy-initialized at startup; all that means is that the + lazy-initialized object is being injected into a non-lazy-initialized + singleton object elsewhere. It is also possible to control lazy-initialization at the container level by using the @@ -2236,14 +2251,14 @@ public class MixedIocObject This option gives you the ability to resolve collaborators by type instead of by name. Supposing you have - an IObjectDefinition with a - collaborator typed SqlConnection, - Spring.NET will search the entire object factory for an object - definition of type SqlConnection and - use it as the collaborator. If 0 (zero) or more than - 1 (one) object definitions of the desired type exist in the - container, a failure will be reported and you won't be able to - use autowiring for that specific object. + an IObjectDefinition with a collaborator + typed SqlConnection, Spring.NET will search + the entire object factory for an object definition of type + SqlConnection and use it as the + collaborator. If 0 (zero) or more than 1 (one) + object definitions of the desired type exist in the container, + a failure will be reported and you won't be able to use + autowiring for that specific object. @@ -2640,13 +2655,13 @@ public class ReplacementComputeValue : IMethodReplacer method invocation into a constructor (as an argument) or as the value of a property setter. Similarly, PropertyRetrievingFactoryObject and - FieldRetrievingFactoryObject allow you to - retrieve values from another object's property or field value. These - classes implement the IFactoryObject interface - which indicates to Spring.NET that this object is itself a factory and - the factories product, not the factory itself, is what will be - associated with the object id. Factory objects are discussed further in - + FieldRetrievingFactoryObject allow you to retrieve + values from another object's property or field value. These classes + implement the IFactoryObject interface which + indicates to Spring.NET that this object is itself a factory and the + factories product, not the factory itself, is what will be associated + with the object id. Factory objects are discussed further in Setting a reference to the value of property. @@ -2661,23 +2676,23 @@ public class ReplacementComputeValue : IMethodReplacer must obviously be static). In the case of a property exposed on an instance, the target - object that a PropertyRetrievingFactoryObject - will evaluate can be either an object instance specified directly - inline or a reference to another arbitrary object. In the case of a - static property exposed on a class, the target object will be the - class (the .NET System.Type) exposing the - property. + object that a PropertyRetrievingFactoryObject will + evaluate can be either an object instance specified directly inline or + a reference to another arbitrary object. In the case of a static + property exposed on a class, the target object will be the class (the + .NET System.Type) exposing the property. The result of evaluating the property lookup may then be used in another object definition as a property value or constructor argument. Note that nested properties are supported for both instance and class - property lookups. The IFactoryObject is - discussed more generally in IFactoryObject is discussed + more generally in . Here's an example where a property path is used against another object instance. In this case, an inner object definition is used and - the property path is nested, i.e. spouse.age. <object name="person" type="Spring.Objects.TestObject, Spring.Core.Tests"> + the property path is nested, i.e. spouse.age. <object name="person" type="Spring.Objects.TestObject, Spring.Core.Tests"> <property name="age" value="20"/> <property name="spouse"> <object type="Spring.Objects.TestObject, Spring.Core.Tests"> @@ -2732,8 +2747,8 @@ public class ReplacementComputeValue : IMethodReplacer The FieldRetrievingFactoryObject class addresses much the same area of concern as the - PropertyRetrievingFactoryObject described in - the previous section. However, as its name might suggest, the + PropertyRetrievingFactoryObject described in the + previous section. However, as its name might suggest, the FieldRetrievingFactoryObject class is concerned with looking up the value of a public field exposed on either an instance or a class (and similarly, in the @@ -2741,8 +2756,8 @@ public class ReplacementComputeValue : IMethodReplacer static). The following example demonstrates using a - FieldRetrievingFactoryObject to look up the - value of a (public, static) field exposed on a class + FieldRetrievingFactoryObject to look up the value + of a (public, static) field exposed on a class <object id="withTypesField" type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests"> @@ -2779,24 +2794,22 @@ public class ReplacementComputeValue : IMethodReplacer Setting a property or constructor argument to the return value of a method invocation. - The MethodInvokingFactoryObject rounds - out the trio of classes that permit the setting of properties and + The MethodInvokingFactoryObject rounds out + the trio of classes that permit the setting of properties and constructor arguments using the members of other objects and classes. Whereas the PropertyRetrievingFactoryObject and FieldRetrievingFactoryObject classes dealt with simply looking up and returning the value of property or field on an - object or class, the - MethodInvokingFactoryObject allows one to set a - constructor or property to the return value of an arbitrary method - invocation, + object or class, the MethodInvokingFactoryObject + allows one to set a constructor or property to the return value of an + arbitrary method invocation, - The MethodInvokingFactoryObject class - handles both the case of invoking an (instance) method on another - object in the container, and the case of a static method call on an - arbitrary class. Additionally, it is sometimes necessary to invoke a - method just to perform some sort of initialization.... while the - mechanisms for handling object initialization have yet to be - introduced (see The MethodInvokingFactoryObject class handles + both the case of invoking an (instance) method on another object in + the container, and the case of a static method call on an arbitrary + class. Additionally, it is sometimes necessary to invoke a method just + to perform some sort of initialization.... while the mechanisms for + handling object initialization have yet to be introduced (see ), these mechanisms do not permit any arguments to be passed to any initialization method, and are confined to invoking an initialization @@ -2807,8 +2820,8 @@ public class ReplacementComputeValue : IMethodReplacer The following example (in an XML based IObjectFactory definition) uses the - MethodInvokingFactoryObject class to force a - call to a static factory method prior to the instantiation of the + MethodInvokingFactoryObject class to force a call + to a static factory method prior to the instantiation of the object... <object id="force-init" @@ -2825,16 +2838,16 @@ public class ReplacementComputeValue : IMethodReplacer thus the calling of its configured StaticMethod static initializer method, when myService is first initialized. Please note that in order to effect this initialization, - the MethodInvokingFactoryObject object - must be operating in + the MethodInvokingFactoryObject object must be operating in singleton mode (the default.. see the next paragraph). Note that since this class is expected to be used primarily for accessing factory methods, this factory defaults to operating in singleton mode. As such, as soon as all of the - properties for a MethodInvokingFactoryObject - object have been set, and if the + properties for a MethodInvokingFactoryObject object + have been set, and if the MethodInvokingFactoryObject object is still in singleton mode, the method will be invoked immediately and the return value cached for later access. The first @@ -2864,8 +2877,8 @@ public class ReplacementComputeValue : IMethodReplacer arguments is significant... the order of the values passed to the Arguments property must be the same as the order of the arguments defined on the method signature, including the - argument Type. This is shown in the example - below <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core"> + argument Type. This is shown in the example below + <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core"> <property name="TargetType" value="Whatever.MyClassFactory, MyAssembly"/> <property name="TargetMethod" value="GetInstance"/> @@ -2882,11 +2895,11 @@ public class ReplacementComputeValue : IMethodReplacer The second way involves passing an arguments dictionary to the NamedArguments property... this dictionary - maps argument names (Strings) to argument - values (any object). The argument names are not case-sensitive, and - order is (obviously) not significant (since dictionaries by definition - do not have an order). This is shown in the example below - <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core"> + maps argument names (Strings) to argument values + (any object). The argument names are not case-sensitive, and order is + (obviously) not significant (since dictionaries by definition do not + have an order). This is shown in the example below <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core"> <property name="TargetObject"> <object type="Whatever.MyClassFactory, MyAssembly"/> </property> @@ -2917,12 +2930,13 @@ public class ReplacementComputeValue : IMethodReplacer invoked to the surrounding factory object. Finally, if you want to use - MethodInvokingFactoryObject in conjunction with - a method that has a variable length argument list, then please note - that the variable arguments need to be passed (and configured) as a + MethodInvokingFactoryObject in conjunction with a + method that has a variable length argument list, then please note that + the variable arguments need to be passed (and configured) as a list. Let us consider the following method - definition that uses the params keyword (in - C#), and its attendant (XML) configuration... [C#] + definition that uses the params keyword (in C#), + and its attendant (XML) configuration... [C#] public class MyClassFactory { public object CreateObject(Type objectType, params string[] arguments) @@ -2950,25 +2964,23 @@ public class MyClassFactory Provided IFactoryObject implementations - In addition to - PropertyRetrievingFactoryObject, + In addition to PropertyRetrievingFactoryObject, MethodInvokingFactoryObject, and - FieldRetrievingFactoryObject Spring.NET comes - with other useful implementations of the - IFactoryObject interface. These are discussed - below. + FieldRetrievingFactoryObject Spring.NET comes with + other useful implementations of the IFactoryObject + interface. These are discussed below. Common logging - The LogFactoryObject is useful when you - would like to share a Common.Logging log object across a number of - classes instead of creating a logging instance per class or class - hierarchy. Information on the Common.Logging project can be found - here. In the - example shown below the same logging instance, with a logging category - name of "DAOLogger", is used in both the SimpleAccountDao and - SimpleProductDao data access objects. <objects xmlns="http://www.springframework.net" + The LogFactoryObject is useful when you would + like to share a Common.Logging log object across a number of classes + instead of creating a logging instance per class or class hierarchy. + Information on the Common.Logging project can be found here. In the example + shown below the same logging instance, with a logging category name of + "DAOLogger", is used in both the SimpleAccountDao and SimpleProductDao + data access objects. <objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd" > @@ -3197,18 +3209,18 @@ public class MyClassFactory to another. When using the XML based file to configure the IoC container, string based property values are converted to the target property type. Spring will rely on the standard .NET support for type conversion unless - an alternative TypeConverter is registered for a - given type. How to register custom TypeConverters will be described - shortly. As a reminder, the standard .NET type converter support works by - associating a TypeConverter attribute with the - class definition by passing the type of the converter as an attribute - argument. + an alternative TypeConverter is registered for a given + type. How to register custom TypeConverters will be described shortly. As + a reminder, the standard .NET type converter support works by associating + a TypeConverter attribute with the class definition by + passing the type of the converter as an attribute argument. More information about creating custom TypeConverter implementations can be found online at Microsoft's MSDN website, by searching for Implementing a Type Converter. For example, an abbreviated class definition for the BCL - type Font is shown below. [Serializable, TypeConverter(typeof(FontConverter)), ...] + type Font is shown below. [Serializable, TypeConverter(typeof(FontConverter)), ...] public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDisposable { // Methods @@ -3220,11 +3232,11 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo Type Conversion for Enumerations The default type converter for enumerations is the - System.ComponentModel.EnumConverter class. To - specify the value for an enumerated property, simply use the name of the + System.ComponentModel.EnumConverter class. To specify + the value for an enumerated property, simply use the name of the property. For example the TestObject class has a - property of the enumerated type FileMode. One of - the values for this enumeration is named Create. The + property of the enumerated type FileMode. One of the + values for this enumeration is named Create. The following XML fragment shows how to configure this property <object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests"> @@ -3237,10 +3249,9 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo Built-in TypeConverters Spring.NET pre-registers a number of custom - TypeConverter instances (for example, to convert - a type expressed as a string into a real - System.Type object). Each of those is listed - below and they are all located in the + TypeConverter instances (for example, to convert a + type expressed as a string into a real System.Type + object). Each of those is listed below and they are all located in the Spring.Objects.TypeConverters namespace of the Spring.Core library. @@ -3364,9 +3375,9 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
Spring.NET uses the standard .NET mechanisms for the resolution of - System.Types, including, but not limited to - checking any configuration files associated with your application, - checking the Global Assembly Cache (GAC), and assembly probing. + System.Types, including, but not limited to checking + any configuration files associated with your application, checking the + Global Assembly Cache (GAC), and assembly probing. @@ -3379,8 +3390,8 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo IObjectFactory or IApplicationContext is to use the custom configuration section handler - TypeConverterSectionHandler This is demonstrated - in section + TypeConverterSectionHandler This is demonstrated in + section An alternate approach, present for legacy reasons in the port of Spring.NET from the Java code base, is to use the object factory @@ -3397,10 +3408,9 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo Using CustomConverterConfigurer This section shows in detail how to define a custom type - converter that does not use the .NET - TypeConverter attribute. The type converter - class is standalone and inherits from the - TypeConverter class. It uses the legacy factory + converter that does not use the .NET TypeConverter + attribute. The type converter class is standalone and inherits from + the TypeConverter class. It uses the legacy factory post-processor approach. Consider a user class ExoticType, and @@ -3471,8 +3481,8 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo }
Finally, we use the CustomConverterConfigurer to register the new TypeConverter with the - IApplicationContext, which will then be able to - use it as needed: <object id="customConverterConfigurer" + IApplicationContext, which will then be able to use + it as needed: <object id="customConverterConfigurer" type="Spring.Objects.Factory.Config.CustomConverterConfigurer, Spring.Core"> <property name="CustomConverters"> <dictionary> @@ -3503,12 +3513,12 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo objects. Internally, Spring.NET uses implementations of the - IObjectPostProcessor interface to process any - marker interfaces it can find and call the appropriate methods. If you - need custom features or other lifecycle behavior Spring.NET doesn't - offer out-of-the-box, you can implement an - IObjectPostProcessor yourself. More information - about this can be found in IObjectPostProcessor interface to process any marker + interfaces it can find and call the appropriate methods. If you need + custom features or other lifecycle behavior Spring.NET doesn't offer + out-of-the-box, you can implement an + IObjectPostProcessor yourself. More information about + this can be found in . All the different lifecycle marker interfaces are described @@ -3521,8 +3531,8 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo Spring.Objects.Factory.IInitializingObject interface gives you the ability to perform initialization work after all the necessary properties on an object are set by the container. - The IInitializingObject interface specifies - exactly one method: + The IInitializingObject interface specifies exactly + one method: void AfterPropertiesSet(): called after all properties have been set by the container. This method @@ -3588,19 +3598,19 @@ public class AnotherExampleObject : IInitializingObject IDisposable / <literal>destroy-method</literal> - The System.IDisposable interface provides - you with the ability to get a callback when an + The System.IDisposable interface provides you + with the ability to get a callback when an IObjectFactory is destroyed. The - IDisposable interface specifies exactly one - method: + IDisposable interface specifies exactly one method: + void Dispose(): and is called on destruction of the container. This allows you to release any resources you are keeping in this object (such as database connections). You can throw any Exception here... however, any such - Exception will not stop the destruction - of the container - it will only get logged. + Exception will not stop the destruction of + the container - it will only get logged. @@ -3652,22 +3662,20 @@ public class AnotherExampleObject : IDisposable This allows objects to manipulate the - IObjectFactory that created them - Programatically, through the IObjectFactory - interface, or by casting the reference to a known subclass of this - which exposes additional functionality. Primarily this would consist - of programmatic retrieval of other objects. While there are cases when - this capability is useful, it should generally be avoided, since it - couples the code to Spring.NET, and does not follow the Inversion of - Control style, where collaborators are provided to objects as - properties. + IObjectFactory that created them Programatically, + through the IObjectFactory interface, or by casting + the reference to a known subclass of this which exposes additional + functionality. Primarily this would consist of programmatic retrieval + of other objects. While there are cases when this capability is + useful, it should generally be avoided, since it couples the code to + Spring.NET, and does not follow the Inversion of Control style, where + collaborators are provided to objects as properties. IObjectNameAware - The - Spring.Objects.Factory.IObjectNameAware + The Spring.Objects.Factory.IObjectNameAware interface gives you the ability to let the container set the name of the object definition on the object instance itself. In those cases where your object needs to know what its name is, implement this @@ -3695,13 +3703,13 @@ public class AnotherExampleObject : IDisposable When working with an IObjectFactory Programatically, child object definitions are represented by the - ChildObjectDefinition class. Most users will never - work with them on this level, instead configuring object definitions - declaratively in something like the - XmlObjectFactory. In an - XmlObjectFactory object definition, a child object - definition is indicated simply by using the parent attribute, specifying - the parent object definition as the value of this attribute. + ChildObjectDefinition class. Most users will never work + with them on this level, instead configuring object definitions + declaratively in something like the XmlObjectFactory. + In an XmlObjectFactory object definition, a child + object definition is indicated simply by using the parent attribute, + specifying the parent object definition as the value of this + attribute. <object id="inheritedTestObject" type="Spring.Objects.TestObject, Spring.Core.Tests"> <property name="name" value="parent"/> @@ -3771,17 +3779,18 @@ public class AnotherExampleObject : IDisposable The Spring container is essentially nothing more than an advanced factory capable of maintaining a registry of different objects and their - dependencies. The IObjectFactory enables you to - read object definitions and access them using the object factory. When - using just the IObjectFactory you would create an - instance of one and then read in some object definitions in the XML format - as follows: [C#] + dependencies. The IObjectFactory enables you to read + object definitions and access them using the object factory. When using + just the IObjectFactory you would create an instance of + one and then read in some object definitions in the XML format as follows: + [C#] IResource input = new FileSystemResource ("objects.xml"); XmlObjectFactory factory = new XmlObjectFactory(input); That is pretty much it. Using GetObject(string) (or the more concise indexer method factory ["string"]) - you can retrieve instances of your objects... [C#] + you can retrieve instances of your objects... [C#] object foo = factory.GetObject ("foo"); // gets the object defined as 'foo' object bar = factory ["bar"]; // same thing, just using the indexer @@ -3801,9 +3810,9 @@ Console.WriteLine (three == four); // prints 'false' The client-side view of the IObjectFactory is - surprisingly simple. The IObjectFactory interface - has only seven methods (and the aforementioned indexer) for clients to - call: + surprisingly simple. The IObjectFactory interface has + only seven methods (and the aforementioned indexer) for clients to call: + bool ContainsObject(string): returns true if the IObjectFactory contains an object @@ -3814,18 +3823,18 @@ Console.WriteLine (three == four); // prints 'false' object GetObject(string): returns an instance of the object registered under the given name. Depending on how the object was configured by the - IObjectFactory configuration, either a - singleton (and thus shared) instance or a newly created object will - be returned. An ObjectsException will be thrown - when either the object could not be found (in which case it'll be a + IObjectFactory configuration, either a singleton + (and thus shared) instance or a newly created object will be + returned. An ObjectsException will be thrown when + either the object could not be found (in which case it'll be a NoSuchObjectDefinitionException), or an exception occurred while instantiated and preparing the object. Object this [string]: this is the indexer - for the IObjectFactory interface. It - functions in all other respects in exactly the same way as the + for the IObjectFactory interface. It functions in + all other respects in exactly the same way as the GetObject(string) method. The rest of this documentation will always refer to the GetObject(string) method, but be aware that you @@ -3836,8 +3845,8 @@ Console.WriteLine (three == four); // prints 'false' Object GetObject(string, Type): returns an object, registered under the given name. The object returned will be - cast to the given Type. If the object could - not be cast, corresponding exceptions will be thrown + cast to the given Type. If the object could not + be cast, corresponding exceptions will be thrown (ObjectNotOfRequiredTypeException). Furthermore, all rules of the GetObject(string) method apply (see above). @@ -3878,8 +3887,8 @@ Console.WriteLine (three == four); // prints 'false' A sub-interface of IObjectFactory, - IConfigurableObjectFactory adds some convenient - methods such as + IConfigurableObjectFactory adds some convenient methods + such as @@ -3926,11 +3935,10 @@ Console.WriteLine (three == four); // prints 'false' The IoC component of the Spring Framework has been designed for extension. There is typically no need for an application developer to subclass any of the various IObjectFactory or - IApplicationContext implementation classes. The - Spring IoC container can be infinitely extended by plugging in - implementations of special integration interfaces. The next few sections - are devoted to detailing all of these various integration - interfaces. + IApplicationContext implementation classes. The Spring + IoC container can be infinitely extended by plugging in implementations of + special integration interfaces. The next few sections are devoted to + detailing all of these various integration interfaces. Customizing objects with @@ -3947,15 +3955,14 @@ Console.WriteLine (three == four); // prints 'false' <literal>IObjectPostProcessor</literal> implementations.</para> <para>You can configure multiple - <literal>IObjectPostProcessors</literal> if you wish. You can - control the order in which these - <literal>IObjectPostProcessor</literal> execute by setting the - 'Order' property (you can only set this property if the + <literal>IObjectPostProcessors</literal> if you wish. You can control + the order in which these <literal>IObjectPostProcessor</literal> execute + by setting the 'Order' property (you can only set this property if the <literal>IObjectPostProcessor</literal> implements the <literal>IOrdered</literal> interface; if you write your own - <literal>IObjectPostProcessor</literal> you should consider - implementing the <literal>IOrdered</literal> interface too); consult - the SDK docs for the <literal>IObjectPostProcessor</literal> and + <literal>IObjectPostProcessor</literal> you should consider implementing + the <literal>IOrdered</literal> interface too); consult the SDK docs for + the <literal>IObjectPostProcessor</literal> and <literal>IOrdered</literal> interfaces for more details.</para> <note> @@ -3965,20 +3972,20 @@ Console.WriteLine (three == four); // prints 'false' <literal>IObjectPostProcessors</literal> get a chance to do their stuff. If you want to change the actual object definition (that is the recipe that defines the object), then you rather need to use a - <literal>IObjectFactoryPostProcessor</literal> (described below in - the section entitled <link + <literal>IObjectFactoryPostProcessor</literal> (described below in the + section entitled <link linkend="objects-factory-customizing-factory-postprocessors">Customizing configuration metadata with IObjectFactoryPostProcessors.</link></para> <para>Also, <literal>IObjectPostProcessors</literal> are scoped per-container. This is only relevant if you are using container - hierarchies. If you define a - <literal>IObjectPostProcessor</literal> in one container, it will - only do its stuff on the objects in that container. Objects that are - defined in another container will not be post-processed by - <literal>IObjectPostProcessors</literal> in another container, - even if both containers are part of the same hierarchy.</para> + hierarchies. If you define a <literal>IObjectPostProcessor</literal> + in one container, it will only do its stuff on the objects in that + container. Objects that are defined in another container will not be + post-processed by <literal>IObjectPostProcessors</literal> in another + container, even if both containers are part of the same + hierarchy.</para> </note> <para>The @@ -3993,18 +4000,17 @@ object PostProcessAfterInitialization(object instance, string name);</programlis by the container, the post-processor will get a callback from the container both <emphasis>before</emphasis> any initialization methods (such as the <methodname>AfterPropertiesSet</methodname> method of the - <literal>IInitializingObject</literal> interface and any declared - init method) are called, and also afterwards. The post-processor is free - to do what it wishes with the object, including ignoring the callback + <literal>IInitializingObject</literal> interface and any declared init + method) are called, and also afterwards. The post-processor is free to + do what it wishes with the object, including ignoring the callback completely. An object post-processor will typically check for marker interfaces, or do something such as wrap an object with a proxy. Some Spring.NET AOP infrastructure classes are implemented as object post-processors as they do this proxy-wrapping logic.</para> <para>Other extensions to the <literal>IObjectPostProcessors</literal> - interface are - <literal>IInstantiationAwareObjectPostProcessor</literal> and - <literal>IDestructionAwareObjectPostProcessor</literal> defined + interface are <literal>IInstantiationAwareObjectPostProcessor</literal> + and <literal>IDestructionAwareObjectPostProcessor</literal> defined below <programlisting language="csharp">public interface IInstantiationAwareObjectPostProcessor : IObjectPostProcessor { object PostProcessBeforeInstantiation(Type objectType, string objectName); @@ -4036,22 +4042,21 @@ public interface IDestructionAwareObjectPostProcessor : IObjectPostProcessor processing such as making sure that a property is set to a value if it contains a <literal>[Required]</literal> attribute or to perform attribute based wiring, i.e. adding the attribute - <literal>[Inject("objectName")]</literal> on a property. Both of - these features are scheduled to be included in Spring .12.</para> + <literal>[Inject("objectName")]</literal> on a property. Both of these + features are scheduled to be included in Spring .12.</para> <para>The <literal>IDestructionAwareObjectPostProcessor</literal> callback contains a single method, - <literal>PostProcessBeforeDestruction</literal>, which is called - before a singleton's destroy method is invoked.</para> + <literal>PostProcessBeforeDestruction</literal>, which is called before + a singleton's destroy method is invoked.</para> - <para>It is important to know that the - <literal>IObjectFactory</literal> treats object post-processors - slightly differently than the + <para>It is important to know that the <literal>IObjectFactory</literal> + treats object post-processors slightly differently than the <literal>IApplicationContext</literal>. An <literal>IApplicationContext</literal> will automatically detect any objects which are deployed into it that implement the - <literal>IObjectPostProcessor</literal> interface, and register them - as post-processors, to be then called appropriately by the factory on + <literal>IObjectPostProcessor</literal> interface, and register them as + post-processors, to be then called appropriately by the factory on object creation. Nothing else needs to be done other than deploying the post-processor in a similar fashion to any other object. On the other hand, when using plain <literal>IObjectFactories</literal>, object @@ -4065,21 +4070,21 @@ factory.AddObjectPostProcessor(pp); ...</programlisting></para> <para>This explicit registration step is not convenient, and this is one - of the reasons why the various - <literal>IApplicationContext</literal> implementations are preferred - above plain <literal>IObjectFactory</literal> implementations in the - vast majority of Spring-backed applications, especially when using + of the reasons why the various <literal>IApplicationContext</literal> + implementations are preferred above plain + <literal>IObjectFactory</literal> implementations in the vast majority + of Spring-backed applications, especially when using IObjectPostProcessors.</para> <note> <para>IObjectPostProcessors and AOP auto-proxying</para> <para>Classes that implement the - <literal>IObjectPostProcessor</literal> interface are special, and - so they are treated differently by the container. All - <literal>IObjectPostProcessors</literal> and their directly - referenced object will be instantiated on startup, as part of the - special startup phase of the IApplicationContext, then all those + <literal>IObjectPostProcessor</literal> interface are special, and so + they are treated differently by the container. All + <literal>IObjectPostProcessors</literal> and their directly referenced + object will be instantiated on startup, as part of the special startup + phase of the IApplicationContext, then all those <literal>IObjectPostProcessors</literal> will be registered in a sorted fashion - and applied to all further objects. Since AOP auto-proxying is implemented as a @@ -4088,8 +4093,8 @@ factory.AddObjectPostProcessor(pp); objects are eligible for auto-proxying (and thus will not have aspects 'woven' into them). For any such object, you should see an info log message: “Object 'foo' is not eligible for getting processed by all - <literal>IObjectPostProcessors</literal> (for example: not - eligible for auto-proxying)â€.</para> + <literal>IObjectPostProcessors</literal> (for example: not eligible + for auto-proxying)â€.</para> </note> <para></para> @@ -4188,8 +4193,8 @@ DEBUG - MovieApp Done.</programlisting> being<emphasis> 'required-to-be-set' </emphasis>(i.e. an setter property with this attribute applied must be configured to be dependency injected with a value), else an - <literal>ObjectInitializationException</literal> will be thrown by - the container at runtime.</para> + <literal>ObjectInitializationException</literal> will be thrown by the + container at runtime.</para> <para>The best way to illustrate the usage of this attribute is with an example.</para> @@ -4236,22 +4241,22 @@ DEBUG - MovieApp Done.</programlisting> appropriately.</para> <para>This component is the - <literal>RequiredAttributeObjectPostProcessor</literal> class. - This is a special <literal>IObjectPostProcessor</literal> - implementation that is <literal>[Required]</literal>-aware and - actually provides the 'blow up if this required property has not been - set' logic. It is very easy to configure; simply drop the following - object definition into your Spring XML configuration.</para> + <literal>RequiredAttributeObjectPostProcessor</literal> class. This is + a special <literal>IObjectPostProcessor</literal> implementation that + is <literal>[Required]</literal>-aware and actually provides the 'blow + up if this required property has not been set' logic. It is very easy + to configure; simply drop the following object definition into your + Spring XML configuration.</para> <programlisting language="myxml"><object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core"/></programlisting> <para>Finally, one can configure an instance of the - <literal>RequiredAttributeObjectPostProcessor</literal> class to - look for another <literal>Attribute</literal> type. This is great if - you already have your own <literal>[Required]</literal>-style - attribute. Simply plug it into the definition of a - <literal>RequiredAttributeObjectPostProcessor</literal> and you - are good to go. By way of an example, let's suppose you (or your + <literal>RequiredAttributeObjectPostProcessor</literal> class to look + for another <literal>Attribute</literal> type. This is great if you + already have your own <literal>[Required]</literal>-style attribute. + Simply plug it into the definition of a + <literal>RequiredAttributeObjectPostProcessor</literal> and you are + good to go. By way of an example, let's suppose you (or your organization / team) have defined an attribute called [Mandatory]. You can make a <literal>RequiredAttributeObjectPostProcessor</literal> instance <literal>[Mandatory]</literal>-aware like so:</para> @@ -4270,8 +4275,8 @@ DEBUG - MovieApp Done.</programlisting> <literal>Spring.Objects.Factory.Config.IObjectFactoryPostProcessor</literal>. The semantics of this interface are similar to the <literal>IObjectPostProcessor</literal>, with one major difference. - <literal>IObjectFactoryPostProcessors</literal> operate on; that is - to say, the Spring IoC container will allow + <literal>IObjectFactoryPostProcessors</literal> operate on; that is to + say, the Spring IoC container will allow <literal>IObjectFactoryPostProcessors</literal> to read the configuration metadata and potentially change it before the container has actually instantiated any other objects. By implementing this @@ -4287,32 +4292,31 @@ DEBUG - MovieApp Done.</programlisting> <para>You can configure multiple <literal>IObjectFactoryPostProcessors</literal> if you wish. You can control the order in which these - <literal>IObjectFactoryPostProcessors</literal> execute by setting - the 'Order' property (you can only set this property if the + <literal>IObjectFactoryPostProcessors</literal> execute by setting the + 'Order' property (you can only set this property if the <literal>IObjectFactoryPostProcessors</literal> implements the <literal>IOrdered</literal> interface; if you write your own <literal>IObjectFactoryPostProcessors</literal> you should consider - implementing the <literal>IOrdered</literal> interface too); consult - the SDK docs for the <literal>IObjectFactoryPostProcessors</literal> - and <literal>IOrdered</literal> interfaces for more details.</para> + implementing the <literal>IOrdered</literal> interface too); consult the + SDK docs for the <literal>IObjectFactoryPostProcessors</literal> and + <literal>IOrdered</literal> interfaces for more details.</para> <note> <para>If you want to change the actual object instances (the objects that are created from the configuration metadata), then you rather - need to use a <literal>IObjectObjectPostProcessor</literal> - (described above in the section entitled <link + need to use a <literal>IObjectObjectPostProcessor</literal> (described + above in the section entitled <link linkend="objects-factory-customizing">Customizing objects with <literal>IObjectPostProcessors</literal></link>.</para> - <para>Also, <literal>IObjectFactoryPostProcessors</literal> are - scoped per-container. This is only relevant if you are using container + <para>Also, <literal>IObjectFactoryPostProcessors</literal> are scoped + per-container. This is only relevant if you are using container hierarchies. If you define a - <literal>IObjectFactoryPostProcessors</literal> in one container, - it will only do its stuff on the object definitions in that container. + <literal>IObjectFactoryPostProcessors</literal> in one container, it + will only do its stuff on the object definitions in that container. Object definitions in another container will not be post-processed by - <literal>IObjectFactoryPostProcessors</literal> in another - container, even if both containers are part of the same - hierarchy.</para> + <literal>IObjectFactoryPostProcessors</literal> in another container, + even if both containers are part of the same hierarchy.</para> </note> <para>An object factory post-processor is executed manually (in the case @@ -4326,9 +4330,9 @@ DEBUG - MovieApp Done.</programlisting> objects transactionally or with any other kind of proxy, as described later in this manual.</para> - <para>In an <literal>IObjectFactory</literal>, the process of - applying an <literal>IObjectFactoryPostProcessor</literal> is - manual, and will be similar to this:</para> + <para>In an <literal>IObjectFactory</literal>, the process of applying + an <literal>IObjectFactoryPostProcessor</literal> is manual, and will be + similar to this:</para> <para><programlisting language="csharp">XmlObjectFactory factory = new XmlObjectFactory(new FileSystemResource("objects.xml")); <lineannotation>// create placeholderconfigurer to bring in some property @@ -4339,32 +4343,32 @@ cfg.setLocation(new FileSystemResource("ado.properties")); cfg.PostProcessObjectFactory(factory);</programlisting></para> <para><anchor - id="objects-factory-autodetect-objectfactorypostprocessors" />This + id="objects-factory-autodetect-objectfactorypostprocessors"></anchor>This explicit registration step is not convenient, and this is one of the reasons why the various <literal>IApplicationContext</literal> implementations are preferred above plain - <literal>IObjectFactory</literal> implementations in the vast - majority of Spring-backed applications, especially when using + <literal>IObjectFactory</literal> implementations in the vast majority + of Spring-backed applications, especially when using <literal>IObjectFactoryPostProcessors</literal>.</para> - <para>An <literal>IApplicationContext</literal> will detect any - objects which are deployed into it that implement the + <para>An <literal>IApplicationContext</literal> will detect any objects + which are deployed into it that implement the <literal>ObjectFactoryPostProcessor</literal> interface, and automatically use them as object factory post-processors, at the appropriate time. Nothing else needs to be done other than deploying these post-processor in a similar fashion to any other object.</para> <note> - <para>Just as in the case of - <literal>IObjectPostProcessors</literal>, you typically don't want - to have <literal>IObjectFactoryPostProcessors</literal> marked as - being lazily-initialized. If they are marked as such, then the Spring + <para>Just as in the case of <literal>IObjectPostProcessors</literal>, + you typically don't want to have + <literal>IObjectFactoryPostProcessors</literal> marked as being + lazily-initialized. If they are marked as such, then the Spring container will never instantiate them, and thus they won't get a chance to apply their custom logic. If you are using the 'default-lazy-init' attribute on the declaration of your <objects/> element, be sure to mark your various - <literal>IObjectFactoryPostProcessor</literal> object definitions - with 'lazy-init="false"'.</para> + <literal>IObjectFactoryPostProcessor</literal> object definitions with + 'lazy-init="false"'.</para> </note> <sect3 xml:id="objects-factory-placeholderconfigurer"> @@ -4389,9 +4393,9 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> implement the <literal>IObjectFactoryPostProcessor</literal> interface. This means that as described here, applying a <literal>PropertyPlaceholderConfigurer</literal> is much more - convenient when using an <literal>IApplicationContext</literal>. - For this reason, it is recommended that users wishing to use this or - other object factory postprocessors use an + convenient when using an <literal>IApplicationContext</literal>. For + this reason, it is recommended that users wishing to use this or other + object factory postprocessors use an <literal>IApplicationContext</literal> instead of an <literal>IObjectFactory</literal>.</para> @@ -4401,7 +4405,8 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> the main Spring.NET configuration file we use place holders, in the NAnt style of ${variableName}, and obtain their values from NameValueSections in the standard .NET application configuration file. - The Spring.NET configuration file looks like: <programlisting language="myxml"><configuration> + The Spring.NET configuration file looks like: <programlisting + language="myxml"><configuration> <configSections> <sectionGroup name="spring"> @@ -4463,16 +4468,16 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> <literal>${connection.string}</literal> match the key names used in the two NameValueSectionHandlers <literal>DaoConfiguration</literal> and <literal>DatabaseConfiguration</literal>. The - <literal>PropertyPlaceholderConfigurer</literal> refers to these - two sections via a comma delimited list of section names in the + <literal>PropertyPlaceholderConfigurer</literal> refers to these two + sections via a comma delimited list of section names in the <literal>configSections</literal> property. If you are using section groups, prefix the section group name, for example myConfigSection/DaoConfiguraiton.</para> - <para>The <literal>PropertyPlaceholderConfigurer</literal> class - also supports retrieving name value pairs from other - <literal>IResource</literal> locations. These can be specified - using the <literal>Location</literal> and <literal>Locations</literal> + <para>The <literal>PropertyPlaceholderConfigurer</literal> class also + supports retrieving name value pairs from other + <literal>IResource</literal> locations. These can be specified using + the <literal>Location</literal> and <literal>Locations</literal> properties of the <literal>PropertyPlaceHolderConfigurer</literal> class.</para> @@ -4529,17 +4534,17 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> property placeholders. The use of environment variables is controlled via the property <literal>EnvironmentVariableMode</literal>. This property is an - enumeration of the type - <literal>EnvironmentVariablesMode</literal> and has three - values, Never, Fallback, and Override. <literal>Fallback</literal> - is the default value and will resolve a property placeholder if it - was not already done so via a value from a resource location. - <literal>Override</literal> will apply environment variables before - applying values defined from a resource location. - <literal>Never</literal> will, quite appropriately, disable - environment variable substitution. An example of how the - <literal>PropertyPlaceholderConfigurer</literal> XML is modified - to enable override usage is shown below <programlisting language="myxml"><object name="appConfigPropertyHolder" + enumeration of the type <literal>EnvironmentVariablesMode</literal> + and has three values, Never, Fallback, and Override. + <literal>Fallback</literal> is the default value and will resolve a + property placeholder if it was not already done so via a value from + a resource location. <literal>Override</literal> will apply + environment variables before applying values defined from a resource + location. <literal>Never</literal> will, quite appropriately, + disable environment variable substitution. An example of how the + <literal>PropertyPlaceholderConfigurer</literal> XML is modified to + enable override usage is shown below <programlisting + language="myxml"><object name="appConfigPropertyHolder" type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core"> <property name="configSections" value="DaoConfiguration,DatabaseConfiguration"/> <property name="EnvironmentVariableMode" value="Override"/> @@ -4554,8 +4559,8 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> <para>The <literal>PropertyOverrideConfigurer</literal>, another object factory post-processor, is similar to the - <literal>PropertyPlaceholderConfigurer</literal>, but in contrast - to the latter, the original definitions can have default values or no + <literal>PropertyPlaceholderConfigurer</literal>, but in contrast to + the latter, the original definitions can have default values or no values at all for object properties. If an overriding configuration file does not have an entry for a certain object property, the default context definition is used.</para> @@ -4564,13 +4569,13 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> <emphasis>not</emphasis> aware of being overridden, so it is not immediately obvious when looking at the XML definition file that the override configurer is being used. In case that there are multiple - <literal>PropertyOverrideConfigurer</literal> instances that - define different values for the same object property, the last one - will win (due to the overriding mechanism).</para> + <literal>PropertyOverrideConfigurer</literal> instances that define + different values for the same object property, the last one will win + (due to the overriding mechanism).</para> <para>The example usage is similar to when using - <literal>PropertyPlaceHolderConfigurer</literal> except that the - key name refers to the name given to the object in the Spring.NET + <literal>PropertyPlaceHolderConfigurer</literal> except that the key + name refers to the name given to the object in the Spring.NET configuration file and is suffixed via 'dot' notation with the name of the property For example, if the application configuration file is <programlisting language="myxml"><configuration> @@ -4671,11 +4676,10 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> <literal>VariableSource</literal> to a single <literal>IVariableSource</literal> instance or the list property <literal>VariableSources</literal> to a list of - <literal>IVariableSource</literal> instances. In the case of the - same property defined in multiple - <literal>IVariableSource</literal> implementations, the first one - in the list that contains the property value will be used. - <programlisting language="myxml"><object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core"> + <literal>IVariableSource</literal> instances. In the case of the same + property defined in multiple <literal>IVariableSource</literal> + implementations, the first one in the list that contains the property + value will be used. <programlisting language="myxml"><object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core"> <property name="VariableSources"> <list> <object type="Spring.Objects.Factory.Config.ConfigSectionVariableSource, Spring.Core"> @@ -4744,16 +4748,16 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> places within the Spring Framework. Some examples of its use is described in <xref linkend="objects-advancedproperty-setting" /> for the <literal>PropertyRetrievingFactoryObject</literal> and - <literal>FieldRetrievingFactoryObject</literal>. An additional use - of creating an custom IFactoryObject implementation is to retrieve an + <literal>FieldRetrievingFactoryObject</literal>. An additional use of + creating an custom IFactoryObject implementation is to retrieve an object from an embedded resource file and use it to set another objects dependency. An example of this is provided <ulink url="http://jira.springframework.org/browse/SPRNET-133#action_19743">here</ulink>.</para> <para>Finally, there is sometimes a need to ask a container for an - actual <literal>IFactoryObject</literal> instance itself, not the - object it produces. This may be achieved by prepending the object id - with '<literal>&</literal>' (sans quotes) when calling the + actual <literal>IFactoryObject</literal> instance itself, not the object + it produces. This may be achieved by prepending the object id with + '<literal>&</literal>' (sans quotes) when calling the <literal>GetObject</literal> method of the <literal>IObjectFactory</literal> (including <literal>IApplicationContext</literal>). So for a given @@ -4769,9 +4773,8 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> <para>The <literal>Spring.Objects.Factory.IConfigurableFactoryObject</literal> - interface inherits from <literal>IFactoryObject</literal> - interface and adds the following property.<itemizedlist - spacing="compact"> + interface inherits from <literal>IFactoryObject</literal> interface + and adds the following property.<itemizedlist spacing="compact"> <listitem> <para><literal> IObjectDefinition ProductTemplate </literal>: Gets the template object definition that should be used to @@ -4780,8 +4783,8 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> </listitem> </itemizedlist></para> - <para><literal>IConfigurableFactoryObject</literal> implementions - you already have examples of in <xref linkend="client-side" /> are + <para><literal>IConfigurableFactoryObject</literal> implementions you + already have examples of in <xref linkend="client-side" /> are <literal>WebServiceProxyFactory</literal>.</para> </sect3> </sect2> @@ -4809,8 +4812,8 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> <literal>IApplicationContext</literal> interface, located in the <literal>Spring.Context</literal> namespace. Deriving from the <literal>IObjectFactory</literal> interface, it provides all the - functionality of the <literal>IObjectFactory</literal>. To be able to - work in a more framework-oriented fashion, using layering and hierarchical + functionality of the <literal>IObjectFactory</literal>. To be able to work + in a more framework-oriented fashion, using layering and hierarchical contexts, the <literal>Spring.Context</literal> namespace also provides the following functionality<itemizedlist spacing="compact"> <listitem> @@ -4843,28 +4846,27 @@ cfg.PostProcessObjectFactory(factory);</programlisting></para> <sect2> <title>IObjectFactory or IApplicationContext? - Short version: use an - IApplicationContext unless - you have a really good reason for not doing so. For those of you that - are looking for slightly more depth as to the 'but why' of the above - recommendation, keep reading. + Short version: use an + IApplicationContext + unless you have a really good reason for not doing so. For + those of you that are looking for slightly more depth as to the 'but + why' of the above recommendation, keep reading. As the IApplicationContext includes all the functionality the object factory via its inheritance of the - IObjectFactory interface, it is generally - recommended to be used over the IObjectFactory - except for a few limited situations where memory consumption might be - critical. This may become more important if the .NET Compact Framework - is supported. The history of IObjectFactory comes - from the Spring Java framework, where the use of Spring in Applets was a - concern to reduce memory consumption. However, for most 'typical' - enterprise applications and systems, the - IApplicationContext is what you will want to use. - Spring generally makes heavy use of the + IObjectFactory interface, it is generally recommended + to be used over the IObjectFactory except for a few + limited situations where memory consumption might be critical. This may + become more important if the .NET Compact Framework is supported. The + history of IObjectFactory comes from the Spring Java + framework, where the use of Spring in Applets was a concern to reduce + memory consumption. However, for most 'typical' enterprise applications + and systems, the IApplicationContext is what you will + want to use. Spring generally makes heavy use of the IObjectPostProcessor extension point (to effect proxying and suchlike), and if you are using just a plain - IObjectFactory then a fair amount of support such - as transactions and AOP will not take effect (at least not without some + IObjectFactory then a fair amount of support such as + transactions and AOP will not take effect (at least not without some extra steps on your part), which could be confusing because nothing will actually be wrong with the configuration. @@ -4873,8 +4875,8 @@ cfg.PostProcessObjectFactory(factory); IApplicationContext interfaces (and attendant implementations). The following sections describe functionality that IApplicationContext adds to the basic - IObjectFactory capabilities in a lot more depth - than the said feature matrix.) + IObjectFactory capabilities in a lot more depth than + the said feature matrix.) @@ -4887,60 +4889,88 @@ cfg.PostProcessObjectFactory(factory); Feature - IObjectFactory + + IObjectFactory + - IApplicationContext + + IApplicationContext + - Object instantiation/wiring + + Object instantiation/wiring + - Yes + + Yes + - Yes + + Yes + - Automatic - IObjectPostProcessor - registration + + Automatic IObjectPostProcessor + registration + - No + + No + - Yes + + Yes + - Automatic - IObjectFactoryPostProcessor - registration + + Automatic IObjectFactoryPostProcessor + registration + - No + + No + - Yes + + Yes + - Convenient - IMessageSource - access + + Convenient IMessageSource + access + - No + + No + - Yes + + Yes + - ApplicationEvent - publication + + ApplicationEvent publication + - No + + No + - Yes + + Yes + @@ -5095,14 +5125,14 @@ IApplicationContext context = Creating a custom resource handler means implementing the IResource interface. The base class - AbstractResource is a useful starting point. Look - at the Spring source for classes such as + AbstractResource is a useful starting point. Look at + the Spring source for classes such as FileSystemResource or AssemblyResource for implementation tips. You can register your custom resource handler either within App.config, as shown in the program listing at the start of this section using a - .ResourceHandlersSectionHandler or define an - object of the type + .ResourceHandlersSectionHandler or define an object + of the type Spring.Objects.Factory.Config.ResourceHandlerConfigurer as you would any other Spring managed object. An example of the latter is shown below: @@ -5177,8 +5207,8 @@ IApplicationContext context = within the regular <objects> section of any standard Spring configuration file. This approach allows for more modularity in defining type aliases, for example if you can't access App.config/Web.config. An - example of registration using a - TypeAliasConfigurer is shown below + example of registration using a TypeAliasConfigurer + is shown below <object id="myTypeAlias" type="Spring.Objects.Factory.Config.TypeAliasConfigurer, Spring.Core"> <property name="TypeAliases"> @@ -5195,14 +5225,14 @@ IApplicationContext context = Registering Type Converters The standard .NET mechanism for specifying a type converter is to - add a TypeConverter attribute to a type - definition to specify the type of the Converter. This is the preferred - way of defining type converters if you control the source code for the - type that you want to define a converter for. However, this - configuration section allows you to specify converters for the types - that you don't control, and it also allows you to override some of the - standard type converters, such as the ones that are defined for some of - the types in the .NET Base Class Library. + add a TypeConverter attribute to a type definition to + specify the type of the Converter. This is the preferred way of defining + type converters if you control the source code for the type that you + want to define a converter for. However, this configuration section + allows you to specify converters for the types that you don't control, + and it also allows you to override some of the standard type converters, + such as the ones that are defined for some of the types in the .NET Base + Class Library. You can specify the type converters in App.config by using Spring.Context.Support.TypeConvertersSectionHandler as shown before or @@ -5227,8 +5257,8 @@ IApplicationContext context = As already stated in the previous section, the IApplicationContext has a couple of features that - distinguish it from the IObjectFactory. Let us - review them one-by-one. + distinguish it from the IObjectFactory. Let us review + them one-by-one. Context Hierarchies @@ -5297,8 +5327,8 @@ IApplicationContext context = Using <literal>IMessageSource</literal> - The IApplicationContext interface extends - an interface called IMessageSource and provides + The IApplicationContext interface extends an + interface called IMessageSource and provides localization (i18n or internationalization) services for text messages and other resource data types such as images. This functionality makes it easier to use .NET's localization features at an application level @@ -5332,9 +5362,9 @@ IApplicationContext context = string GetMessage(string name, CultureInfo cultureInfo, params object[] args): retrieves a message - from the IMessageSource using a variable - list of arguments as replacement values in the message. The - specified culture is used to resolve the message. + from the IMessageSource using a variable list + of arguments as replacement values in the message. The specified + culture is used to resolve the message. @@ -5349,11 +5379,10 @@ IApplicationContext context = string GetMessage(IMessageSourceResolvable - resolvable, CultureInfo culture) - : all properties used in the methods above are also - wrapped in a class - the - MessageSourceResolvable, which you can use in - this method. + resolvable, CultureInfo culture) : + all properties used in the methods above are also wrapped in a + class - the MessageSourceResolvable, which you + can use in this method. @@ -5380,17 +5409,17 @@ IApplicationContext context = When an IApplicationContext gets loaded, it - automatically searches for an IMessageSource - object defined in the context. The object has to have the name + automatically searches for an IMessageSource object + defined in the context. The object has to have the name messageSource. If such an object is found, all calls to the methods described above will be delegated to the message source that was found. If no message source was found, the - IApplicationContext checks to see if it has a - parent containing a similar object, with a similar name. If so, it uses - that object as the IMessageSource. If it can't - find any source for messages, an empty - StaticMessageSource will be instantiated in order to - be able to accept calls to the methods defined above. + IApplicationContext checks to see if it has a parent + containing a similar object, with a similar name. If so, it uses that + object as the IMessageSource. If it can't find any + source for messages, an empty StaticMessageSource + will be instantiated in order to be able to accept calls to the methods + defined above. @@ -5401,23 +5430,23 @@ IApplicationContext context = Spring.NET provides two IMessageSource - implementations. These are - ResourceSetMessageSource and - StaticMessageSource. Both implement + implementations. These are ResourceSetMessageSource + and StaticMessageSource. Both implement IHierarchicalMessageSource to resolve messages hierarchically. The StaticMessageSource is hardly ever used but provides programmatic ways to add messages to the source. - The ResourceSetMessageSource is more interesting - and an example is provided for in the distribution and discussed more + The ResourceSetMessageSource is more interesting and + an example is provided for in the distribution and discussed more extensively in the section. The - ResourceSetMessageSource is configured by - providing a list of ResourceManagers. When a - message code is to be resolved, the list of ResourceManagers is searched - to resolve the code. For each ResourceManager a + ResourceSetMessageSource is configured by providing a + list of ResourceManagers. When a message code is to + be resolved, the list of ResourceManagers is searched to resolve the + code. For each ResourceManager a ResourceSet is retrieved and asked to resolve the code. Note that this search does not replace the standard hub-and-spoke search for localized resources. The ResourceManagers list specifies the - multiple 'hubs' where the standard search starts. <object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core"> + multiple 'hubs' where the standard search starts. <object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core"> <property name="resourceManagers"> <list> <value>Spring.Examples.AppContext.MyResource, Spring.Examples.AppContext</value> @@ -5430,9 +5459,9 @@ IApplicationContext context = assembly name. This will be converted to a ResourceManager via the ResourceManagerConverter TypeConverter. This converter can be similarly used to set a property on any object that is - of the type ResourceManager. You may also specify - an instance of the ResourceManager to use via an - object reference. The convenience class + of the type ResourceManager. You may also specify an + instance of the ResourceManager to use via an object + reference. The convenience class Spring.Objects.Factory.Config.ResourceManagerFactoryObject can be used to conveniently create an instance of a ResourceManager. <object name="myResourceManager" type="Spring.Objects.Factory.Config.ResourceManagerFactoryObject, Spring.Core"> @@ -5471,7 +5500,8 @@ IApplicationContext context = '{0} is required {1}' and another key name field.firstname with the value 'First name'. The following code will create the string - 'First name is required dude!' string[] codes = {"field.firstname"}; + 'First name is required dude!' string[] codes = {"field.firstname"}; DefaultMessageResolvable dmr = new DefaultMessageResolvable(codes, null); ctx.GetMessage("error.required", new object[] { dmr, "dude!" }, @@ -5482,14 +5512,13 @@ ctx.GetMessage("error.required", program, Spring.Examples.AppContext, that demonstrates usage of these features. - The IMessageSourceAware interface can also - be used to acquire a reference to any - IMessageSource that has been defined. Any object - that is defined in an IApplicationContext that - implements the IMessageSourceAware interface will - be injected with the application context's - IMessageSource when it (the object) is being - created and configured. + The IMessageSourceAware interface can also be + used to acquire a reference to any IMessageSource + that has been defined. Any object that is defined in an + IApplicationContext that implements the + IMessageSourceAware interface will be injected with + the application context's IMessageSource when it (the + object) is being created and configured. @@ -5541,13 +5570,26 @@ ctx.GetMessage("error.required", from a source object of a particular type for which it has matching handler methods. - IApplicationContext implements - this interface and delegates the implementation to an instance of - Spring.Objects.Events.Support.EventRegistry. You - are free to create and use as many EventRegistries as you like but since - it is common to use only one in an application, - IApplicationContext provides convenient access to - a single instance. + + + void Unsubscribe(object subscriber ): + Unsubscribe all events from the source object for which it has + matching handler methods. + + + + void Unsubscribe(object subscriber, Type + targetSourceType ): Unsubscribe all events from a source + object of a particular type for which it has matching handler + methods. + + IApplicationContext implements this + interface and delegates the implementation to an instance of + Spring.Objects.Events.Support.EventRegistry. You are + free to create and use as many EventRegistries as you like but since it + is common to use only one in an application, + IApplicationContext provides convenient access to a + single instance. Within the example/Spring/Spring.Examples.EventRegistry @@ -5567,8 +5609,9 @@ MyEventPublisher publisher = (MyEventPublisher)ctx.GetObject("MyEventPublisher") // Publishes events to the context. ctx.PublishEvents( publisher ); One of the two subscribers subscribes to all events - published to the IApplicationContext instance, - using the publisher type as the filter criteria.// Gets first instance of subscriber + published to the IApplicationContext instance, using + the publisher type as the filter criteria.// Gets first instance of subscriber MyEventSubscriber subscriber = (MyEventSubscriber)ctx.GetObject("MyEventSubscriber"); // Gets second instance of subscriber @@ -5588,23 +5631,21 @@ ctx.Subscribe( subscriber, typeof(MyEventPublisher) ); This Event notification from <literal>IApplicationContext</literal> - Event handling in the IApplicationContext - is provided through the IApplicationListener - interface that contains the single method void - OnApplicationEvent( object source, ApplicationEventArgs - applicationEventArgs ). Classes that implement the - IApplicationListener interface are automatically - registered as a listener with the - IApplicationContext. Publishing an event is done - via the context's PublishEvent( ApplicationEventArgs eventArgs + Event handling in the IApplicationContext is + provided through the IApplicationListener interface + that contains the single method void OnApplicationEvent( object + source, ApplicationEventArgs applicationEventArgs ). Classes + that implement the IApplicationListener interface are + automatically registered as a listener with the + IApplicationContext. Publishing an event is done via + the context's PublishEvent( ApplicationEventArgs eventArgs ) method. This implementation is based on the traditional Observer design pattern. - The event argument type, - ApplicationEventArgs, adds the time of the event - firing as a property. The derived class - ContextEventArgs is used to notify observers on - the lifecycle events of the application context. It contains a property + The event argument type, ApplicationEventArgs, + adds the time of the event firing as a property. The derived class + ContextEventArgs is used to notify observers on the + lifecycle events of the application context. It contains a property ContextEvent Event that returns the enumeration Refreshed or Closed.. The Refreshed enumeration value indicated that the @@ -5620,11 +5661,12 @@ ctx.Subscribe( subscriber, typeof(MyEventPublisher) ); This Implementing custom events can be done as well. Simply call the PublishEvent method on the - IApplicationContext, specifying a parameter which - is an instance of your custom event argument subclass. + IApplicationContext, specifying a parameter which is + an instance of your custom event argument subclass. Let's have a look at an example. First, the - IApplicationContext: <object id="emailer" type="Example.EmailObject"> + IApplicationContext: <object id="emailer" type="Example.EmailObject"> <property name="blackList"> <list> <value>black@list.org</value> @@ -5638,8 +5680,8 @@ ctx.Subscribe( subscriber, typeof(MyEventPublisher) ); This <property name="notificationAddress"> <value>spam@list.org</value> </property> -</object> and then, the actual objects: - public class EmailObject : IApplicationContextAware { +</object> and then, the actual objects: public class EmailObject : IApplicationContextAware { // the blacklist private IList blackList; @@ -5724,8 +5766,8 @@ public class BlackListNotifier : IApplicationListener interface, have already been mentioned. It is worth mentioning again here though, that post-processors are much - more convenient to use in IApplicationContexts - than in plain IObjectFactory instances. In an + more convenient to use in IApplicationContexts than + in plain IObjectFactory instances. In an IApplicationContext, any deployed object which implements the above marker interface is automatically detected and registered as an object post-processor, to be called appropriately at @@ -5754,8 +5796,8 @@ public class BlackListNotifier : IApplicationListener The PropertyPlaceholderConfigurer has already been described in the context of its use within an - IObjectFactory. It is worth mentioning here - though, that it is generally more convenient to use it with an + IObjectFactory. It is worth mentioning here though, + that it is generally more convenient to use it with an IApplicationContext, since the context will automatically recognize and apply any object factory post-processors, such as this one, when they are simply deployed into it like any other @@ -5808,14 +5850,13 @@ ctx.refresh(); The majority of the code inside an application is best written in a Dependency Injection (Inversion of Control) style, where that code is served out of an IObjectFactory or - IApplicationContext container, has its own - dependencies supplied by the container when it is created, and is - completely unaware of the container. However, there is sometimes a need - for singleton (or quasi-singleton) style access to an - IObjectFactory or - IApplicationContext. For example, third party code - may try to construct a new object directly without the ability to force it - to get these objects out of the IObjectFactory. Similarly, nested user + IApplicationContext container, has its own dependencies + supplied by the container when it is created, and is completely unaware of + the container. However, there is sometimes a need for singleton (or + quasi-singleton) style access to an IObjectFactory or + IApplicationContext. For example, third party code may + try to construct a new object directly without the ability to force it to + get these objects out of the IObjectFactory. Similarly, nested user control components in a WinForms application are created inside the generated code in InitializeComponent. If this user control would like to obtain references to objects contained in the container it can use the @@ -5823,16 +5864,16 @@ ctx.refresh(); obtain the object it requires. (Note support for DI in WinForms is under development.) - The Spring.Context.Support.ContextRegistry - class allows you to obtain a reference to an - IApplicationContext via a static locator method. - The ContextRegistry is initialized when creating an + The Spring.Context.Support.ContextRegistry class + allows you to obtain a reference to an + IApplicationContext via a static locator method. The + ContextRegistry is initialized when creating an IApplicationContext through use of the - ContextHandler discussed previously. The simple - static method GetContext() can then be used to retrieve - the context. Alternatively, if you create an - IApplicationContext though other means you can - register it with the ContextRegistry via the method + ContextHandler discussed previously. The simple static + method GetContext() can then be used to retrieve the + context. Alternatively, if you create an + IApplicationContext though other means you can register + it with the ContextRegistry via the method void RegisterContext(IApplicationContext context) in the start-up code of your application. Hierarchical context retrieval is also supported though the use of the GetContext(string @@ -5859,7 +5900,35 @@ ctx.refresh(); will be reread from disk when it is retrieved again. Note that in a web application RefeshSection will not work as advertised and you will need to touch the web.config files to reload a configuration. - - - \ No newline at end of file + + + Stereotype attributes + + Beginning with Spring 1.2, the [Repository] attribute was introduced + as a marker for any class that fulfills the role or stereotype of a + repository (a.k.a. Data Access Object or DAO). Among the possibilities for + leveraging such a marker is the automatic translation of exceptions as + described in Exception + Translation. + + Spring 1.2 introduces further stereotype annotations: [Component] + and [Service]. [Component] serves as a generic stereotype for any + Spring-managed component; whereas, [Repository] and [Service] serve as + specializations of [Component] for more specific use cases (e.g., in the + persistence and service layers, respectively). The ASP.NET MVC + [Controller] attribute will serve this purpose for the controller layer. + What this means is that you can annotate your component classes with + [Component], but by annotating them with [Repository] or [Service] your + classes are more properly suited for processing by tools or associating + with aspects. For example, these stereotype annotations make ideal targets + for pointcuts. Of course, it is also possible that [Repository] and + [Service] may carry additional semantics in future releases of the Spring + Framework. Thus, if you are making a decision between using [Component] or + [Service] for your service layer, [Service] is clearly the better choice. + Similarly, as stated above, [Repository] is already supported as a marker + for automatic exception translation in your persistence layer. The next + version of Spring will use the [Component] attribute to perform attribute + based autowiring by-type as in the Spring Java Framework. + + diff --git a/doc/reference/src/orm.xml b/doc/reference/src/orm.xml index c0d8c111..cbad46ef 100644 --- a/doc/reference/src/orm.xml +++ b/doc/reference/src/orm.xml @@ -16,7 +16,12 @@ * limitations under the License. */ --> - + Object Relational Mapping (ORM) data access
@@ -48,11 +53,11 @@ Ease of testing. Spring's IoC approach makes it easy to swap the implementations and config locations of - Hibernate SessionFactory instances, - ADO.NET DbProvider instances, - transaction managers, and mapper object implementations (if needed). - This makes it much easier to isolate and test each piece of - persistence-related code in isolation. + Hibernate SessionFactory instances, ADO.NET + DbProvider instances, transaction managers, and + mapper object implementations (if needed). This makes it much easier + to isolate and test each piece of persistence-related code in + isolation. @@ -69,21 +74,20 @@ General resource management. Spring application contexts can handle the location and configuration of - Hibernate ISessionFactory instances, - ADO.NET DbProvider instances and other - related resources. This makes these values easy to manage and change. - Spring offers efficient, easy and safe handling of persistence - resources. For example: related code using NHibernate generally needs - to use the same NHibernate Session for - efficiency and proper transaction handling. Spring makes it easy to - transparently create and bind a Session - to the current thread, either by using an explicit 'template' wrapper - class at the code level or by exposing a current - Session through the Hibernate - SessionFactory (for DAOs based on plain - Hibernate 1.2 API). Thus Spring solves many of the issues that - repeatedly arise from typical NHibernate usage, for any transaction - environment (local or distributed). + Hibernate ISessionFactory instances, ADO.NET + DbProvider instances and other related resources. + This makes these values easy to manage and change. Spring offers + efficient, easy and safe handling of persistence resources. For + example: related code using NHibernate generally needs to use the same + NHibernate Session for efficiency and proper + transaction handling. Spring makes it easy to transparently create and + bind a Session to the current thread, either by + using an explicit 'template' wrapper class at the code level or by + exposing a current Session through the Hibernate + SessionFactory (for DAOs based on plain Hibernate + 1.2 API). Thus Spring solves many of the issues that repeatedly arise + from typical NHibernate usage, for any transaction environment (local + or distributed). @@ -157,13 +161,13 @@ for appropriate conversion of specific API exceptions to a common infrastructure exception hierarchy. Spring introduces a DAO exception hierarchy, applicable to any data access strategy. For direct ADO.NET, - the AdoTemplate class mentioned in a previous - section cares for connection handling, and for proper conversion of - ADO.NET data access exceptions (not even singly rooted in .NET 1.1) to - Spring's DataAccessException hierarchy, including - translation of database-specific SQL error codes to meaningful exception - classes. It supports both distributed and local transactions, via - respective Spring transaction managers. + the AdoTemplate class mentioned in a previous section + cares for connection handling, and for proper conversion of ADO.NET data + access exceptions (not even singly rooted in .NET 1.1) to Spring's + DataAccessException hierarchy, including translation + of database-specific SQL error codes to meaningful exception classes. It + supports both distributed and local transactions, via respective Spring + transaction managers. Spring also offers Hibernate support, consisting of a HibernateTemplate analogous to @@ -200,23 +204,22 @@ the other the .NET 2.0 TransactionScope API. The first strategy is encapsulated in the class - Spring.Data.NHibernate.HibernateTransactionManager - in both the Spring.Data.NHibernate - namespace. This strategy is preferred when you are using a - single database. ADO.NET operations can also participate in the same - transaction, either by using AdoTemplate or by retrieving the ADO.NET - connection/transaction object pair stored in thread local storage when - the transaction begins. Refer to the documentation of Spring's ADO.NET - framework for more information on retrieving and using the - connection/transaction pair without using AdoTemplate. You can use the - HibernateTransactionManager and associated classes such as - SessionFactory, HibernateTemplate directly as you would any third party - API, however they are most commonly used through Spring's XML - configuration file to gain the benefits of easy configuration for a - particular runtime environment and as the basis for the configuration of - a data access layer also configured using XML. An XML fragment showing - the declaration of HibernateTransactionManager is - shown below. + Spring.Data.NHibernate.HibernateTransactionManager in + both the Spring.Data.NHibernate namespace. This + strategy is preferred when you are using a single database. ADO.NET + operations can also participate in the same transaction, either by using + AdoTemplate or by retrieving the ADO.NET connection/transaction object + pair stored in thread local storage when the transaction begins. Refer + to the documentation of Spring's ADO.NET framework for more information + on retrieving and using the connection/transaction pair without using + AdoTemplate. You can use the HibernateTransactionManager and associated + classes such as SessionFactory, HibernateTemplate directly as you would + any third party API, however they are most commonly used through + Spring's XML configuration file to gain the benefits of easy + configuration for a particular runtime environment and as the basis for + the configuration of a data access layer also configured using XML. An + XML fragment showing the declaration of + HibernateTransactionManager is shown below. <object id="HibernateTransactionManager" type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate"> @@ -227,17 +230,17 @@ </object> The important property of - HibernateTransactionManager are the references to - the DbProvider and the Hibernate ISessionFactory. For more information - on the DbProvider, refer to the chapter HibernateTransactionManager are the references to the + DbProvider and the Hibernate ISessionFactory. For more information on + the DbProvider, refer to the chapter DbProvider and the following section on SessionFactory set up. The second strategy is to use the class - Sping.Data.TxScopeTransactionManager that uses - .NET 2.0 System.Transaction namespace and its corresponding - TransactionScope API. This is preferred when you are using multiple - transactional resources, such as multiple databases. + Sping.Data.TxScopeTransactionManager that uses .NET + 2.0 System.Transaction namespace and its corresponding TransactionScope + API. This is preferred when you are using multiple transactional + resources, such as multiple databases. Both strategies associate one Hibernate Session for the scope of the transaction (scope in the general demarcation sense, not @@ -264,13 +267,13 @@ To avoid tying application objects to hard-coded resource lookups, Spring allows you to define resources like a DbProvider or a Hibernate - SessionFactory as objects in an - application context. Application objects that need to access resources - just receive references to such pre-defined instances via object - references (the DAO definition in the next section illustrates this). - The following excerpt from an XML application context definition shows - how to set up Spring's ADO.NET DbProvider and a Hibernate - SessionFactory on top of it: + SessionFactory as objects in an application context. + Application objects that need to access resources just receive + references to such pre-defined instances via object references (the DAO + definition in the next section illustrates this). The following excerpt + from an XML application context definition shows how to set up Spring's + ADO.NET DbProvider and a Hibernate SessionFactory on + top of it: <objects xmlns="http://www.springframework.net" xmlns:db="http://www.springframework.net/database"> @@ -352,9 +355,9 @@ - Delegate to the DbProvider itself as - the NHibernate connection provider instead of listing it via - property hibernate.connection.provider via + Delegate to the DbProvider itself as the + NHibernate connection provider instead of listing it via property + hibernate.connection.provider via HibernateProperties. @@ -364,8 +367,8 @@ hibernate.connection.provider is used and a warning level message is logged. If you use Spring's DbProvider as the NHibernate connection provider then you can take advantage of - IDbProvider implementations that will let you - change the connection string at runtime such as IDbProvider implementations that will let you change + the connection string at runtime such as UserCredentialsDbProvider and MultiDelegatingDbProvider. @@ -377,20 +380,19 @@ linkend="dbprovider-multidelegating">MultiDelegatingDbProvider only change the connection string at runtime based on values in thread local storage and do not clear out the Hibernate cache that is unique - to each ISessionFactory instance. As such, they - are only useful for selecting at runtime a single database instance. + to each ISessionFactory instance. As such, they are + only useful for selecting at runtime a single database instance. Cleaning up an existing session factory when switching to a new database is left to user code. Creating a new session factory per connection string (assuming the same mapping files can be used across all databases connections) is not currently supported. To support this functionality, you can subclass - LocalSessionFactoryObject and override the - method ISessionFactory NewSessionFactory(Configuration + LocalSessionFactoryObject and override the method + ISessionFactory NewSessionFactory(Configuration config) so that it returns an implementation of ISessionFactory that selects among multiple instances based on values in thread local storage, much like the - implementation of - MultiDelegatingDbProvider. + implementation of MultiDelegatingDbProvider.
@@ -401,13 +403,12 @@ methods that can be part of any custom data access object or business service. There are no restrictions on the implementation of the surrounding object at all, it just needs to provide a Hibernate - SessionFactory. It can get the latter - from anywhere, but preferably as an object reference from a Spring IoC - container - via a simple SessionFactory - property setter. The following snippets show a DAO definition in a - Spring container, referencing the above defined - SessionFactory, and an example for a DAO - method implementation.
+ SessionFactory. It can get the latter from anywhere, + but preferably as an object reference from a Spring IoC container - via + a simple SessionFactory property setter. The + following snippets show a DAO definition in a Spring container, + referencing the above defined SessionFactory, and an + example for a DAO method implementation.
<objects> @@ -437,11 +438,11 @@ The HibernateTemplate class provides many methods that mirror the methods exposed on the Hibernate - Session interface, in addition to a - number of convenience methods such as the one shown above. If you need - access to the Session to invoke methods - that are not exposed on the HibernateTemplate, - you can always drop down to a callback-based approach like so. + Session interface, in addition to a number of + convenience methods such as the one shown above. If you need access to + the Session to invoke methods that are not exposed on + the HibernateTemplate, you can always drop down to a + callback-based approach like so. public class HibernateCustomerDao : ICustomerDao { @@ -483,20 +484,20 @@ inside the anonymous delegate implementation. A callback implementation effectively can be used for any - Hibernate data access. HibernateTemplate will - ensure that Session instances are - properly opened and closed, and automatically participate in - transactions. The template instances are thread-safe and reusable, they - can thus be kept as instance variables of the surrounding class. For - simple single step actions like a single Find, Load, SaveOrUpdate, or - Delete call, HibernateTemplate offers alternative - convenience methods that can replace such one line callback - implementations. Furthermore, Spring provides a convenient + Hibernate data access. HibernateTemplate will ensure + that Session instances are properly opened and + closed, and automatically participate in transactions. The template + instances are thread-safe and reusable, they can thus be kept as + instance variables of the surrounding class. For simple single step + actions like a single Find, Load, SaveOrUpdate, or Delete call, + HibernateTemplate offers alternative convenience + methods that can replace such one line callback implementations. + Furthermore, Spring provides a convenient HibernateDaoSupport base class that provides a SessionFactory property for receiving a - SessionFactory and for use by subclasses. - In combination, this allows for very simple DAO implementations for - typical requirements: + SessionFactory and for use by subclasses. In + combination, this allows for very simple DAO implementations for typical + requirements: public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao { @@ -512,22 +513,21 @@ Implementing Spring-based DAOs without callbacks As an alternative to using Spring's - HibernateTemplate to implement DAOs, data access - code can also be written in a more traditional fashion, without wrapping - the Hibernate access code in a callback, while still respecting and - participating in Spring's generic - DataAccessException hierarchy. The - HibernateDaoSupport base class offers methods to - access the current transactional Session + HibernateTemplate to implement DAOs, data access code + can also be written in a more traditional fashion, without wrapping the + Hibernate access code in a callback, while still respecting and + participating in Spring's generic DataAccessException + hierarchy. The HibernateDaoSupport base class offers + methods to access the current transactional Session and to convert exceptions in such a scenario; similar methods are also available as static helpers on the - SessionFactoryUtils class. Note that such code - will usually pass 'false' as the value of the + SessionFactoryUtils class. Note that such code will + usually pass 'false' as the value of the DoGetSession(..) method's 'allowCreate' argument, to enforce running within a transaction (which avoids the need to close the returned - Session, as its lifecycle is managed by - the transaction). Asking for the + Session, as its lifecycle is managed by the + transaction). Asking for the public class HibernateProductDao extends HibernateDaoSupport implements ProductDao { @@ -540,20 +540,19 @@ } } - This code will not translate the Hibernate exception to a generic - DataAccessException. + This code will not translate the Hibernate + exception to a generic DataAccessException.
- Implementing DAOs based on plain Hibernate 1.2 API + Implementing DAOs based on plain Hibernate 1.2/2.0 API Hibernate 1.2 introduced a feature called "contextual Sessions", - where Hibernate itself manages one current - ISession per transaction. This is roughly - equivalent to Spring's synchronization of one Hibernate - Session per transaction. A corresponding - DAO implementation looks like as follows, based on the plain Hibernate - API: + where Hibernate itself manages one current ISession + per transaction. This is roughly equivalent to Spring's synchronization + of one Hibernate Session per transaction. A + corresponding DAO implementation looks like as follows, based on the + plain Hibernate API: public class ProductDaoImpl implements IProductDao { @@ -592,8 +591,8 @@ public class HibernateCustomerDao : ICustomerDao { The above DAO follows the Dependency Injection pattern: it fits nicely into a Spring IoC container, just like it would if coded against - Spring's HibernateTemplate. Of course, such a DAO - can also be set up in plain C# (for example, in unit tests): simply + Spring's HibernateTemplate. Of course, such a DAO can + also be set up in plain C# (for example, in unit tests): simply instantiate it and call SessionFactory property with the desired factory reference. As a Spring object definition, it would look as follows: @@ -651,26 +650,72 @@ public class HibernateCustomerDao : ICustomerDao { of course appealing from a non-invasiveness perspective, and will no doubt feel more natural to Hibernate developers. - However, the DAO throws plain - HibernateException which means that callers can - only treat exceptions as generally fatal - unless they want to depend on - Hibernate's own exception hierarchy. Catching specific causes such as an - optimistic locking failure is not possible without tying the caller to - the implementation strategy. This trade off might be acceptable to - applications that are strongly Hibernate-based and/or do not need any - special exception treatment. +
+ Exception Translation - Fortunately, Spring's - LocalSessionFactoryObject supports Hibernate's - SessionFactory.GetCurrentSession() method for - any Spring transaction strategy, returning the current Spring-managed - transactional Session even with - HibernateTransactionManager. + However, the DAO implemenation as shown throws plain + HibernateException which means that callers can + only treat exceptions as generally fatal - unless they want to depend + on Hibernate's own exception hierarchy. Catching specific causes such + as an optimistic locking failure is not possible without tying the + caller to the implementation strategy. This trade off might be + acceptable to applications that are strongly Hibernate-based and/or do + not need any special exception treatment. As an alternative you can + use Spring's exception translation advice to convert the NHibernate + exception to Spring's DataAccessException hierarchy. - In summary: DAOs can be implemented based on the plain Hibernate - 1.2 API, while still being able to participate in Spring-managed - transactions. In this approach there is one session associated with the - transaction. + Spring offers a solution allowing exception translation to be + applied transparently through the [Repository] + attribute: + + [Repository] +public class HibernateCustomerDao : ICustomerDao { + + // class body here + +} + + and register an exception translation post processor. + + <objects> + + <!-- configure session factory (omittied for brevity) --> + + <!-- Exception translation object post processor --> + <object type="Spring.Dao.Attributes.PersistenceExceptionTranslationPostProcessor, Spring.Data"/> + + <!-- Same DAO configuration as before --> + <object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate"> + <property name="sessionFactory" ref="MySessionFactory"/> + </object> + +</objects> + + The postprocessor will automatically look for all exception + translators (implementations of the + IPersistenceExceptionTranslator interface) and + advise all object marked with the [Repository] + attribute so that the discovered translators can intercept and apply + the appropriate translation on the thrown exceptions. Spring's + LocalSessionFactory object implements the + IPersistenceExceptionTranslator interface and + performs the same exception translation as was done when using + HibernateTemplate. + + The [Repository] attribute is definedin the + Spring.Data assembly, however it is used as a 'marker' attribute, and + you can provide your own if you would like to avoid coupling your DAO + implementation to a Spring attribute. This is done by setting + PersistenceExceptionTranslationPostProcessor's + property RepositoryAttributeType to your own + attribute type. + + + In summary: DAOs can be implemented based on the plain + Hibernate 1.2/2.0 API, while still being able to participate in + Spring-managed transactions and exception translation. + +
@@ -680,10 +725,10 @@ public class HibernateCustomerDao : ICustomerDao { application, on top of such lower-level data access services spanning any number of operations. There are no restrictions on the implementation of the surrounding business service here as well, it just - needs a Spring PlatformTransactionManager. Again, - the latter can come from anywhere, but preferably as an object reference - via a TransactionManager property - just like - the productDAO should be set via a + needs a Spring PlatformTransactionManager. Again, the + latter can come from anywhere, but preferably as an object reference via + a TransactionManager property - just like the + productDAO should be set via a setProductDao(..) method. The following snippets show a transaction manager and a business service definition in a Spring application context, and an example for a business method @@ -691,7 +736,23 @@ public class HibernateCustomerDao : ICustomerDao { <objects> -TO BE DONE + <object id="HibernateTransactionManager" + type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate"> + + <property name="DbProvider" ref="DbProvider"/> + <property name="SessionFactory" ref="MySessionFactory"/> + + </object> + + <!-- DAO definition not listed, see above for an example. --> + + <object id="FulfillmentService" type="Spring.Northwind.Service.FulfillmentService, Spring.Northwind.Service"> + <property name="CustomerDao" ref="CustomerDao"/> + <property name="OrderDao" ref="OrderDao"/> + <property name="ShippingService" ref="ShippingService"/> + <property name="TransactionManager" ref="HibernateTransactionManager"/> + </object> + </objects> @@ -707,9 +768,35 @@ TO BE DONE private IShippingService shippingService; + + public TransactionManager TransactionManager + { + set { transactionTemplate = new TransactionTemplate(value); + } public void ProcessCustomer(string customerId) { - TO BE DONE + tt.Execute(delegate(ITransactionStatus status) + { + //Find all orders for customer + Customer customer = CustomerDao.FindById(customerId); + foreach (Order order in customer.Orders) + { + //Validate Order + Validate(order); + + //Ship with external shipping service + ShippingService.ShipOrder(order); + + //Update shipping date + order.ShippedDate = DateTime.Now; + + //Update shipment date + OrderDao.SaveOrUpdate(order); + + //Other operations...Decrease product quantity... etc + } + return null; + }); } }
@@ -846,19 +933,17 @@ TO BE DONE Transaction management strategies Both TransactionTemplate and - TransactionInterceptor (not yet seen explicitly - in above configuration, TransactionProxyFactoryObject uses a + TransactionInterceptor (not yet seen explicitly in + above configuration, TransactionProxyFactoryObject uses a TransactionInterceptor, you would have to specify it explicitly if you were using an ordinary ProxyFactoryObject.) delegate the actual - transaction handling to a - PlatformTransactionManager instance, which can be - a HibernateTransactionManager (for a single - Hibernate SessionFactory, using a - ThreadLocal - Session under the hood) or a - TxScopeTransactionManager (delegating to MS-DTC - for distributed transaction) for Hibernate applications. You could even - use a custom PlatformTransactionManager + transaction handling to a PlatformTransactionManager + instance, which can be a HibernateTransactionManager + (for a single Hibernate SessionFactory, using a + ThreadLocal Session under the + hood) or a TxScopeTransactionManager (delegating to + MS-DTC for distributed transaction) for Hibernate applications. You + could even use a custom PlatformTransactionManager implementation. So switching from native Hibernate transaction management to TxScopeTransactionManager, such as when facing distributed transaction requirements for certain deployments of your application, is @@ -868,22 +953,20 @@ TO BE DONE as they just use the generic transaction management APIs. For distributed transactions across multiple Hibernate session - factories, simply combine - TxScopeTransactionManager as a transaction - strategy with multiple LocalSessionFactoryObject - definitions. Each of your DAOs then gets one specific - SessionFactory reference passed into it's - respective object property. + factories, simply combine TxScopeTransactionManager + as a transaction strategy with multiple + LocalSessionFactoryObject definitions. Each of your + DAOs then gets one specific SessionFactory reference + passed into it's respective object property. TO BE DONE HibernateTransactionManager can export the - ADO.NET Transaction used by Hibernate to - plain ADO.NET access code, for a specific - DbProvider. (matching connection string). - This allows for high-level transaction demarcation with mixed - Hibernate/ADO.NET data access! + ADO.NET Transaction used by Hibernate to plain + ADO.NET access code, for a specific DbProvider. + (matching connection string). This allows for high-level transaction + demarcation with mixed Hibernate/ADO.NET data access!
@@ -962,4 +1045,4 @@ TO BE DONE this chapter for further information on those usage scenarios.
- \ No newline at end of file + diff --git a/doc/reference/src/wcf.xml b/doc/reference/src/wcf.xml index 4e21949e..eff105dd 100644 --- a/doc/reference/src/wcf.xml +++ b/doc/reference/src/wcf.xml @@ -16,7 +16,12 @@ * limitations under the License. */ --> - + Windows Communication Foundation (WCF)
@@ -26,19 +31,6 @@ dependency injection and add additional behavior to them using Aspect-Oriented programming (AOP). - There are two approaches in the 1.2 M1 release for configuring your - services with DI which are discussed in the following sections. One - approach creates an implementation of your service interface (a dynamic - proxy) that retrieves a configured instance of your service type from the - Spring container. This dynamic proxy is then the final service type that - is hosted. The second approach uses the extension points in WCF itself to - delegate to the Spring container to create and configure your service - type. Both approaches are discussed below. - - As it is desirable to have just one approach, we would greatly - appreciate your input regarding these two approaches as well as any other - suggestions regarding WCF support. - For those who would like to get their feet wet right way, check out the WcfQuickStart application in the examples directory.
@@ -117,18 +109,17 @@ To host this service type in a standalone application define an instance of a Spring.ServiceModel.Activation.ServiceHostFactoryObject - and set is property TargetName to the id value of - the previously defined service type. + and set is property TargetName to the id value of the + previously defined service type. ServiceHostFactoryObject is a Spring IFactoryObject implementation. (See here for more - information on IFactoryObjects and their - interaction with the container.) The - ServiceHostFactoryObject will create an instance - of - Spring.ServiceModel.Activation.SpringServiceHost - that will be the ServiceHost instance associated with your service type. - This configuration for this step is shown below. + information on IFactoryObjects and their interaction + with the container.) The ServiceHostFactoryObject + will create an instance of + Spring.ServiceModel.Activation.SpringServiceHost that + will be the ServiceHost instance associated with your service type. This + configuration for this step is shown below. <object id="calculatorServiceHost" type="Spring.ServiceModel.Activation.ServiceHostFactoryObject, Spring.Services"> <property name="TargetName" value="calculator" /> @@ -155,21 +146,21 @@ Spring.ServiceModel.Activation.SpringServiceHost - is where the dynamic proxy for your service type is - generated. This dynamic proxy will implement a single 'WCF' interface, - the same on that your service type implements. The implementation of the - service interface methods on the proxy will delegate to a wrapped - 'target' object which is the object instance retrieved by name from the - Spring container using the Spring API, - ApplicationContext.GetObject(name). Since the - object retrieved in this manner is fully configured, your WCF service is - as well. + is where the dynamic proxy for your service type is generated. + This dynamic proxy will implement a single 'WCF' interface, the same on + that your service type implements. The implementation of the service + interface methods on the proxy will delegate to a wrapped 'target' + object which is the object instance retrieved by name from the Spring + container using the Spring API, + ApplicationContext.GetObject(name). Since the object + retrieved in this manner is fully configured, your WCF service is as + well. Outside of a standalone application you can also use the class Spring.ServiceModel.Activation.ServiceHostFactory (which inherits from - System.ServiceModel.Activation.ServiceHostFactory) - to host your services so that they can be configured via dependency + System.ServiceModel.Activation.ServiceHostFactory) to + host your services so that they can be configured via dependency injection. To use the dynamic proxy approached described here you should still refer to the name of the service as the name of the object definition used to configure the service type in the Spring @@ -179,75 +170,10 @@ need to specify the service name as the name of the object definition in the Spring container and to ensure that singleton=false is used in the object definition. You can also use - Spring.ServiceModel.Activation.ServiceHostFactory - to host your service inside IIS but should still refer to the service by + Spring.ServiceModel.Activation.ServiceHostFactory to + host your service inside IIS but should still refer to the service by the name of the object in the Spring container. - -
- Dependency Injection using WCF extensibility points. - - The second approach uses the extensibility points in WCF itself to - delegate to Spring to create and configure your WCF service. This - approach was first taken (afaik) by Oran Dennison on his blog - and several other folks on the web since then. In this approach Spring - specific implementations of the WCF interfaces - System.ServiceModel.Dispatcher.IInstanceProvider - and - System.ServiceModel.Description.IServiceBehavior - are used to integrate Spring directly into the instancing of WCF - services. - - Spring's implementation of - IInstanceProvider is - Spring.ServiceModel.Support.SpringInstanceProvider. - This implementation will look for an object by type in the Spring - container and retrieve an instance configured using DI. If there is more - than one object of the type registered with the container than an - exception will be thrown. The - SpringInstanceProvider is used by a custom - service behavior class, - Spring.ServiceModel.Support.SpringServiceBehavior - where it is applied to all the service endpoints. This behavior is then - added to the custom service host - Spring.ServiceModel.Activation.SpringServiceHost - - The service type is used to locate the object in the container. In - your .svc file you specify the custom service host type and also the - type of the service. Here is an example taken from the WcfQuickStart - application that shows the use of this approach inside IIS. - - <%@ ServiceHost Language="C#" Debug="true" Service="Spring.WcfQuickStart.CalculatorService" - Factory="Spring.ServiceModel.Activation.ServiceHostFactory" %> - - - The Spring configuration for the object is shown below. - - <object id="calculator" type="Spring.WcfQuickStart.CalculatorService, App_Code" singleton="false"> - <property name="SleepInSeconds" value="1"/> - </object> - - - The object must be declared as a 'prototype' object, i.e. not a - singleton, in order to interact correctly with WCF instancing. - - - While integrating 'natively' with WCF does seem to be the most - natural approach there is one 'gotya' that needs to be investigated - further to see if there is an acceptable workaround in order for this - approach to be viable. The issue is that if the service is configured to - be a singleton, for example using - [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] - then the invocation of the IInstanceProvider is - short-circuited. See the notes on the MSDN class documentation here. - One workaround, which is not very appealing, is to use the PerCall - instancing mode but set the singleton attribute in the Spring - configuration to true, this way the same instance is always - returned. -
@@ -257,8 +183,8 @@ additional AOP advice to your WCF services in the same way as you have always done in Spring. The following configuration shows how to apply some simple performance monitoring advice to all services in the - Spring.WcfQuickStart namespace and is taken from - the QuickStart example. + Spring.WcfQuickStart namespace and is taken from the + QuickStart example. <object id="serviceOperation" type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop"> <property name="pattern" value="Spring.WcfQuickStart.*"/> @@ -299,7 +225,7 @@ </object> - This will be shortened using a custom namespce in the 1.2 RC1 + This will be shortened using a custom namespce in the 1.2 final release @@ -307,4 +233,44 @@ enpoints in the <client> section of the standard WCF configuration inside of App.config.
-
\ No newline at end of file + +
+ Exporting PONOs as WCF Services + + Much like the approach taken for .asmx web services Spring provides + an exporter that will add [ServiceContract] and + [OperationContract] attributes by default to all public + interface methods on a given (PONO) class. The exporter class is + Spring.ServiceModel.ServiceExporter and has various + options to fine-tune what interfaces are exported and the specific + attributes that get applied to each method and on that class. Here is a + simple example + + <object id="HelloWorldExporter" type="Spring.ServiceModel.ServiceExporter, Spring.Services"> + <property name="TargetName" value="HelloWorld"/> + <property name="MemberAttributes"> + <dictionary> + <entry key="SayHelloWorld"> + <object type="System.ServiceModel.OperationContractAttribute, System.ServiceModel"> + <property name="IsOneWay" value="false"/> + <!-- configure any other OperationContractAttribute properties here --> + </object> + </entry> + </dictionary> + </property> +</object> + + Spring does not provide any means to add + [DataContract] or [DataMember] attributes to + method arguments of your service operations. As such, either you will do + that yourself or you may choose to use a serializer other than + DataContractSerializer, for example one that relies on method arguments + that implement the ISerializable interface, having the + [Serializable] attribute, or are serializable via the + XmlSerializer. Use the latter serializers is a good way to migrate from an + existing RCP based approach, such as using .NET remoting, to WCF in order + to take advantage of the WCF runtime and avoid editing much existing code. + You can then incrementally refactor and/or create new operations that use + DataContractSerializer. +
+
diff --git a/doc/reference/src/web.xml b/doc/reference/src/web.xml index a123cc48..fdb9aa71 100644 --- a/doc/reference/src/web.xml +++ b/doc/reference/src/web.xml @@ -16,12 +16,135 @@ * limitations under the License. */ --> - + Spring.NET Web Framework Introduction + Spring.NET's web application framework aims to increase your + productivity writing ASP.NET WebForms applications. It offers a unique + value proposition to creating ASP.NET applications not found in other .NET + web framework. + + The goal of the framework is to make it easy to write 'thin and + clean' web applications. By thin, what is meant is that the WebForm's + responsibility is to act as adapter between the HTML based world of the + web and the oo world of your application. The application layer your web + form communicates with is where the business logic resides, not in the web + tier. By 'clean' what is meant that the web framework should have a good + separation of concerns, leading ideally to an event-handler that does not + contain any reference to UI elements. This makes it possible to test your + event handler code in integration style tests. Last but not least, + Spring's web framework reduces the incidental complexity of common tasks + in the web tier, for example the conversion of HTML control data to object + and then vice-versa after the request has been processed by the + application layer. + + Highlights of Spring's Web framework are + + + + Dependency Injection for all + ASP.NET artifacts. This includes pages and user controls but also + modules, providers and HTTP handlers. Your pages, controls, etc., do + not have any Spring dependencies in order to be configured via + dependency injection. + + + + Bi-directional data + binding. This allows you to declaratively define the data that + will be marshaled out of your html/user controls and into a data model + that in turn is generally submitted to the application layer. After + the data model is updated in the application layer, those changes are + automatically reflected in the html/user controls on post back. This + removes large amounts of tedious, error prone boilerplate code. + + + + Web object scopes. Object + definitions can be defined at the application, session or request + scope. This makes it easy to inject, say a session scoped shopping + cart, into your page without having to do any lower level + programming + + + + Data Model Management. + While ASP.NET managed the view state of your form, it does not offer + facilities to manage the data model that you build up to submit to the + application layer. Spring provides a mechanism similar to view state + to help manage your data model. + + + + UI agnostic validation + framework. Declaratively define complex validation rules, for + example that take into account complex relationships in your data + model. Error controls are provided to easily render validation + failure. This allows you to centralize your validation logic and also + reuse it on the server side, for example using parameter validation + advice described in the aspect library chapter + + + + Externalized page navigation + through 'result mapping'. Instead of hard coding urls and data + to direct where a page should go next, result mappings are externally + defined and configured that associate logical names and a URL (+ + data). This also allows to encryption of values that are sent via + Response.Redirect. + + + + Improved localization + and master page support - Advanced localization features (including + image localization) as well as declarative configuration of what mater + page to apply to different parts of your web application are easy to + perform. + + + + + + All you know about ASP.NET development still applies, Spring's + approach is to 'embrace and extend' the basic ASP.NET programming model so + you can be as productive as possible. + + + Support for ASP.NET MVC is planned for Spring.NET 2.0 and previews + of our integration with the MVC framework will be mode available when + the final MVC framework ships. + + + What follows is a more detailed background and motivation of + features and most importantly the detailed reference manual for using + Spring's web framework. One of the great things about the framework is + that it is not an all or nothing solution. If you choose to use only + dependency injection and bi-directional data binding, that is just fine. + You can incrementally adopt the web framework, addressing problems areas + in your current web application with a specific feature. There is no need + to go 'whole hog' into using all parts of the framework everywhere in your + application. + + The Spring.NET distribution ships with a number of Web QuickStarts + and a complete reference application, SpringAir. Web QuickStarts are the + best way to learn each Spring.Web feature by following simple examples, + and the SpringAir reference application has a Spring.Web-enabled frontend + which uses many best practices for Spring.NET web applications, so please + do refer to it as you are reading this (reference) material (see ). + + + + Background + One of the objections many developers have to the ASP.NET programming model is that it is not a "true MVC" (Model-View-Controller) implementation, because controller-type logic within the page is too @@ -60,13 +183,11 @@ transliterated to help developers be more productive when using the upcoming ASP.NET MVC support. - - Spring.Web also adds support for applying the dependency injection principle to one's ASP.NET Pages and - Controls as well as http modules and custom - provider modules. This means that application developers can easily inject - service dependencies into web controllers by leveraging the power of the + Controls as well as http modules and custom provider + modules. This means that application developers can easily inject service + dependencies into web controllers by leveraging the power of the Spring.NET IoC container. See Dependency Injection for ASP.NET Pages for more information. @@ -74,41 +195,40 @@ should not have to deal with ASP.NET UI controls directly. Such event handlers should rather work with the presentation model of the page, represented either as a hierarchy of domain objects or an ADO.NET - DataSet. It is for that reason that the Spring.NET - team implemented bidirectional data binding framework to handle the - mapping of values to and from the controls on a page to the underlying - data model. The data binding framework also transparently takes care of - data type conversion and formatting, enabling application developers to - work with fully typed data (domain) objects in the event handlers of - code-behind files. See Bidirectional Data - Binding and Model Management for more information. + DataSet. It is for that reason that the Spring.NET team + implemented bidirectional data binding framework to handle the mapping of + values to and from the controls on a page to the underlying data model. + The data binding framework also transparently takes care of data type + conversion and formatting, enabling application developers to work with + fully typed data (domain) objects in the event handlers of code-behind + files. See Bidirectional Data Binding and + Model Management for more information. The flow of control through an application is another area of concern that is addressed by Spring.NET Web Framework. Typical ASP.NET applications will use Response.Redirect or - Server.Transfer calls within - Page logic to navigate to an appropriate page after - an action is executed. This typically leads to hard-coded target URLs in - the Page, which is never a good thing. Result - mapping solves this problem by allowing application developers to specify - aliases for action results that map to target URLs based on information in - an external configuration file that can easily be edited. Under - consideration for future releases of Spring.NET is a process management - framework, which will take this approach to another level, allowing you to - control complex page flows in a very simple way. See Result Mapping for more - information. + Server.Transfer calls within Page + logic to navigate to an appropriate page after an action is executed. This + typically leads to hard-coded target URLs in the Page, + which is never a good thing. Result mapping solves this problem by + allowing application developers to specify aliases for action results that + map to target URLs based on information in an external configuration file + that can easily be edited. Under consideration for future releases of + Spring.NET is a process management framework, which will take this + approach to another level, allowing you to control complex page flows in a + very simple way. See Result + Mapping for more information. Standard localization support is also limited in versions of ASP.NET prior to ASP.NET 2.0. Even though Visual Studio 2003 generates a local - resource file for each ASP.NET Page and user - control, those resources are never used by the ASP.NET infrastructure. - This means that application developers have to deal directly with resource - managers whenever they need access to localized resources, which in the - opinion of the Spring.NET team should not be the case. Spring.NET's Web - Framework (hereafter referred to as Spring.Web) adds comprehensive support - for localization using both local resource files and global resources that - are configured within and for a Spring.NET container. See Page and user control, + those resources are never used by the ASP.NET infrastructure. This means + that application developers have to deal directly with resource managers + whenever they need access to localized resources, which in the opinion of + the Spring.NET team should not be the case. Spring.NET's Web Framework + (hereafter referred to as Spring.Web) adds comprehensive support for + localization using both local resource files and global resources that are + configured within and for a Spring.NET container. See Localization and Message Sources for more information. @@ -124,27 +244,18 @@ In order to implement some of the above mentioned features the Spring.NET team had to extend (as in the object-oriented sense) the standard ASP.NET Page and - UserControl classes. This means that in order to - take advantage of the full feature stack of - Spring.Web (most notably bidirectional data binding, localization and - result mapping), your code-behind classes will have to extend Spring.Web - specific base classes such as Spring.Web.UI.Page; - however, some very powerful features such as dependency injection for - ASP.NET Pages, Controls, and providers can be leveraged without having to - extend Spring.Web-specific base classes. It is worth stating that by - taking advantage of some of the more useful features - offered by Spring.Web you will be coupling the presentation tier of your + UserControl classes. This means that in order to take + advantage of the full feature stack of Spring.Web + (most notably bidirectional data binding, localization and result + mapping), your code-behind classes will have to extend Spring.Web specific + base classes such as Spring.Web.UI.Page; however, some + very powerful features such as dependency injection for ASP.NET Pages, + Controls, and providers can be leveraged without having to extend + Spring.Web-specific base classes. It is worth stating that by taking + advantage of some of the more useful features offered + by Spring.Web you will be coupling the presentation tier of your application(s) to Spring.Web. The choice of whether or not this is appropriate is, of course, left to you. - - Finally, please be aware that the standard Spring.NET distribution - (as of v1.1) ships with a number of Web QuickStarts and a complete - reference application, SpringAir. Web QuickStarts are the best way to - learn each Spring.Web feature by following simple examples, and the - SpringAir reference application has a Spring.Web-enabled frontend which - uses many best practices for Spring.NET web applications, so please do - refer to it as you are reading this (reference) material (see ). @@ -159,13 +270,12 @@ means that all of the controllers (ASP.NET Pages) that make up a typical Spring.Web enabled application will be configured using the same standard Spring.NET XML configuration syntax. Spring.Web - uses a custom PageHandlerFactory implementation - to load and configure a Spring.NET IoC container, which is in turn used - to locate an appropriate Page to handle a HTTP - request. The WebSupportModule configures - miscellaneous Spring infrastructure classes for use in a web - environment, for example setting the storage strategy of - LogicalThreadContext to be + uses a custom PageHandlerFactory implementation to + load and configure a Spring.NET IoC container, which is in turn used to + locate an appropriate Page to handle a HTTP request. + The WebSupportModule configures miscellaneous Spring + infrastructure classes for use in a web environment, for example setting + the storage strategy of LogicalThreadContext to be HybridContextStorage. The instantiation and configuration of the Spring.NET IoC @@ -202,8 +312,8 @@ infrastructure to use Spring.NET's page factory, which will in turn create instances of the appropriate .aspx Page, (possibly) inject dependencies into said - Page (as required), and then forward the handling - of the request to said Page. + Page (as required), and then forward the handling of + the request to said Page. After the Spring.Web page factory is configured, you will also need to define a root application context by adding a Spring.NET @@ -265,8 +375,8 @@ The custom configuration section handler is of the type - Spring.Context.Support.WebContextHandler - which will in turn instantiate an IoC container of the type + Spring.Context.Support.WebContextHandler which + will in turn instantiate an IoC container of the type Spring.Context.Support.WebApplicationContext. This will ensure that all of the features provided by Spring.Web are handled properly (such as request and session-scoped object @@ -410,8 +520,8 @@ Spring.Web builds on top of the feature set and capabilities of ASP.NET; one example of this can be seen the way that Spring.Web has used - the code-behind class of the Page mechanism to - satisfy the Controller portion of the MVC architectural + the code-behind class of the Page mechanism to satisfy + the Controller portion of the MVC architectural pattern. In MVC-based (web) applications, the Controller is typically a thin wrapper around one or more service objects. In the specific case of Spring.Web, the Spring.NET @@ -419,12 +529,11 @@ be easily injected into Page Controllers. Accordingly, Spring.Web provides first class support for dependency injection in ASP.NET - Pages. This allows application developers to inject - any required service object dependencies (and indeed any other - dependencies) into their Pages using standard - Spring.NET configuration instead of having to rely on custom service - locators or manual object lookups in a Spring.NET application - context. + Pages. This allows application developers to inject any + required service object dependencies (and indeed any other dependencies) + into their Pages using standard Spring.NET + configuration instead of having to rely on custom service locators or + manual object lookups in a Spring.NET application context. Once an application developer has configured the Spring.NET web @@ -476,15 +585,14 @@ pages from the configuration of other .NET classes is in the value passed to the type attribute. As can be seen in the above configuration snippet the type name is actually the - path to the .aspx file for the - Page, relative to the directory context it is - defined in. In the case of the above example, those definitions are in the - root context so Login.aspx and - Default.aspx also must be in the root of the web - application's virtual directory. The master page is defined using an - absolute path because it could conceivably be referenced from child - contexts that are defined within subdirectories of the web - application. + path to the .aspx file for the Page, + relative to the directory context it is defined in. In the case of the + above example, those definitions are in the root context so + Login.aspx and Default.aspx also + must be in the root of the web application's virtual directory. The master + page is defined using an absolute path because it could conceivably be + referenced from child contexts that are defined within subdirectories of + the web application. The astute reader may have noticed that the definitions for the Login and Default pages don't @@ -493,13 +601,13 @@ Spring.NET, where the id or name attributes are typically mandatory (although not always, as in the case of inner object definitions). This is actually intentional, because in the - case of Spring.Web Page - Controller instances one typically wants to use the - name of the .aspx file name as the identifier. If an + case of Spring.Web Page Controller + instances one typically wants to use the name of the + .aspx file name as the identifier. If an id is not specified, the Spring.Web infrastructure will simply use the name of the .aspx file as the object identifier (minus any leading path information, and minus the file - extension too). + extension too). Nothing prevents an application developer from specifying an id or name value explicitly; one use @@ -536,10 +644,10 @@ You can perform dependency injection on custom HTTP modules through the use of the class - Spring.Context.Support.HttpApplicationConfigurer. - You register your custom HTTP module as you would normally, for example - a module of the type HtmlCommentAppenderModule, - taken from the Web Quickstart, appends additional comments into the http + Spring.Context.Support.HttpApplicationConfigurer. You + register your custom HTTP module as you would normally, for example a + module of the type HtmlCommentAppenderModule, taken + from the Web Quickstart, appends additional comments into the http response. It is registered as shown below <httpModules> @@ -706,7 +814,7 @@ class MyControl : Control, ISupportsWebDependencyInjection - Object Scope + Web object scopes Spring.NET web applications support an additional attribute within object definition elements that allows you to control the scope of an @@ -822,8 +930,8 @@ class MyControl : Control, ISupportsWebDependencyInjection using the default content supplied in the master page. Both the ContentPlaceHolder and - Content controls can contain any valid ASP.NET - markup: HTML, standard ASP.NET controls, user controls, etc. + Content controls can contain any valid ASP.NET markup: + HTML, standard ASP.NET controls, user controls, etc. VS.NET 2003 issue @@ -840,9 +948,9 @@ class MyControl : Control, ISupportsWebDependencyInjection Linking child pages to their master - The Spring.Web.UI.Page class exposes a - property called MasterPageFile, which can be used to - specify the master page. + The Spring.Web.UI.Page class exposes a property + called MasterPageFile, which can be used to specify + the master page. The recommended way to do this is by leveraging the Spring.NET IoC container and creating definitions similar to the following: @@ -905,7 +1013,8 @@ class MyControl : Control, ISupportsWebDependencyInjection management methods: InitializeModel, LoadModel and SaveModel. This is perhaps best illustrated by an example from the SpringAir reference - application. First, let's take a look at the page markup:<%@ Page Language="c#" Inherits="TripForm" CodeFile="TripForm.aspx.cs" %> + application. First, let's take a look at the page markup:<%@ Page Language="c#" Inherits="TripForm" CodeFile="TripForm.aspx.cs" %> <asp:Content ID="body" ContentPlaceHolderID="body" runat="server"> <div style="text-align: center"> @@ -1053,8 +1162,8 @@ class MyControl : Control, ISupportsWebDependencyInjection TripPoint class to represent departure and return, which are exposed as StartingFrom and ReturningFrom properties. It also uses - TripMode enumeration to specify whether the trip is - one way or return trip, which is exposed as Mode + TripMode enumeration to specify whether the trip is one + way or return trip, which is exposed as Mode property. Finally, let's see the code-behind class that ties everything @@ -1266,9 +1375,9 @@ class MyControl : Control, ISupportsWebDependencyInjection commonly used binding type, SimpleExpressionBinding. The SimpleExpressionBinding is what we used in the example at the beginning of this section to bind our web form to a - Trip instance. It uses Spring.NET Expression - Language to extract and to set values within source and target objects. - We discussed sourceExpression and + Trip instance. It uses Spring.NET Expression Language + to extract and to set values within source and target objects. We + discussed sourceExpression and targetExpression arguments earlier, so let's focus on the remaining ones. @@ -1290,8 +1399,8 @@ class MyControl : Control, ISupportsWebDependencyInjection form doesn't have a simple one-to-one mapping to presentation model. In our earlier trip form example, the presentation model was intentionally designed to allow for simple one-to-one mappings. For - the sake of discussion, let's add the Airport - class and modify our TripPoint class like + the sake of discussion, let's add the Airport class + and modify our TripPoint class like this:namespace SpringAir.Domain { [Serializable] @@ -1346,14 +1455,14 @@ class MyControl : Control, ISupportsWebDependencyInjection } } }Instead of the string property - AirportCode, our TripPoint - class now exposes an Airport property of type + AirportCode, our TripPoint class + now exposes an Airport property of type Airport, which is defined above. Now we have a problem: what used to be a simple string to string binding, with the airport code selected in a dropdown being copied directly into the TripPoint.AirportCode property and vice versa, now becomes a not so - simple string to Airport binding, so let's see - how we can solve this mismatch problem. + simple string to Airport binding, so let's see how + we can solve this mismatch problem. First of all, binding from the model to the control is still very straight forward. We just need to set up one-way bindings from @@ -1369,17 +1478,16 @@ class MyControl : Control, ISupportsWebDependencyInjection might be able to set Code property of the Airport object, but that will likely make the Airport.Name property invalid. What we really want - do is find an instance of the Airport class - based on the airport code and set the - TripPoint.Airport property to it. Fortunately, this - is very simple to do with Spring.NET data binding, especially because - we already have airportDao object defined in the - Spring context, which has GetAirport(string - airportCode) finder method. All we need to do is set up data - bindings from source to target that will invoke this finder method - when evaluating the source expression. Our complete set of bindings - for these two drop down lists will then look like - this:protected override void InitializeDataBindings() + do is find an instance of the Airport class based + on the airport code and set the TripPoint.Airport + property to it. Fortunately, this is very simple to do with Spring.NET + data binding, especially because we already have + airportDao object defined in the Spring context, + which has GetAirport(string airportCode) finder + method. All we need to do is set up data bindings from source to + target that will invoke this finder method when evaluating the source + expression. Our complete set of bindings for these two drop down lists + will then look like this:protected override void InitializeDataBindings() { BindingManager.AddBinding("@(airportDao).GetAirport(leavingFromAirportCode.SelectedValue)", "Trip.StartingFrom.Airport", BindingDirection.SourceToTarget); BindingManager.AddBinding("leavingFromAirportCode.SelectedValue", "Trip.StartingFrom.Airport.Code", BindingDirection.TargetToSource); @@ -1407,7 +1515,8 @@ class MyControl : Control, ISupportsWebDependencyInjection Spring.Globalization.Formatters namespace, but if you have requirements that cannot be satisfied by one of the standard formatters it is easy enough to write your own -- all you need to do - is implement a very simple IFormatter interface:public interface IFormatter + is implement a very simple IFormatter interface:public interface IFormatter { string Format(object value); object Parse(string value); @@ -1439,9 +1548,8 @@ class MyControl : Control, ISupportsWebDependencyInjection Data Binding Events - Spring.Web's base Page class adds two - events to the standard .NET page lifecycle - - DataBound and + Spring.Web's base Page class adds two events + to the standard .NET page lifecycle - DataBound and DataUnbound. The DataUnbound event is fired after the data @@ -1829,8 +1937,8 @@ protected override void InitializeDataBindings() The global resources are cached within the Spring.NET - IApplicationContext and are accessible through - the Spring.NET IMessageSource interface. + IApplicationContext and are accessible through the + Spring.NET IMessageSource interface. The Spring.Web Page and UserControl classes have a reference to their owning @@ -1857,11 +1965,11 @@ protected override void InitializeDataBindings() A localizer is simply an object that implements the Spring.Globalization.ILocalizer interface. - Spring.Globalization.AbstractLocalizer is - provided as a convenient base class for localization: this class has one - abstract method, LoadResources. This method must load - and return a list of all the resources that must be automatically - applied from the resource store. + Spring.Globalization.AbstractLocalizer is provided as + a convenient base class for localization: this class has one abstract + method, LoadResources. This method must load and + return a list of all the resources that must be automatically applied + from the resource store. Spring.NET ships with one concrete implementation of a localizer, Spring.Globalization.Localizers.ResourceSetLocalizer, @@ -1872,8 +1980,8 @@ protected override void InitializeDataBindings() store resources within the files in a web application instead of as embedded resources in an assembly. Of course, if an application developer would rather store such resources in a database, he or she can - write their own ILocalizer implementation that - will load a list of resources to apply from a database. + write their own ILocalizer implementation that will + load a list of resources to apply from a database. As mentioned previously, one would typically configure the localizer to be used within an abstract base definition for those pages @@ -1896,9 +2004,9 @@ protected override void InitializeDataBindings() automatically one can completely omit the localizer definition. One last thing to note is that Spring.NET - UserControl instances will (by default) inherit - the localizer and other localization settings from the page that they - are contained within, but one can similarly also override that behavior + UserControl instances will (by default) inherit the + localizer and other localization settings from the page that they are + contained within, but one can similarly also override that behavior using explicit dependency injection. @@ -2011,17 +2119,16 @@ protected override void InitializeDataBindings() In addition to global and local resource management, Spring.Web also adds support for user culture management by exposing the current CultureInfo through the - UserCulture property on the - Page and UserControl - classes. + UserCulture property on the Page + and UserControl classes. The UserCulture property will simply delegate culture resolution to an implementation of - Spring.Globalization.ICultureResolver interface. - One can specify exactly which culture resolver to use by configuring the + Spring.Globalization.ICultureResolver interface. One + can specify exactly which culture resolver to use by configuring the CultureResolver property of the - Page class in the relevant object definition as - shown below. + Page class in the relevant object definition as shown + below. <object name="BasePage" abstract="true"> <property name="CultureResolver"> @@ -2030,43 +2137,42 @@ protected override void InitializeDataBindings() </object> Several useful implementations of - ICultureResolver ship as part of Spring.Web, so - it is unlikely that application developers will have to implement their - own culture resolver. However, if one does have such a requirement, the + ICultureResolver ship as part of Spring.Web, so it is + unlikely that application developers will have to implement their own + culture resolver. However, if one does have such a requirement, the resulting implementation should be fairly straightforward as there are only two methods that one need implement. The following sections discuss - each available implementation of the - ICultureResolver interface. + each available implementation of the ICultureResolver + interface. DefaultWebCultureResolver This is default culture resolver implementation. It will be used if one does not specify a culture resolver for a page, or if one - explicitly injects a DefaultWebCultureResolver - into a page definition explicitly. The latter case (explicit - injection) is sometimes useful because it allows one to specify a - culture that should always be used by providing a value to the + explicitly injects a DefaultWebCultureResolver into + a page definition explicitly. The latter case (explicit injection) is + sometimes useful because it allows one to specify a culture that + should always be used by providing a value to the DefaultCulture property on the resolver. - The DefaultWebCultureResolver will first - look at the DefaultCulture property and return its - value if said property value is not null. If it is null, the - DefaultWebCultureResolver will fall back to - request header inspection, and finally, if no - 'Accept-Lang' request headers are present it will - return the UI culture of the currently executing thread. + The DefaultWebCultureResolver will first look + at the DefaultCulture property and return its value + if said property value is not null. If it is null, the + DefaultWebCultureResolver will fall back to request + header inspection, and finally, if no 'Accept-Lang' + request headers are present it will return the UI culture of the + currently executing thread. RequestCultureResolver This resolver works in a similar way to the - DefaultWebCultureResolver with the exception - that it always checks request headers first, and - only then falls back to the value of the - DefaultCulture property or the culture code of the - current thread. + DefaultWebCultureResolver with the exception that + it always checks request headers first, and only + then falls back to the value of the DefaultCulture + property or the culture code of the current thread. @@ -2086,16 +2192,16 @@ protected override void InitializeDataBindings() of the DefaultWebCultureResolver. - CookieCultureResolver will not work if - your application uses localhost as the server - URL, which is a typical setting in a development environment. + CookieCultureResolver will not work if your + application uses localhost as the server URL, + which is a typical setting in a development environment. In order to work around this limitation you should use SessionCultureResolver during development and - switch to CookieCultureResolver before you - deploy the application in a production. This is easily accomplished - in Spring.Web (simply change the config file) but is something that - you should be aware of. + switch to CookieCultureResolver before you deploy + the application in a production. This is easily accomplished in + Spring.Web (simply change the config file) but is something that you + should be aware of. @@ -2106,14 +2212,14 @@ protected override void InitializeDataBindings() In order to be able to change the culture application developers will need to use one of the culture resolvers that support culture changes, such as SessionCultureResolver or - CookieCultureResolver. One could also write a - custom ICultureResolver that will persist culture + CookieCultureResolver. One could also write a custom + ICultureResolver that will persist culture information in a database, as part of a user's profile. Once that requirement is satisfied, all that one need do is to set the UserCulture property to a new - CultureInfo object before the page is rendered. - In the following .aspx example, there are two link + CultureInfo object before the page is rendered. In + the following .aspx example, there are two link buttons that can be used to change the user's culture. In the code-behind, this is all one need do to set the new culture. A code snippet for the code-behind file @@ -2159,8 +2265,8 @@ private void SetLanguage(object sender, CommandEventArgs e) flow. In Spring.Web, a logical result is encapsulated and defined by the - Result class; because of this one can configure - results just like any other object: + Result class; because of this one can configure results + just like any other object: <objects xmlns="http://www.springframework.net"> @@ -2242,10 +2348,10 @@ private void SetLanguage(object sender, CommandEventArgs e) The above example shows independent result object definitions, which are useful for global results such as a home- and login- page. - Result definitions that are only going to be used - by one page should be simply embedded within the definition of a page, - either as inner object definitions or using a special shortcut notation - for defining a result definition: + Result definitions that are only going to be used by + one page should be simply embedded within the definition of a page, either + as inner object definitions or using a special shortcut notation for + defining a result definition: <object type="~/UI/Forms/UserRegistration.aspx" parent="basePage"> @@ -2441,7 +2547,7 @@ protected override void OnInit(EventArgs e) additional information. There are a few other controls not documented here, please check the SDK docs for their descriptions. - + Validation Controls The location in the web page where validation errors are to be @@ -2464,8 +2570,8 @@ protected override void OnInit(EventArgs e) Some standard controls are not easy to use with Spring's databinding support. Examples are check boxes and ratio button groups. In this case you should use the CheckBoxList and - RadioButtonGroup controls. Databinding itself can - be done using the RadioButtonGroup controls. Databinding itself can be + done using the DataBindingPanel instead of the using the BindingManager API within the code behind page. @@ -2488,4 +2594,4 @@ protected override void OnInit(EventArgs e) injection for more information. - \ No newline at end of file + diff --git a/doc/reference/src/webservices.xml b/doc/reference/src/webservices.xml index bb960164..8f287b2b 100644 --- a/doc/reference/src/webservices.xml +++ b/doc/reference/src/webservices.xml @@ -16,10 +16,16 @@ * limitations under the License. */ --> - + Web Services - + Introduction While the out-of-the-box support for web services in .NET is @@ -66,7 +72,7 @@ example named 'calculator'. More information can be found here 'Web Services example'. - + Removing the need for .asmx files Unlike web pages, which use .aspx files to @@ -107,8 +113,8 @@ namespace MyComany.MyApp.Services is: 1. Register the - Spring.Web.Services.WebServiceFactoryHandler as - the HTTP handler for *.asmx requests within one's + Spring.Web.Services.WebServiceFactoryHandler as the + HTTP handler for *.asmx requests within one's web.config file. @@ -156,7 +162,7 @@ namespace MyComany.MyApp.Services http://localhost/MyWebApp/HelloWorld.asmx - + Injecting dependencies into web services For arguments sake, let's say that we want to change the @@ -228,8 +234,8 @@ namespace MyApp.Services </object>
- The WebServiceExporter copies the existing - web service and method attribute values to the proxy implementation (if + The WebServiceExporter copies the existing web + service and method attribute values to the proxy implementation (if indeed any are defined). Please note however that existing values can be overridden by setting properties on the WebServiceExporter. @@ -248,7 +254,7 @@ namespace MyApp.Services - + Exposing PONOs as Web Services Now that we are generating a server-side proxy for the service, @@ -260,12 +266,12 @@ namespace MyApp.Services target service's methods. This means that we can safely remove the - WebService and WebMethod - attribute declarations from the service implementation, and what we are - left with is a plain old .NET object (a PONO). The example above would - still work, because the proxy generator will automatically add - WebMethod attributes to all methods of the - exported interfaces. + WebService and WebMethod attribute + declarations from the service implementation, and what we are left with + is a plain old .NET object (a PONO). The example above would still work, + because the proxy generator will automatically add + WebMethod attributes to all methods of the exported + interfaces. However, that is still not the ideal solution. You would lose information that the optional WebService and @@ -424,11 +430,10 @@ namespace MyApp.Services Spring.NET provides a simple IFactoryObject implementation that will generate a "proxy for proxy" (however obtuse that may sound). Basically, the - Spring.Web.Services.WebServiceProxyFactory class - will create a proxy for the VS.NET- / WSDL-generated proxy that - implements a specified service interface (thus solving the problem with - the web-service proxy classes mentioned in the preceding - paragraph). + Spring.Web.Services.WebServiceProxyFactory class will + create a proxy for the VS.NET- / WSDL-generated proxy that implements a + specified service interface (thus solving the problem with the + web-service proxy classes mentioned in the preceding paragraph). At this point, an example may well be more illustrative in conveying what is happening; consider the following interface definition @@ -457,26 +462,25 @@ namespace MyCompany.Services What is important to notice is that the underlying implementation class for the web service does not have to implement the same - IHelloWorld service interface... so long as - matching methods with compliant signatures exist (a kind of duck - typing), Spring.NET will be able to create a proxy and delegate method - calls appropriately. If a matching method cannot be found, the - Spring.NET infrastructure code will throw an exception. + IHelloWorld service interface... so long as matching + methods with compliant signatures exist (a kind of duck typing), + Spring.NET will be able to create a proxy and delegate method calls + appropriately. If a matching method cannot be found, the Spring.NET + infrastructure code will throw an exception. That said, if you control both the client and the server it is probably a good idea to make sure that the web service class on the server implements the service interface, especially if you plan on - exporting it using Spring.NET's - WebServiceExporter, which requires an interface - in order to work. + exporting it using Spring.NET's WebServiceExporter, + which requires an interface in order to work. Generating proxies dynamically - The WebServiceProxyFactory can also - dynamically generate a web-service proxy. The XML object definition for - this factory object is shown below + The WebServiceProxyFactory can also dynamically + generate a web-service proxy. The XML object definition for this factory + object is shown below <object id="calculatorService" type="Spring.Web.Services.WebServiceProxyFactory, Spring.Services"> @@ -507,8 +511,8 @@ namespace MyCompany.Services Configuring the proxy instance - The WebServiceProxyFactory also implements - the interface, + The WebServiceProxyFactory also implements the + interface, Spring.Objects.Factory.IConfigurableFactoryObject, allowing to specify configuration for the product that the WebServiceProxyFactory creates. This is done by @@ -550,4 +554,4 @@ namespace MyCompany.Services on our wiki. - \ No newline at end of file + diff --git a/readme.txt b/readme.txt index eab9c3e0..1fa0f45c 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -THE SPRING.NET FRAMEWORK, Release 1.2.0 M1 (August 14, 2008) +THE SPRING.NET FRAMEWORK, Release 1.2.0 RC1 (October 15, 2008) -------------------------------------------------------------------- http://www.springframework.net/ diff --git a/src/Spring/CommonAssemblyInfo.cs b/src/Spring/CommonAssemblyInfo.cs index 1196324b..2dec9eed 100644 --- a/src/Spring/CommonAssemblyInfo.cs +++ b/src/Spring/CommonAssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Reflection; [assembly: AssemblyConfiguration("net-2.0.win32; Release")] #endif [assembly: AssemblyCompany("http://www.springframework.net")] -[assembly: AssemblyProduct("Spring.NET Framework 1.2")] +[assembly: AssemblyProduct("Spring.NET Framework 1.2.0 RC1")] [assembly: AssemblyCopyright("Copyright 2002-2007 Spring.NET Framework Team.")] [assembly: AssemblyTrademark("Apache License, Version 2.0")] [assembly: AssemblyCulture("")] diff --git a/src/Spring/Spring.Aop/Spring.Aop.2005.csproj b/src/Spring/Spring.Aop/Spring.Aop.2005.csproj index 5aa4e8ad..de0d271b 100644 --- a/src/Spring/Spring.Aop/Spring.Aop.2005.csproj +++ b/src/Spring/Spring.Aop/Spring.Aop.2005.csproj @@ -394,6 +394,7 @@ + diff --git a/src/Spring/Spring.Core/Spring.Core.2005.csproj b/src/Spring/Spring.Core/Spring.Core.2005.csproj index 10620982..f8ab8219 100644 --- a/src/Spring/Spring.Core/Spring.Core.2005.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2005.csproj @@ -976,6 +976,7 @@ Code + Code diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedSession.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedSession.cs index 52744545..5dea77a3 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedSession.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/CachedSession.cs @@ -590,6 +590,16 @@ namespace Spring.Messaging.Nms.Connections target.Rollback(); } + /// + /// Gets or sets the request timeout. + /// + /// The request timeout. + public TimeSpan RequestTimeout + { + get { return target.RequestTimeout; } + set { target.RequestTimeout = value; } + } + /// /// Gets a value indicating whether this is transacted. /// diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs index 4b374b71..065a4dd5 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs @@ -474,6 +474,12 @@ namespace Spring.Messaging.Nms.Connections // don't pass the call to the target. } + public TimeSpan RequestTimeout + { + get { return target.RequestTimeout; } + set { target.RequestTimeout = value; } + } + public void Start() { // Handle start method: track started state. @@ -505,16 +511,6 @@ namespace Spring.Messaging.Nms.Connections } - public ISession CreateSession(AcknowledgementMode acknowledgementMode, TimeSpan requestTimeout) - { - ISession session = singleConnectionFactory.GetSession(target, acknowledgementMode, requestTimeout); - if (session != null) - { - return session; - } - return target.CreateSession(acknowledgementMode, requestTimeout); - } - #region Pass through implementations to the target connection diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs index ac0361f3..e8b6da7d 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs @@ -30,13 +30,27 @@ namespace Spring.Messaging.Nms.Support.Converter /// Mark Pollack public interface ITypeMapper { + /// + /// Gets the name of the field in the message that has type information.. + /// + /// The name of the type id field. string TypeIdFieldName { get; } - + + /// + /// Convert from a type to a string. + /// + /// The type of object to convert. + /// string FromType(Type typeOfObjectToConvert); + /// + /// Convert from a string to a type + /// + /// The type id. + /// Type ToType(string typeId); } } \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs index 01ae76e1..a23f911b 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs @@ -1,3 +1,22 @@ +#region License + +/* + * Copyright © 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion using System; @@ -6,6 +25,9 @@ using Spring.Core.TypeResolution; namespace Spring.Messaging.Nms.Support.Converter { + /// + /// Provides a layer of indirection when adding the 'type' of the object as a message property. + /// public class TypeMapper : ITypeMapper { private string defaultNamespace; @@ -15,12 +37,13 @@ namespace Spring.Messaging.Nms.Support.Converter private IDictionary idTypeMapping; private IDictionary typeIdMapping; - - //TODO generalize? private string defaultHashtableTypeId = "Hashtable"; private Type defaultHashtableClass = typeof(Hashtable); + /// + /// Initializes a new instance of the [ERROR: invalid expression DeclaringTypeKind]. + /// public TypeMapper() { idTypeMapping = new Hashtable(); @@ -28,23 +51,40 @@ namespace Spring.Messaging.Nms.Support.Converter } + /// + /// Gets or sets the id type mapping. + /// + /// The id type mapping. public IDictionary IdTypeMapping { get { return idTypeMapping; } set { idTypeMapping = value; } } + /// + /// Gets the name of the field in the message that has type information.. + /// + /// The name of the type id field. public string TypeIdFieldName { get { return "__TypeId__"; } } + /// + /// Sets the default hashtable class. + /// + /// The default hashtable class. public Type DefaultHashtableClass { set { defaultHashtableClass = value; } } + /// + /// Convert from a type to a string. + /// + /// The type of object to convert. + /// public string FromType(Type typeOfObjectToConvert) { @@ -62,6 +102,11 @@ namespace Spring.Messaging.Nms.Support.Converter } } + /// + /// Convert from a string to a type + /// + /// The type id. + /// public Type ToType(string typeId) { if (idTypeMapping.Contains(typeId)) @@ -82,6 +127,10 @@ namespace Spring.Messaging.Nms.Support.Converter } + /// + /// Gets or sets the default namespace. + /// + /// The default namespace. public string DefaultNamespace { get @@ -95,6 +144,10 @@ namespace Spring.Messaging.Nms.Support.Converter } + /// + /// Gets or sets the default name of the assembly. + /// + /// The default name of the assembly. public string DefaultAssemblyName { get @@ -107,6 +160,9 @@ namespace Spring.Messaging.Nms.Support.Converter } } + /// + /// Afters the properties set. + /// public void AfterPropertiesSet() { ValidateIdTypeMapping(); diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs index 2bb2d463..d776d56f 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs @@ -9,6 +9,10 @@ using Spring.Messaging.Nms.Support.Converter; namespace Spring.Messaging.Nms.Support.Converter { + /// + /// Convert an object via XML serialization for sending via an ITextMessage + /// + /// Mark Pollack public class XmlMessageConverter : IMessageConverter { private IMessageConverter defaultMessageConverter = new SimpleMessageConverter(); @@ -17,11 +21,24 @@ namespace Spring.Messaging.Nms.Support.Converter private ITypeMapper typeMapper; + /// + /// Sets the type mapper. + /// + /// The type mapper. public ITypeMapper TypeMapper { set { typeMapper = value; } } + /// + /// Convert a .NET object to a NMS Message using the supplied session + /// to create the message object. + /// + /// the object to convert + /// the Session to use for creating a NMS Message + /// the NMS Message + /// NMSException if thrown by NMS API methods + /// MessageConversionException in case of conversion failure public IMessage ToMessage(object objectToConvert, ISession session) { if (objectToConvert == null) @@ -49,7 +66,12 @@ namespace Spring.Messaging.Nms.Support.Converter } } - private string GetXmlString(object objectToConvert) + /// + /// Gets the XML string for an object + /// + /// The object to convert. + /// XML string + protected virtual string GetXmlString(object objectToConvert) { string xmlString; XmlTextWriter xmlTextWriter = null; @@ -72,6 +94,12 @@ namespace Spring.Messaging.Nms.Support.Converter return xmlString; } + /// + /// Convert from a NMS Message to a .NET object. + /// + /// the message to convert + /// the converted .NET object + /// MessageConversionException in case of conversion failure public object FromMessage(IMessage messageToConvert) { if (messageToConvert == null) @@ -108,13 +136,23 @@ namespace Spring.Messaging.Nms.Support.Converter } } - private Type GetTargetType(ITextMessage message) + /// + /// Gets the type of the target given the message. + /// + /// The message. + /// Type of the target + protected virtual Type GetTargetType(ITextMessage message) { return typeMapper.ToType(message.Properties.GetString(typeMapper.TypeIdFieldName)); } - private String UTF8ByteArrayToString(Byte[] characters) + /// + /// Converts a byte array to a UTF8 string. + /// + /// The characters. + /// UTF8 string + protected virtual String UTF8ByteArrayToString(Byte[] characters) { UTF8Encoding encoding = new UTF8Encoding(); @@ -124,11 +162,16 @@ namespace Spring.Messaging.Nms.Support.Converter } - private Byte[] StringToUTF8ByteArray(String pXmlString) + /// + /// Converts a UTF8 string to a byte array + /// + /// The p XML string. + /// + protected virtual Byte[] StringToUTF8ByteArray(String xmlString) { UTF8Encoding encoding = new UTF8Encoding(); - Byte[] byteArray = encoding.GetBytes(pXmlString); + Byte[] byteArray = encoding.GetBytes(xmlString); return byteArray; } diff --git a/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2005.csproj b/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2005.csproj index b8036b58..c67cd2ae 100644 --- a/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2005.csproj +++ b/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2005.csproj @@ -83,8 +83,11 @@ + + + diff --git a/src/Spring/Spring.Messaging/Spring.Messaging.2005.csproj b/src/Spring/Spring.Messaging/Spring.Messaging.2005.csproj index 110b5da1..159e0532 100644 --- a/src/Spring/Spring.Messaging/Spring.Messaging.2005.csproj +++ b/src/Spring/Spring.Messaging/Spring.Messaging.2005.csproj @@ -73,7 +73,6 @@ -