update product version numbers and dates in readme.txt etc
update docs update to ActiveMQ NMS svn revision 704303 Add missing code xml docs.
This commit is contained in:
@@ -14,10 +14,10 @@
|
||||
<!-- Include spring helpers -->
|
||||
<include buildfile="${spring.basedir}/Spring.include"/>
|
||||
|
||||
<property name="package.version" value="1.1.2" unless="${property::exists('project.version')}"/>
|
||||
<property name="package.version" value="1.2.0" unless="${property::exists('project.version')}"/>
|
||||
<property name="using-clover" value="false"/>
|
||||
<!-- change this to sync the sdk doc version generated -->
|
||||
<property name="package.version.docs" value="1.1.0" unless="${property::exists('project.version')}"/>
|
||||
<property name="package.version.docs" value="1.2.0" unless="${property::exists('project.version')}"/>
|
||||
<!-- make system environment variables available as NAnt properties -->
|
||||
<sysinfo/>
|
||||
|
||||
|
||||
@@ -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] - <name-values> elements to not append values for same key value
|
||||
[SPRNET-1047] - ObjectPostProcessors order isn't respected when mixing <object order="x"> 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 <listener-container> 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
|
||||
|
||||
@@ -16,7 +16,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<chapter xml:id="aop-aspect-library" xmlns="http://docbook.org/ns/docbook" version="5">
|
||||
<chapter version="5" xml:id="aop-aspect-library"
|
||||
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>Aspect Library</title>
|
||||
|
||||
<sect1 xml:id="aop-library-introduction">
|
||||
@@ -54,8 +60,8 @@
|
||||
implement is <literal>Spring.Caching.ICache</literal> located in
|
||||
<literal>Spring.Core</literal>. Two implementations are provided,
|
||||
<literal>Spring.Caching.AspNetCache</literal> located in
|
||||
<literal>Spring.Web</literal> which stores cache entries within an
|
||||
ASP.NET cache and a simple implementation,
|
||||
<literal>Spring.Web</literal> which stores cache entries within an ASP.NET
|
||||
cache and a simple implementation,
|
||||
<literal>Spring.Caching.NonExpiringCache</literal> 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 @@
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>CacheResultItems</literal> - used when returning a collection as
|
||||
a return value</para>
|
||||
<para><literal>CacheResultItems</literal> - used when returning a
|
||||
collection as a return value</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
@@ -97,9 +103,8 @@
|
||||
</itemizedlist>
|
||||
|
||||
<para>Each <literal>CacheResult</literal>,
|
||||
<literal>CacheResultItems</literal>, and
|
||||
<literal>CacheParameter</literal> attributes define the following
|
||||
properties.</para>
|
||||
<literal>CacheResultItems</literal>, and <literal>CacheParameter</literal>
|
||||
attributes define the following properties.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
@@ -125,14 +130,14 @@
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>The <literal>InvalidateCache</literal> attribute has properties
|
||||
for the CacheName, the Key as well as the Condition, with the same
|
||||
meanings as listed previously.</para>
|
||||
<para>The <literal>InvalidateCache</literal> attribute has properties for
|
||||
the CacheName, the Key as well as the Condition, with the same meanings as
|
||||
listed previously.</para>
|
||||
|
||||
<para>Each <literal>ICache</literal> implementation will have
|
||||
properties that are specific to a caching technology. In the case of
|
||||
<literal>AspNetCache</literal>, the two important properties to
|
||||
configure are:</para>
|
||||
<para>Each <literal>ICache</literal> implementation will have properties
|
||||
that are specific to a caching technology. In the case of
|
||||
<literal>AspNetCache</literal>, the two important properties to configure
|
||||
are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
@@ -202,32 +207,32 @@ public <classname>Airport</classname> GetAirport(long id)
|
||||
|
||||
<para>The configuration to enable the caching aspect is shown below</para>
|
||||
|
||||
<programlisting language="myxml"><![CDATA[<object" id="CacheAspect" type="Spring.Aspects.Cache.CacheAspect, Spring.Aop"/>
|
||||
<programlisting language="myxml"><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>
|
||||
<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>
|
||||
|
||||
<!-- 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>]]></programlisting>
|
||||
<!-- 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></programlisting>
|
||||
|
||||
<para>in this example an <literal>ObjectNameAutoProxyCreator</literal>
|
||||
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.</para>
|
||||
<para>in this example an <literal>ObjectNameAutoProxyCreator</literal> 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.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="exception-aspect">
|
||||
@@ -251,6 +256,11 @@ public <classname>Airport</classname> GetAirport(long id)
|
||||
<listitem>
|
||||
<para>swallow - the exception is ignored.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>execute - Execute an abritrary Spring Expression Language (SpEL
|
||||
expression)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>The applicability of general exception handling advice depends
|
||||
@@ -268,13 +278,13 @@ public <classname>Airport</classname> GetAirport(long id)
|
||||
could be referred to as a Domain Specific Language (DSL). Here is a simple
|
||||
example, which should hopefully be self explanatory.</para>
|
||||
|
||||
<para><programlisting language="myxml"><![CDATA[<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>]]></programlisting>What this is instructing the advice to do is
|
||||
<para><programlisting language="myxml"><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></programlisting>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</programlisting>
|
||||
action, i.e. log(Debug,"LoggerName").</para>
|
||||
|
||||
<para>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.</para>
|
||||
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.</para>
|
||||
|
||||
<para>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</programlisting>
|
||||
likely be better off creating your own custom aspect class instead of a
|
||||
scripting approach.</para>
|
||||
|
||||
<para>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</para>
|
||||
<para>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.</para>
|
||||
|
||||
<programlisting language="myxml"><![CDATA[<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>]]></programlisting>
|
||||
<programlisting language="csharp"><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>
|
||||
</programlisting>
|
||||
|
||||
<para>You can also configure <literal>ExceptionHandlerAdvice</literal> to
|
||||
use an instance of <literal>IExceptionHandler</literal> 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</para>
|
||||
|
||||
<programlisting language="myxml"><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></programlisting>
|
||||
|
||||
<para></para>
|
||||
|
||||
<para>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</programlisting>
|
||||
<listitem>
|
||||
<para>swallow</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>execute</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>The form of the expression depends on the action. For logging, the
|
||||
@@ -476,9 +522,10 @@ on exception name ArithmeticException return 12</programlisting>
|
||||
|
||||
<para>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, <ulink url="http://netcommon.sourceforge.net/">Common.Logging</ulink>, that provides
|
||||
portability across different logging libraries. There are a number of
|
||||
configuration options available, listed below</para>
|
||||
logging library, <ulink
|
||||
url="http://netcommon.sourceforge.net/">Common.Logging</ulink>, that
|
||||
provides portability across different logging libraries. There are a
|
||||
number of configuration options available, listed below</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
@@ -510,19 +557,19 @@ on exception name ArithmeticException return 12</programlisting>
|
||||
XML fragment. Alternatively, you can use the class
|
||||
<literal>SimpleLoggingAdvice</literal> programatically.</para>
|
||||
|
||||
<programlisting language="myxml"><![CDATA[<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"/>
|
||||
<programlisting language="myxml"><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="Separator" value=";"/>
|
||||
<property name="LogLevel" value="Info"/>
|
||||
|
||||
|
||||
<property name="HideProxyTypeNames" value="true"/>
|
||||
<property name="UseDynamicLogger" value="true"/>
|
||||
</object>]]></programlisting>
|
||||
<property name="HideProxyTypeNames" value="true"/>
|
||||
<property name="UseDynamicLogger" value="true"/>
|
||||
</object></programlisting>
|
||||
|
||||
<para>The default values for LogUniqueIdentifier, LogExecutionTime,
|
||||
LogMethodArguments and LogReturnValue are false. The default separator
|
||||
@@ -568,8 +615,8 @@ on exception name ArithmeticException return 12</programlisting>
|
||||
use a GUID. You can alter this behavior by overriding the method
|
||||
<literal>string CreateUniqueIdentifier()</literal>. The
|
||||
<literal>SimpleLoggingAdvice</literal> class inherits from
|
||||
<literal>AbstractLoggingAdvice</literal>, which has the abstract
|
||||
method <literal>object InvokeUnderLog(IMethodInvocation invocation, ILog
|
||||
<literal>AbstractLoggingAdvice</literal>, which has the abstract method
|
||||
<literal>object InvokeUnderLog(IMethodInvocation invocation, ILog
|
||||
log)</literal> and you can also override the method <literal>ILog
|
||||
GetLoggerForInvocation(IMethodInvocation invocation)</literal> 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)</p
|
||||
following XML fragment. Alternatively, you can use the
|
||||
<literal>RetryAdvice</literal> class programatically.</para>
|
||||
|
||||
<programlisting language="myxml"><![CDATA[<object name="exceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
|
||||
<property name="retryExpression" value="on exception name ArithmeticException retry 3x delay 1s"/>
|
||||
</object>]]></programlisting>
|
||||
<programlisting language="myxml"><object name="exceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
|
||||
<property name="retryExpression" value="on exception name ArithmeticException retry 3x delay 1s"/>
|
||||
</object></programlisting>
|
||||
|
||||
<sect2>
|
||||
<title>Language Reference</title>
|
||||
@@ -721,13 +768,13 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)</p
|
||||
<para>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
|
||||
<literal>ParameterValidationAdvice</literal> is used in conjunction
|
||||
with the <literal>Validated</literal> 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 <link linkend="springair">SpringAir sample
|
||||
application</link>, you would apply the <literal>Validated</literal>
|
||||
attribute to the method parameters as shown below.</para>
|
||||
<literal>ParameterValidationAdvice</literal> is used in conjunction with
|
||||
the <literal>Validated</literal> 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 <link linkend="springair">SpringAir sample application</link>, you
|
||||
would apply the <literal>Validated</literal> attribute to the method
|
||||
parameters as shown below.</para>
|
||||
|
||||
<programlisting language="csharp">public <classname>FlightSuggestions</classname> SuggestFlights( [<classname>Validated</classname>("tripValidator")] <classname>Trip</classname> trip)
|
||||
{
|
||||
@@ -736,30 +783,29 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)</p
|
||||
|
||||
<para>The <literal>Validated</literal> 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
|
||||
<literal>Validated</literal> attribute is located in the namespace
|
||||
<literal>Spring.Validation</literal> of the <literal>Spring.Core</literal>
|
||||
assembly.</para>
|
||||
object in the Spring application context. The <literal>Validated</literal>
|
||||
attribute is located in the namespace <literal>Spring.Validation</literal>
|
||||
of the <literal>Spring.Core</literal> assembly.</para>
|
||||
|
||||
<para>The configuration of the advice is to simply define the an instance
|
||||
of the <literal>ParameterValidationAdvice</literal> class and apply the
|
||||
advice, for example based on object names using an
|
||||
<literal>ObjectNameAutoProxyCreator</literal>, as shown below,</para>
|
||||
|
||||
<programlisting language="myxml"><![CDATA[<object id="validationAdvice" type="Spring.Aspects.Validation.ParameterValidationAdvice, Spring.Aop"/>
|
||||
<programlisting language="myxml"><object id="validationAdvice" type="Spring.Aspects.Validation.ParameterValidationAdvice, Spring.Aop"/>
|
||||
|
||||
<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>]]></programlisting>
|
||||
<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></programlisting>
|
||||
|
||||
<para>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)</p
|
||||
errors information from its property <literal>ValidationErrors</literal>.
|
||||
See the SDK documentation for details.</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
||||
@@ -60,8 +60,8 @@
|
||||
<info>
|
||||
<title>The Spring.NET Framework</title>
|
||||
<subtitle>Reference Documentation</subtitle>
|
||||
<releaseinfo>Version 1.2.0 M1</releaseinfo>
|
||||
<pubdate>Last Updated August 15,2008</pubdate>
|
||||
<releaseinfo>Version 1.2.0 RC1</releaseinfo>
|
||||
<pubdate>Last Updated October 15,2008</pubdate>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
|
||||
@@ -16,8 +16,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<chapter xml:id="messaging" xmlns="http://docbook.org/ns/docbook" version="5">
|
||||
<title>Message Oriented Middleware</title>
|
||||
<chapter version="5" xml:id="messaging" 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>Message Oriented Middleware - Apache ActiveMQ</title>
|
||||
|
||||
<section>
|
||||
<title>Introduction</title>
|
||||
@@ -50,25 +55,27 @@
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Apache NMS in namespace <literal>Spring.Messaging.Nms</literal>.
|
||||
'Nms' is sometimes used as the class prefix</para>
|
||||
<para>Apache ActiveMQ (NMS) in namespace
|
||||
<literal>Spring.Messaging.Nms</literal>. 'Nms' is sometimes used as
|
||||
the class prefix</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>TIBCO EMS in namespace <literal>Spring.Messaging.Ems</literal>.
|
||||
'Ems' is sometimes used as the class prefix</para>
|
||||
'Ems' is sometimes used as the class prefix (to becommerically
|
||||
available )</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>SonicMQ in namespace <literal>Spring.Messaging.Sonic</literal>,
|
||||
'Jms' is sometimes used as the class prefix. (available 1.2
|
||||
RC1)</para>
|
||||
'Jms' is sometimes used as the class prefix. (to be commercially
|
||||
available)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Websphere MQ in namespace
|
||||
<literal>Spring.Messaging.Xms</literal>, 'Xms' is sometimes used as
|
||||
the class prefix (available 1.2 RC1)</para>
|
||||
the class prefix (to be commerically available)</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
@@ -78,11 +85,11 @@
|
||||
<literal>NmsTemplate</literal>, <literal> EmsTemplate</literal> (etc.) is
|
||||
used. Asynchronous message consumption is performed though a
|
||||
multi-threaded message listener container,
|
||||
<literal>SimpleMessageListenerContainer</literal>. 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 <literal>IMessageConverter</literal> interface is used by both the
|
||||
<literal>SimpleMessageListenerContainer</literal>. 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
|
||||
<literal>IMessageConverter</literal> interface is used by both the
|
||||
template class and the message listener container to convert between
|
||||
provider message types and PONOs.</para>
|
||||
|
||||
@@ -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.</para>
|
||||
comfortable with that programming model. </para>
|
||||
|
||||
<para>A WCF binding for Apache NMS is being developed as a separate
|
||||
project under the <link
|
||||
ns6:href="http://www.springframework.org/extensions/faq">Spring
|
||||
Extensions</link> umbrella project. Stay tuned for details.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -222,16 +234,16 @@
|
||||
<title>Messaging Template overview</title>
|
||||
|
||||
<para>Code that uses the messaging template classes
|
||||
(<literal>NmsTemplate</literal>, <literal>EmsTemplate</literal>,
|
||||
etc) only needs to implement callback interfaces giving them a clearly
|
||||
(<literal>NmsTemplate</literal>, <literal>EmsTemplate</literal>, etc)
|
||||
only needs to implement callback interfaces giving them a clearly
|
||||
defined contract. The <literal>IMessageCreator</literal> callback
|
||||
interface creates a message given a Session provided by the calling code
|
||||
in <literal>NmsTemplate</literal>. In order to allow for more complex
|
||||
usage of the provider messaging API, the callback
|
||||
<literal>ISessionCallback</literal> provides the user with the
|
||||
provider specific messaging Session and the callback
|
||||
<literal>IProducerCallback</literal> exposes a provider specific
|
||||
Session and MessageProducer pair.</para>
|
||||
<literal>ISessionCallback</literal> provides the user with the provider
|
||||
specific messaging Session and the callback
|
||||
<literal>IProducerCallback</literal> exposes a provider specific Session
|
||||
and MessageProducer pair.</para>
|
||||
|
||||
<para>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 @@
|
||||
<literal>NmsTemplate</literal> and then safely inject this shared
|
||||
reference into multiple collaborators. To be clear, the
|
||||
<literal>NmsTemplate</literal> is stateful, in that it maintains a
|
||||
reference to a <literal>ConnectionFactory</literal>, but this
|
||||
state is not conversational state.</para>
|
||||
reference to a <literal>ConnectionFactory</literal>, but this state is
|
||||
not conversational state.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
@@ -321,11 +333,10 @@
|
||||
session and also take into account the unique properties of the
|
||||
producers and consumers when caching.</para>
|
||||
|
||||
<para><literal>MessageProducers</literal> are cached based on
|
||||
their destination. <literal>MessageConsumers</literal> are cached
|
||||
based on a key composed of the destination, selector, noLocal delivery
|
||||
flag, and the durable subscription name (if creating durable
|
||||
consumers).</para>
|
||||
<para><literal>MessageProducers</literal> are cached based on their
|
||||
destination. <literal>MessageConsumers</literal> are cached based on a
|
||||
key composed of the destination, selector, noLocal delivery flag, and
|
||||
the durable subscription name (if creating durable consumers).</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -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
|
||||
<literal>NmsTemplate</literal> delegates the resolution of a
|
||||
destination name to a destination object by delegating to an
|
||||
implementation of the interface
|
||||
<literal>IDestinationResolver</literal>.
|
||||
<literal>NmsTemplate</literal> delegates the resolution of a destination
|
||||
name to a destination object by delegating to an implementation of the
|
||||
interface <literal>IDestinationResolver</literal>.
|
||||
<literal>DynamicDestinationResolver</literal> is the default
|
||||
implementation used by <literal>NmsTemplate</literal> and
|
||||
accommodates resolving dynamic destinations.</para>
|
||||
implementation used by <literal>NmsTemplate</literal> and accommodates
|
||||
resolving dynamic destinations.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>A subclass of
|
||||
<literal>AbstractMessageListenerContainer</literal> is used to
|
||||
receive messages from JMS and drive the Message-Driven PONOs (MDPs) that
|
||||
are injected into it. There are one subclasses of
|
||||
<literal>AbstractMessageListenerContainer</literal> packaged with
|
||||
Spring - <literal>SimpleMessageListenerContainer</literal>.
|
||||
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.</para>
|
||||
<para>A subclass of <literal>AbstractMessageListenerContainer</literal>
|
||||
is used to receive messages from JMS and drive the Message-Driven PONOs
|
||||
(MDPs) that are injected into it. There are one subclasses of
|
||||
<literal>AbstractMessageListenerContainer</literal> packaged with Spring
|
||||
- <literal>SimpleMessageListenerContainer</literal>. 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.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -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 <literal>Destination</literal> object using the
|
||||
<literal>IDestinationResolver</literal> associated with the template.
|
||||
The last method sends the message to the destination specified by
|
||||
<literal>NmsTemplate</literal>''s
|
||||
<literal>DefaultDestination</literal> property.</para>
|
||||
<literal>IDestinationResolver</literal> associated with the template. The
|
||||
last method sends the message to the destination specified by
|
||||
<literal>NmsTemplate</literal>''s <literal>DefaultDestination</literal>
|
||||
property.</para>
|
||||
|
||||
<para>All methods take as an argument an instance of
|
||||
<literal>IMessageCreator</literal> which defines the API contract for
|
||||
you to create the JMS message. The interface is show below</para>
|
||||
<literal>IMessageCreator</literal> which defines the API contract for you
|
||||
to create the JMS message. The interface is show below</para>
|
||||
|
||||
<para><programlisting language="csharp">public interface IMessageCreator {
|
||||
IMessage CreateMessage(ISession session);
|
||||
@@ -554,23 +562,21 @@
|
||||
<title>Using MessageConverters</title>
|
||||
|
||||
<para>In order to facilitate the sending of domain model objects, the
|
||||
<literal>NmsTemplate</literal> has various send methods that take a
|
||||
.NET object as an argument for a message's data content. The overloaded
|
||||
<literal>NmsTemplate</literal> has various send methods that take a .NET
|
||||
object as an argument for a message's data content. The overloaded
|
||||
methods <literal>ConvertAndSend</literal> and
|
||||
<literal>ReceiveAndConvert</literal> in
|
||||
<literal>NmsTemplate</literal> delegate the conversion process to an
|
||||
instance of the <literal>IMessageConverter</literal>
|
||||
interface. This interface defines a simple contract to convert between
|
||||
.NET objects and JMS messages. The default implementation
|
||||
<literal>SimpleMessageConverter</literal> 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.</para>
|
||||
|
||||
<para>The sample applications contains a XmlMessageConverter that
|
||||
converts objects to an XML string and vice-versa for sending via a
|
||||
<literal>ReceiveAndConvert</literal> in <literal>NmsTemplate</literal>
|
||||
delegate the conversion process to an instance of the
|
||||
<literal>IMessageConverter</literal> interface. This interface defines a
|
||||
simple contract to convert between .NET objects and JMS messages. The
|
||||
default implementation <literal>SimpleMessageConverter</literal>
|
||||
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 <literal>XmlMessageConverter</literal> that converts
|
||||
objects to an XML string and vice-versa for sending via a
|
||||
TextMessage.</para>
|
||||
|
||||
<para>The family of <literal>ConvertAndSend</literal> messages are
|
||||
@@ -619,13 +625,13 @@
|
||||
template.ConvertAndSend("APP.STOCK.MARKETDATA", marketData);
|
||||
}</programlisting>To accommodate the setting of message's properties, headers,
|
||||
and body that can not be generally encapsulated inside a converter
|
||||
class, the <literal>IMessageConverterPostProcessor</literal>
|
||||
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
|
||||
<literal>ConvertAndSendUsingDelegate</literal> allow for the use of
|
||||
a delegate to perform message post processing. This family of methods is
|
||||
class, the <literal>IMessageConverterPostProcessor</literal> 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
|
||||
<literal>ConvertAndSendUsingDelegate</literal> allow for the use of a
|
||||
delegate to perform message post processing. This family of methods is
|
||||
listed below</para>
|
||||
|
||||
<itemizedlist>
|
||||
@@ -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
|
||||
<code><property>ReceiveTimeout</property></code> on
|
||||
<literal>NmsTemplate</literal> specifies how long the receiver
|
||||
should wait before giving up waiting for a message.</para>
|
||||
<literal>NmsTemplate</literal> specifies how long the receiver should
|
||||
wait before giving up waiting for a message.</para>
|
||||
|
||||
<para>The <methodname>Receive</methodname> methods are listed
|
||||
below</para>
|
||||
@@ -774,8 +780,8 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
|
||||
<para>The <methodname>Receive</methodname> method without arguments will
|
||||
use the <property>DefaultDestination</property>. The
|
||||
<methodname>ReceiveSelected</methodname> methods apply the provided
|
||||
message selector string to the <literal>MessageConsumer</literal>
|
||||
that is created.</para>
|
||||
message selector string to the <literal>MessageConsumer</literal> that
|
||||
is created.</para>
|
||||
|
||||
<para>The <methodname>ReceiveAndConvert</methodname> 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
|
||||
<para>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
|
||||
<literal>Spring.Messaging.Nms.Core</literal> is an interface
|
||||
<literal>IMessageListener</literal> that can be used with
|
||||
NMS.</para>
|
||||
programming convenience in <literal>Spring.Messaging.Nms.Core</literal>
|
||||
is an interface <literal>IMessageListener</literal> that can be used
|
||||
with NMS.</para>
|
||||
|
||||
<para>Below is a simple implementation of the IMessageListener interface
|
||||
that processing a message.</para>
|
||||
@@ -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,
|
||||
<literal>AbstractMessageListenerContainer</literal>, and one
|
||||
concrete implementation,
|
||||
<literal>SimpleMessageListenerContainer</literal>.
|
||||
<literal>SimpleMessageListenerContainer</literal> creates a fixed
|
||||
number of JMS Sessions/MessageConsumer pairs as set by the property
|
||||
<literal>AbstractMessageListenerContainer</literal>, and one concrete
|
||||
implementation, <literal>SimpleMessageListenerContainer</literal>.
|
||||
<literal>SimpleMessageListenerContainer</literal> creates a fixed number
|
||||
of JMS Sessions/MessageConsumer pairs as set by the property
|
||||
<property>ConcurrentConsumers</property>. Here is a sample
|
||||
configuration</para>
|
||||
|
||||
@@ -933,13 +937,12 @@ namespace MyApp
|
||||
to an implementation of <literal>IExceptionHandler</literal> and
|
||||
registered with the container via the property
|
||||
<literal>ExceptionListener</literal>. The registered
|
||||
<literal>IExceptionHandler</literal> will be invoked if the
|
||||
exception is of the type <literal>NMSException</literal> (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
|
||||
<literal>IExceptionHandler</literal> will be invoked if the exception is
|
||||
of the type <literal>NMSException</literal> (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
|
||||
<literal>HandleListenerException</literal> to change this
|
||||
behavior.</para>
|
||||
|
||||
@@ -951,12 +954,11 @@ namespace MyApp
|
||||
<section>
|
||||
<title>The ISessionAwareMessageListener interface</title>
|
||||
|
||||
<para>The <literal>ISessionAwareMessageListener</literal> interface
|
||||
is a Spring-specific interface that provides a similar contract to the
|
||||
messaging provider's <literal>IMessageListener</literal> interface
|
||||
or Listener delegate/event, but also provides the message handling
|
||||
method with access to the Session from which the Message was
|
||||
received.</para>
|
||||
<para>The <literal>ISessionAwareMessageListener</literal> interface is a
|
||||
Spring-specific interface that provides a similar contract to the
|
||||
messaging provider's <literal>IMessageListener</literal> interface or
|
||||
Listener delegate/event, but also provides the message handling method
|
||||
with access to the Session from which the Message was received.</para>
|
||||
|
||||
<programlisting language="csharp">public interface ISessionAwareMessageListener
|
||||
{
|
||||
@@ -976,9 +978,8 @@ namespace MyApp
|
||||
of course some constraints).</para>
|
||||
|
||||
<para>Consider the following interface definition. Notice that although
|
||||
the interface extends neither the
|
||||
<literal>IMessageListener</literal> nor
|
||||
<literal>ISessionAwareMessageListener</literal> interfaces, it can
|
||||
the interface extends neither the <literal>IMessageListener</literal>
|
||||
nor <literal>ISessionAwareMessageListener</literal> interfaces, it can
|
||||
still be used as a Message-Driven PONOs (MDP) via the use of the
|
||||
<literal>MessageListenerAdapter</literal> class. Notice also how the
|
||||
various message handling methods are strongly typed according to the
|
||||
@@ -1042,8 +1043,7 @@ namespace MyApp
|
||||
}</programlisting>
|
||||
|
||||
<para>The configuration of the attendant
|
||||
<literal>MessageListenerAdapter</literal> would look like
|
||||
this</para>
|
||||
<literal>MessageListenerAdapter</literal> would look like this</para>
|
||||
|
||||
<programlisting language="myxml"><object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/>
|
||||
|
||||
@@ -1058,12 +1058,11 @@ namespace MyApp
|
||||
|
||||
<para>Please note that if the above 'MessageListener' receives a Message
|
||||
of a type other than ITextMessage, a
|
||||
<literal>ListenerExecutionFailedException</literal> will be thrown
|
||||
(and subsequently handled by the container by logging the
|
||||
exception).</para>
|
||||
<literal>ListenerExecutionFailedException</literal> will be thrown (and
|
||||
subsequently handled by the container by logging the exception).</para>
|
||||
|
||||
<para>If your <literal>IMessageConverter</literal> implementation
|
||||
will return multiple object types, overloading the handler method is
|
||||
<para>If your <literal>IMessageConverter</literal> 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
|
||||
<row>
|
||||
<entry>id</entry>
|
||||
|
||||
<entry><para>A object name for the hosting listener container.
|
||||
If not specified, a object name will be automatically
|
||||
generated.</para></entry>
|
||||
<entry>
|
||||
<para>A object name for the hosting listener container. If not
|
||||
specified, a object name will be automatically
|
||||
generated.</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>destination <emphasis
|
||||
role="bold">(required)</emphasis></entry>
|
||||
|
||||
<entry><para>The destination name for this listener, resolved
|
||||
through the <literal>IDestinationResolver</literal>
|
||||
strategy.</para></entry>
|
||||
<entry>
|
||||
<para>The destination name for this listener, resolved through
|
||||
the <literal>IDestinationResolver</literal> strategy.</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>ref <emphasis role="bold">(required)</emphasis></entry>
|
||||
|
||||
<entry><para>The object name of the handler
|
||||
object.</para></entry>
|
||||
<entry>
|
||||
<para>The object name of the handler object.</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>method</entry>
|
||||
|
||||
<entry><para>The name of the handler method to invoke. If the
|
||||
<literal>ref</literal> points to a
|
||||
<literal>IMessageListener</literal> or Spring
|
||||
<literal>ISessionAwareMessageListener</literal>,
|
||||
this attribute may be omitted.</para></entry>
|
||||
<entry>
|
||||
<para>The name of the handler method to invoke. If the
|
||||
<literal>ref</literal> points to a
|
||||
<literal>IMessageListener</literal> or Spring
|
||||
<literal>ISessionAwareMessageListener</literal>, this
|
||||
attribute may be omitted.</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>response-destination</entry>
|
||||
|
||||
<entry><para>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.</para></entry>
|
||||
<entry>
|
||||
<para>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.</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>subscription</entry>
|
||||
|
||||
<entry><para>The name of the durable subscription, if
|
||||
any.</para></entry>
|
||||
<entry>
|
||||
<para>The name of the durable subscription, if any.</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>selector</entry>
|
||||
|
||||
<entry><para>An optional message selector for this
|
||||
listener.</para></entry>
|
||||
<entry>
|
||||
<para>An optional message selector for this listener.</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>pubsub-domain</entry>
|
||||
|
||||
<entry><para>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.
|
||||
</para></entry>
|
||||
<entry>
|
||||
<para>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.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
@@ -1264,8 +1274,8 @@ namespace MyApp
|
||||
<para>The following table describes all available attributes. Consult
|
||||
the class-level SDK documentation of the
|
||||
<literal>AbstractMessageListenerContainer</literal> and its subclass
|
||||
<literal>SimpleMessageListenerContainer</literal> for more detail on
|
||||
the individual properties.</para>
|
||||
<literal>SimpleMessageListenerContainer</literal> for more detail on the
|
||||
individual properties.</para>
|
||||
|
||||
<table id="nms-namespace-listener-container-tbl">
|
||||
<title>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>
|
||||
</chapter>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<chapter xml:id="orm" xmlns="http://docbook.org/ns/docbook" version="5">
|
||||
<chapter version="5" xml:id="orm" 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>Object Relational Mapping (ORM) data access</title>
|
||||
|
||||
<section xml:id="orm-introduction">
|
||||
@@ -48,11 +53,11 @@
|
||||
<listitem>
|
||||
<para><emphasis>Ease of testing.</emphasis> Spring's IoC approach
|
||||
makes it easy to swap the implementations and config locations of
|
||||
Hibernate <literal>SessionFactory</literal> instances,
|
||||
ADO.NET <literal>DbProvider</literal> 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.</para>
|
||||
Hibernate <literal>SessionFactory</literal> instances, ADO.NET
|
||||
<literal>DbProvider</literal> 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.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
@@ -69,21 +74,20 @@
|
||||
<listitem>
|
||||
<para><emphasis>General resource management.</emphasis> Spring
|
||||
application contexts can handle the location and configuration of
|
||||
Hibernate <literal>ISessionFactory</literal> instances,
|
||||
ADO.NET <literal>DbProvider</literal> 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 <literal>Session</literal> for
|
||||
efficiency and proper transaction handling. Spring makes it easy to
|
||||
transparently create and bind a <literal>Session</literal>
|
||||
to the current thread, either by using an explicit 'template' wrapper
|
||||
class at the code level or by exposing a current
|
||||
<literal>Session</literal> through the Hibernate
|
||||
<literal>SessionFactory</literal> (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).</para>
|
||||
Hibernate <literal>ISessionFactory</literal> instances, ADO.NET
|
||||
<literal>DbProvider</literal> 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 <literal>Session</literal> for efficiency and proper
|
||||
transaction handling. Spring makes it easy to transparently create and
|
||||
bind a <literal>Session</literal> to the current thread, either by
|
||||
using an explicit 'template' wrapper class at the code level or by
|
||||
exposing a current <literal>Session</literal> through the Hibernate
|
||||
<literal>SessionFactory</literal> (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).</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
@@ -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 <literal>AdoTemplate</literal> 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 <literal>DataAccessException</literal> 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.</para>
|
||||
the <literal>AdoTemplate</literal> 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
|
||||
<literal>DataAccessException</literal> 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.</para>
|
||||
|
||||
<para>Spring also offers Hibernate support, consisting of a
|
||||
<literal>HibernateTemplate</literal> analogous to
|
||||
@@ -200,23 +204,22 @@
|
||||
the other the .NET 2.0 TransactionScope API.</para>
|
||||
|
||||
<para>The first strategy is encapsulated in the class
|
||||
<literal>Spring.Data.NHibernate.HibernateTransactionManager
|
||||
</literal>in both the <literal>Spring.Data.NHibernate
|
||||
</literal>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 <literal>HibernateTransactionManager</literal> is
|
||||
shown below.</para>
|
||||
<literal>Spring.Data.NHibernate.HibernateTransactionManager </literal>in
|
||||
both the <literal>Spring.Data.NHibernate </literal>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
|
||||
<literal>HibernateTransactionManager</literal> is shown below.</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="HibernateTransactionManager"
|
||||
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">
|
||||
@@ -227,17 +230,17 @@
|
||||
</object></programlisting>
|
||||
|
||||
<para>The important property of
|
||||
<literal>HibernateTransactionManager</literal> are the references to
|
||||
the DbProvider and the Hibernate ISessionFactory. For more information
|
||||
on the DbProvider, refer to the chapter <link
|
||||
<literal>HibernateTransactionManager</literal> are the references to the
|
||||
DbProvider and the Hibernate ISessionFactory. For more information on
|
||||
the DbProvider, refer to the chapter <link
|
||||
linkend="dbprovider">DbProvider</link> and the following section on
|
||||
SessionFactory set up.</para>
|
||||
|
||||
<para>The second strategy is to use the class
|
||||
<literal>Sping.Data.TxScopeTransactionManager</literal> 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.</para>
|
||||
<literal>Sping.Data.TxScopeTransactionManager</literal> 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.</para>
|
||||
|
||||
<para>Both strategies associate one Hibernate Session for the scope of
|
||||
the transaction (scope in the general demarcation sense, not
|
||||
@@ -264,13 +267,13 @@
|
||||
<para>To avoid tying application objects to hard-coded resource lookups,
|
||||
Spring allows you to define resources like a
|
||||
<literal>DbProvider</literal> or a Hibernate
|
||||
<literal>SessionFactory</literal> 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
|
||||
<literal>SessionFactory</literal> on top of it:</para>
|
||||
<literal>SessionFactory</literal> 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 <literal>SessionFactory</literal> on
|
||||
top of it:</para>
|
||||
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net"
|
||||
xmlns:db="http://www.springframework.net/database">
|
||||
@@ -352,9 +355,9 @@
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Delegate to the <literal>DbProvider</literal> itself as
|
||||
the NHibernate connection provider instead of listing it via
|
||||
property hibernate.connection.provider via
|
||||
<para>Delegate to the <literal>DbProvider</literal> itself as the
|
||||
NHibernate connection provider instead of listing it via property
|
||||
hibernate.connection.provider via
|
||||
<literal>HibernateProperties</literal>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
@@ -364,8 +367,8 @@
|
||||
hibernate.connection.provider is used and a warning level message is
|
||||
logged. If you use Spring's <literal>DbProvider</literal> as the
|
||||
NHibernate connection provider then you can take advantage of
|
||||
<literal>IDbProvider</literal> implementations that will let you
|
||||
change the connection string at runtime such as <link lang=""
|
||||
<literal>IDbProvider</literal> implementations that will let you change
|
||||
the connection string at runtime such as <link lang=""
|
||||
linkend="dbprovider-usercredentials">UserCredentialsDbProvider</link>
|
||||
and <link
|
||||
linkend="dbprovider-multidelegating">MultiDelegatingDbProvider</link>.</para>
|
||||
@@ -377,20 +380,19 @@
|
||||
linkend="dbprovider-multidelegating">MultiDelegatingDbProvider</link>
|
||||
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 <literal>ISessionFactory</literal> instance. As such, they
|
||||
are only useful for selecting at runtime a single database instance.
|
||||
to each <literal>ISessionFactory</literal> 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
|
||||
<literal>LocalSessionFactoryObject</literal> and override the
|
||||
method <literal>ISessionFactory NewSessionFactory(Configuration
|
||||
<literal>LocalSessionFactoryObject</literal> and override the method
|
||||
<literal>ISessionFactory NewSessionFactory(Configuration
|
||||
config)</literal> so that it returns an implementation of
|
||||
<literal>ISessionFactory</literal> that selects among multiple
|
||||
instances based on values in thread local storage, much like the
|
||||
implementation of
|
||||
<literal>MultiDelegatingDbProvider</literal>.</para>
|
||||
implementation of <literal>MultiDelegatingDbProvider</literal>.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
@@ -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
|
||||
<literal>SessionFactory</literal>. It can get the latter
|
||||
from anywhere, but preferably as an object reference from a Spring IoC
|
||||
container - via a simple <methodname>SessionFactory</methodname>
|
||||
property setter. The following snippets show a DAO definition in a
|
||||
Spring container, referencing the above defined
|
||||
<literal>SessionFactory</literal>, and an example for a DAO
|
||||
method implementation.</para>
|
||||
<literal>SessionFactory</literal>. It can get the latter from anywhere,
|
||||
but preferably as an object reference from a Spring IoC container - via
|
||||
a simple <methodname>SessionFactory</methodname> property setter. The
|
||||
following snippets show a DAO definition in a Spring container,
|
||||
referencing the above defined <literal>SessionFactory</literal>, and an
|
||||
example for a DAO method implementation.</para>
|
||||
|
||||
<programlisting language="myxml"><objects>
|
||||
|
||||
@@ -437,11 +438,11 @@
|
||||
|
||||
<para>The <literal>HibernateTemplate</literal> class provides many
|
||||
methods that mirror the methods exposed on the Hibernate
|
||||
<literal>Session</literal> interface, in addition to a
|
||||
number of convenience methods such as the one shown above. If you need
|
||||
access to the <literal>Session</literal> to invoke methods
|
||||
that are not exposed on the <literal>HibernateTemplate</literal>,
|
||||
you can always drop down to a callback-based approach like so.</para>
|
||||
<literal>Session</literal> interface, in addition to a number of
|
||||
convenience methods such as the one shown above. If you need access to
|
||||
the <literal>Session</literal> to invoke methods that are not exposed on
|
||||
the <literal>HibernateTemplate</literal>, you can always drop down to a
|
||||
callback-based approach like so.</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
@@ -483,20 +484,20 @@
|
||||
inside the anonymous delegate implementation.</para>
|
||||
|
||||
<para>A callback implementation effectively can be used for any
|
||||
Hibernate data access. <literal>HibernateTemplate</literal> will
|
||||
ensure that <literal>Session</literal> 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, <literal>HibernateTemplate</literal> offers alternative
|
||||
convenience methods that can replace such one line callback
|
||||
implementations. Furthermore, Spring provides a convenient
|
||||
Hibernate data access. <literal>HibernateTemplate</literal> will ensure
|
||||
that <literal>Session</literal> 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,
|
||||
<literal>HibernateTemplate</literal> offers alternative convenience
|
||||
methods that can replace such one line callback implementations.
|
||||
Furthermore, Spring provides a convenient
|
||||
<literal>HibernateDaoSupport</literal> base class that provides a
|
||||
<methodname>SessionFactory</methodname> property for receiving a
|
||||
<literal>SessionFactory</literal> and for use by subclasses.
|
||||
In combination, this allows for very simple DAO implementations for
|
||||
typical requirements:</para>
|
||||
<literal>SessionFactory</literal> and for use by subclasses. In
|
||||
combination, this allows for very simple DAO implementations for typical
|
||||
requirements:</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
|
||||
{
|
||||
@@ -512,22 +513,21 @@
|
||||
<title>Implementing Spring-based DAOs without callbacks</title>
|
||||
|
||||
<para>As an alternative to using Spring's
|
||||
<literal>HibernateTemplate</literal> 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
|
||||
<literal>DataAccessException</literal> hierarchy. The
|
||||
<literal>HibernateDaoSupport</literal> base class offers methods to
|
||||
access the current transactional <literal>Session</literal>
|
||||
<literal>HibernateTemplate</literal> 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 <literal>DataAccessException</literal>
|
||||
hierarchy. The <literal>HibernateDaoSupport</literal> base class offers
|
||||
methods to access the current transactional <literal>Session</literal>
|
||||
and to convert exceptions in such a scenario; similar methods are also
|
||||
available as static helpers on the
|
||||
<literal>SessionFactoryUtils</literal> class. Note that such code
|
||||
will usually pass '<literal>false</literal>' as the value of the
|
||||
<literal>SessionFactoryUtils</literal> class. Note that such code will
|
||||
usually pass '<literal>false</literal>' as the value of the
|
||||
<methodname>DoGetSession(..)</methodname> method's
|
||||
'<literal>allowCreate</literal>' argument, to enforce running within a
|
||||
transaction (which avoids the need to close the returned
|
||||
<literal>Session</literal>, as its lifecycle is managed by
|
||||
the transaction). Asking for the</para>
|
||||
<literal>Session</literal>, as its lifecycle is managed by the
|
||||
transaction). Asking for the</para>
|
||||
|
||||
<programlisting language="csharp">public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
|
||||
|
||||
@@ -540,20 +540,19 @@
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>This code will not translate the Hibernate exception to a generic
|
||||
DataAccessException.</para>
|
||||
<para>This code will <emphasis>not</emphasis> translate the Hibernate
|
||||
exception to a generic <literal>DataAccessException</literal>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="orm-hibernate-straight">
|
||||
<title>Implementing DAOs based on plain Hibernate 1.2 API</title>
|
||||
<title>Implementing DAOs based on plain Hibernate 1.2/2.0 API</title>
|
||||
|
||||
<para>Hibernate 1.2 introduced a feature called "contextual Sessions",
|
||||
where Hibernate itself manages one current
|
||||
<literal>ISession</literal> per transaction. This is roughly
|
||||
equivalent to Spring's synchronization of one Hibernate
|
||||
<literal>Session</literal> per transaction. A corresponding
|
||||
DAO implementation looks like as follows, based on the plain Hibernate
|
||||
API:</para>
|
||||
where Hibernate itself manages one current <literal>ISession</literal>
|
||||
per transaction. This is roughly equivalent to Spring's synchronization
|
||||
of one Hibernate <literal>Session</literal> per transaction. A
|
||||
corresponding DAO implementation looks like as follows, based on the
|
||||
plain Hibernate API:</para>
|
||||
|
||||
<programlisting language="csharp">public class ProductDaoImpl implements IProductDao {
|
||||
|
||||
@@ -592,8 +591,8 @@ public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
<para>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 <literal>HibernateTemplate</literal>. Of course, such a DAO
|
||||
can also be set up in plain C# (for example, in unit tests): simply
|
||||
Spring's <literal>HibernateTemplate</literal>. Of course, such a DAO can
|
||||
also be set up in plain C# (for example, in unit tests): simply
|
||||
instantiate it and call <methodname>SessionFactory</methodname> property
|
||||
with the desired factory reference. As a Spring object definition, it
|
||||
would look as follows:</para>
|
||||
@@ -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.</para>
|
||||
|
||||
<para>However, the DAO throws plain
|
||||
<literal>HibernateException</literal> 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.</para>
|
||||
<section xml:id="orm-hibernate-straight-ex">
|
||||
<title>Exception Translation</title>
|
||||
|
||||
<para>Fortunately, Spring's
|
||||
<literal>LocalSessionFactoryObject</literal> supports Hibernate's
|
||||
<methodname>SessionFactory.GetCurrentSession()</methodname> method for
|
||||
any Spring transaction strategy, returning the current Spring-managed
|
||||
transactional <literal>Session</literal> even with
|
||||
<literal>HibernateTransactionManager</literal>.</para>
|
||||
<para>However, the DAO implemenation as shown throws plain
|
||||
<literal>HibernateException</literal> 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.</para>
|
||||
|
||||
<para>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.</para>
|
||||
<para>Spring offers a solution allowing exception translation to be
|
||||
applied transparently through the <literal>[Repository]</literal>
|
||||
attribute:</para>
|
||||
|
||||
<programlisting language="csharp">[Repository]
|
||||
public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
// class body here
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>and register an exception translation post processor.</para>
|
||||
|
||||
<programlisting><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></programlisting>
|
||||
|
||||
<para>The postprocessor will automatically look for all exception
|
||||
translators (implementations of the
|
||||
<literal>IPersistenceExceptionTranslator</literal> interface) and
|
||||
advise all object marked with the <literal>[Repository]</literal>
|
||||
attribute so that the discovered translators can intercept and apply
|
||||
the appropriate translation on the thrown exceptions. Spring's
|
||||
<literal>LocalSessionFactory</literal> object implements the
|
||||
<literal>IPersistenceExceptionTranslator</literal> interface and
|
||||
performs the same exception translation as was done when using
|
||||
<literal>HibernateTemplate</literal>.</para>
|
||||
|
||||
<para>The <literal>[Repository</literal>] 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
|
||||
<literal>PersistenceExceptionTranslationPostProcessor's</literal>
|
||||
property <literal>RepositoryAttributeType</literal> to your own
|
||||
attribute type.</para>
|
||||
|
||||
<para><note>
|
||||
<para>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.</para>
|
||||
</note></para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="orm-hibernate-tx-programmatic">
|
||||
@@ -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 <literal>PlatformTransactionManager</literal>. Again,
|
||||
the latter can come from anywhere, but preferably as an object reference
|
||||
via a <methodname>TransactionManager</methodname> property - just like
|
||||
the <literal>productDAO</literal> should be set via a
|
||||
needs a Spring <literal>PlatformTransactionManager</literal>. Again, the
|
||||
latter can come from anywhere, but preferably as an object reference via
|
||||
a <methodname>TransactionManager</methodname> property - just like the
|
||||
<literal>productDAO</literal> should be set via a
|
||||
<methodname>setProductDao(..)</methodname> 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 {
|
||||
|
||||
<programlisting language="myxml"><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></programlisting>
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}</programlisting>
|
||||
</section>
|
||||
@@ -846,19 +933,17 @@ TO BE DONE
|
||||
<title>Transaction management strategies</title>
|
||||
|
||||
<para>Both <literal>TransactionTemplate</literal> and
|
||||
<literal>TransactionInterceptor</literal> (not yet seen explicitly
|
||||
in above configuration, TransactionProxyFactoryObject uses a
|
||||
<literal>TransactionInterceptor</literal> (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
|
||||
<literal>PlatformTransactionManager</literal> instance, which can be
|
||||
a <literal>HibernateTransactionManager</literal> (for a single
|
||||
Hibernate <literal>SessionFactory</literal>, using a
|
||||
<literal>ThreadLocal</literal>
|
||||
<literal>Session</literal> under the hood) or a
|
||||
<literal>TxScopeTransactionManager</literal> (delegating to MS-DTC
|
||||
for distributed transaction) for Hibernate applications. You could even
|
||||
use a custom <literal>PlatformTransactionManager</literal>
|
||||
transaction handling to a <literal>PlatformTransactionManager</literal>
|
||||
instance, which can be a <literal>HibernateTransactionManager</literal>
|
||||
(for a single Hibernate <literal>SessionFactory</literal>, using a
|
||||
<literal>ThreadLocal</literal> <literal>Session</literal> under the
|
||||
hood) or a <literal>TxScopeTransactionManager</literal> (delegating to
|
||||
MS-DTC for distributed transaction) for Hibernate applications. You
|
||||
could even use a custom <literal>PlatformTransactionManager</literal>
|
||||
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.</para>
|
||||
|
||||
<para>For distributed transactions across multiple Hibernate session
|
||||
factories, simply combine
|
||||
<literal>TxScopeTransactionManager</literal> as a transaction
|
||||
strategy with multiple <literal>LocalSessionFactoryObject</literal>
|
||||
definitions. Each of your DAOs then gets one specific
|
||||
<literal>SessionFactory</literal> reference passed into it's
|
||||
respective object property.</para>
|
||||
factories, simply combine <literal>TxScopeTransactionManager</literal>
|
||||
as a transaction strategy with multiple
|
||||
<literal>LocalSessionFactoryObject</literal> definitions. Each of your
|
||||
DAOs then gets one specific <literal>SessionFactory</literal> reference
|
||||
passed into it's respective object property.</para>
|
||||
|
||||
<programlisting>TO BE DONE
|
||||
</programlisting>
|
||||
|
||||
<para><literal>HibernateTransactionManager</literal> can export the
|
||||
ADO.NET <literal>Transaction</literal> used by Hibernate to
|
||||
plain ADO.NET access code, for a specific
|
||||
<literal>DbProvider</literal>. (matching connection string).
|
||||
This allows for high-level transaction demarcation with mixed
|
||||
Hibernate/ADO.NET data access!</para>
|
||||
ADO.NET <literal>Transaction</literal> used by Hibernate to plain
|
||||
ADO.NET access code, for a specific <literal>DbProvider</literal>.
|
||||
(matching connection string). This allows for high-level transaction
|
||||
demarcation with mixed Hibernate/ADO.NET data access!</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="orm-hibernate-web">
|
||||
@@ -962,4 +1045,4 @@ TO BE DONE
|
||||
this chapter for further information on those usage scenarios.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<chapter xml:id="wcf" xmlns="http://docbook.org/ns/docbook" version="5">
|
||||
<chapter version="5" xml:id="wcf" 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>Windows Communication Foundation (WCF)</title>
|
||||
|
||||
<section xml:id="wcf-introduction">
|
||||
@@ -26,19 +31,6 @@
|
||||
dependency injection and add additional behavior to them using
|
||||
Aspect-Oriented programming (AOP).</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>For those who would like to get their feet wet right way, check out
|
||||
the WcfQuickStart application in the examples directory.</para>
|
||||
</section>
|
||||
@@ -117,18 +109,17 @@
|
||||
<para>To host this service type in a standalone application define an
|
||||
instance of a
|
||||
<literal>Spring.ServiceModel.Activation.ServiceHostFactoryObject</literal>
|
||||
and set is property <literal>TargetName</literal> to the id value of
|
||||
the previously defined service type.
|
||||
and set is property <literal>TargetName</literal> to the id value of the
|
||||
previously defined service type.
|
||||
<literal>ServiceHostFactoryObject</literal> is a Spring
|
||||
<literal>IFactoryObject</literal> implementation. (See <link
|
||||
linkend="objects-factory-lifecycle-factoryobject">here</link> for more
|
||||
information on <literal>IFactoryObjects</literal> and their
|
||||
interaction with the container.) The
|
||||
<literal>ServiceHostFactoryObject</literal> will create an instance
|
||||
of
|
||||
<literal>Spring.ServiceModel.Activation.SpringServiceHost</literal>
|
||||
that will be the ServiceHost instance associated with your service type.
|
||||
This configuration for this step is shown below.</para>
|
||||
information on <literal>IFactoryObjects</literal> and their interaction
|
||||
with the container.) The <literal>ServiceHostFactoryObject</literal>
|
||||
will create an instance of
|
||||
<literal>Spring.ServiceModel.Activation.SpringServiceHost</literal> that
|
||||
will be the ServiceHost instance associated with your service type. This
|
||||
configuration for this step is shown below.</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="calculatorServiceHost" type="Spring.ServiceModel.Activation.ServiceHostFactoryObject, Spring.Services">
|
||||
<property name="TargetName" value="calculator" />
|
||||
@@ -155,21 +146,21 @@
|
||||
</note>
|
||||
|
||||
<para><literal>Spring.ServiceModel.Activation.SpringServiceHost
|
||||
</literal>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,
|
||||
<literal>ApplicationContext.GetObject(name)</literal>. Since the
|
||||
object retrieved in this manner is fully configured, your WCF service is
|
||||
as well.</para>
|
||||
</literal>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,
|
||||
<literal>ApplicationContext.GetObject(name)</literal>. Since the object
|
||||
retrieved in this manner is fully configured, your WCF service is as
|
||||
well.</para>
|
||||
|
||||
<para>Outside of a standalone application you can also use the class
|
||||
<literal>Spring.ServiceModel.Activation.ServiceHostFactory</literal>
|
||||
(which inherits from
|
||||
<literal>System.ServiceModel.Activation.ServiceHostFactory</literal>)
|
||||
to host your services so that they can be configured via dependency
|
||||
<literal>System.ServiceModel.Activation.ServiceHostFactory</literal>) 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
|
||||
<literal>Spring.ServiceModel.Activation.ServiceHostFactory</literal>
|
||||
to host your service inside IIS but should still refer to the service by
|
||||
<literal>Spring.ServiceModel.Activation.ServiceHostFactory</literal> to
|
||||
host your service inside IIS but should still refer to the service by
|
||||
the name of the object in the Spring container.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="wcf-di-extension-points">
|
||||
<title>Dependency Injection using WCF extensibility points.</title>
|
||||
|
||||
<para>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 <ulink
|
||||
url="http://orand.blogspot.com/2006/10/wcf-service-dependency-injection.html">blog</ulink>
|
||||
and several other folks on the web since then. In this approach Spring
|
||||
specific implementations of the WCF interfaces
|
||||
<literal>System.ServiceModel.Dispatcher.IInstanceProvider</literal>
|
||||
and
|
||||
<literal>System.ServiceModel.Description.IServiceBehavior</literal>
|
||||
are used to integrate Spring directly into the instancing of WCF
|
||||
services.</para>
|
||||
|
||||
<para>Spring's implementation of
|
||||
<literal>IInstanceProvider</literal> is
|
||||
<literal>Spring.ServiceModel.Support.SpringInstanceProvider</literal>.
|
||||
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
|
||||
<literal>SpringInstanceProvider</literal> is used by a custom
|
||||
service behavior class,
|
||||
<literal>Spring.ServiceModel.Support.SpringServiceBehavior</literal>
|
||||
where it is applied to all the service endpoints. This behavior is then
|
||||
added to the custom service host
|
||||
<literal>Spring.ServiceModel.Activation.SpringServiceHost</literal></para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<programlisting language="myxml"><%@ ServiceHost Language="C#" Debug="true" Service="Spring.WcfQuickStart.CalculatorService"
|
||||
Factory="Spring.ServiceModel.Activation.ServiceHostFactory" %>
|
||||
</programlisting>
|
||||
|
||||
<para>The Spring configuration for the object is shown below.</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="calculator" type="Spring.WcfQuickStart.CalculatorService, App_Code" <emphasis
|
||||
role="bold">singleton="false"</emphasis>>
|
||||
<property name="SleepInSeconds" value="1"/>
|
||||
</object></programlisting>
|
||||
|
||||
<note>
|
||||
<para>The object must be declared as a 'prototype' object, i.e. not a
|
||||
singleton, in order to interact correctly with WCF instancing.</para>
|
||||
</note>
|
||||
|
||||
<para>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
|
||||
<literal>[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]</literal>
|
||||
then the invocation of the <literal>IInstanceProvider</literal> is
|
||||
short-circuited. See the notes on the MSDN class documentation <ulink
|
||||
url="http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iinstanceprovider.aspx">here</ulink>.
|
||||
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.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="wcf-aop">
|
||||
@@ -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
|
||||
<literal>Spring.WcfQuickStart</literal> namespace and is taken from
|
||||
the QuickStart example.</para>
|
||||
<literal>Spring.WcfQuickStart</literal> namespace and is taken from the
|
||||
QuickStart example.</para>
|
||||
|
||||
<programlisting language="myxml"> <object id="serviceOperation" type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop">
|
||||
<property name="pattern" value="Spring.WcfQuickStart.*"/>
|
||||
@@ -299,7 +225,7 @@
|
||||
</object></programlisting>
|
||||
|
||||
<note>
|
||||
<para>This will be shortened using a custom namespce in the 1.2 RC1
|
||||
<para>This will be shortened using a custom namespce in the 1.2 final
|
||||
release</para>
|
||||
</note>
|
||||
|
||||
@@ -307,4 +233,44 @@
|
||||
enpoints in the <client> section of the standard WCF configuration
|
||||
inside of App.config.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
<section>
|
||||
<title>Exporting PONOs as WCF Services</title>
|
||||
|
||||
<para>Much like the approach taken for .asmx web services Spring provides
|
||||
an exporter that will add <literal>[ServiceContract] </literal>and
|
||||
<literal>[OperationContract]</literal> attributes by default to all public
|
||||
interface methods on a given (PONO) class. The exporter class is
|
||||
<literal>Spring.ServiceModel.ServiceExporter</literal> 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</para>
|
||||
|
||||
<programlisting><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></programlisting>
|
||||
|
||||
<para>Spring does not provide any means to add<literal>
|
||||
[DataContract]</literal> or <literal>[DataMember]</literal> 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 <literal>ISerializable</literal> interface, having the
|
||||
<literal>[Serializable]</literal> 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
|
||||
<literal>DataContractSerializer</literal>. </para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
@@ -16,12 +16,135 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<chapter xml:id="web" xmlns="http://docbook.org/ns/docbook" version="5">
|
||||
<chapter version="5" xml:id="web" 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>Spring.NET Web Framework</title>
|
||||
|
||||
<sect1 xml:id="web-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>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. </para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>Highlights of Spring's Web framework are</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><link linkend="web-di">Dependency Injection</link> 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.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link linkend="web-databinding">Bi-directional data
|
||||
binding</link>. 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.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link linkend="web-objectscope">Web object scopes</link>. 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</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link linkend="web-databinding">Data Model Management</link>.
|
||||
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.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link linkend="web-validation-controls">UI agnostic validation
|
||||
framework</link>. 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</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link linkend="web-resultmapping">Externalized page navigation
|
||||
through 'result mapping'</link>. 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.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Improved <link linkend="web-localization">localization</link>
|
||||
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.</para>
|
||||
|
||||
<para> </para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>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. </para>
|
||||
|
||||
<note>
|
||||
<para>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.</para>
|
||||
</note>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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 <xref
|
||||
linkend="springair" />).</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Background</title>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para></para>
|
||||
|
||||
<para>Spring.Web also adds support for applying the dependency injection
|
||||
principle to one's ASP.NET <literal>Pages</literal> and
|
||||
<literal>Controls</literal> 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
|
||||
<literal>Controls</literal> 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 <link linkend="web-di">Dependency Injection
|
||||
for ASP.NET Pages</link> for more information.</para>
|
||||
|
||||
@@ -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
|
||||
<literal>DataSet</literal>. 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 <link linkend="web-databinding">Bidirectional Data
|
||||
Binding and Model Management</link> for more information.</para>
|
||||
<literal>DataSet</literal>. 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 <link linkend="web-databinding">Bidirectional Data Binding and
|
||||
Model Management</link> for more information.</para>
|
||||
|
||||
<para>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 <literal>Response.Redirect</literal> or
|
||||
<literal>Server.Transfer</literal> calls within
|
||||
<literal>Page</literal> logic to navigate to an appropriate page after
|
||||
an action is executed. This typically leads to hard-coded target URLs in
|
||||
the <literal>Page</literal>, 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 <link
|
||||
linkend="web-resultmapping">Result Mapping</link> for more
|
||||
information.</para>
|
||||
<literal>Server.Transfer</literal> calls within <literal>Page</literal>
|
||||
logic to navigate to an appropriate page after an action is executed. This
|
||||
typically leads to hard-coded target URLs in the <literal>Page</literal>,
|
||||
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 <link linkend="web-resultmapping">Result
|
||||
Mapping</link> for more information.</para>
|
||||
|
||||
<para>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 <literal>Page</literal> 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 <link
|
||||
resource file for each ASP.NET <literal>Page</literal> 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 <link
|
||||
linkend="web-localization">Localization and Message Sources</link> for
|
||||
more information.</para>
|
||||
|
||||
@@ -124,27 +244,18 @@
|
||||
<para>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 <literal>Page</literal> and
|
||||
<literal>UserControl</literal> classes. This means that in order to
|
||||
take advantage of the <emphasis>full</emphasis> 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 <literal>Spring.Web.UI.Page</literal>;
|
||||
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 <emphasis>some</emphasis> of the more useful features
|
||||
offered by Spring.Web you will be coupling the presentation tier of your
|
||||
<literal>UserControl</literal> classes. This means that in order to take
|
||||
advantage of the <emphasis>full</emphasis> 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 <literal>Spring.Web.UI.Page</literal>; 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 <emphasis>some</emphasis> 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.</para>
|
||||
|
||||
<para>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 <xref
|
||||
linkend="springair" />).</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="web-contexts">
|
||||
@@ -159,13 +270,12 @@
|
||||
means that all of the controllers (ASP.NET <literal>Page</literal>s)
|
||||
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 <literal>PageHandlerFactory</literal> implementation
|
||||
to load and configure a Spring.NET IoC container, which is in turn used
|
||||
to locate an appropriate <literal>Page</literal> to handle a HTTP
|
||||
request. The <literal>WebSupportModule</literal> configures
|
||||
miscellaneous Spring infrastructure classes for use in a web
|
||||
environment, for example setting the storage strategy of
|
||||
<literal>LogicalThreadContext</literal> to be
|
||||
uses a custom <literal>PageHandlerFactory</literal> implementation to
|
||||
load and configure a Spring.NET IoC container, which is in turn used to
|
||||
locate an appropriate <literal>Page</literal> to handle a HTTP request.
|
||||
The <literal>WebSupportModule</literal> configures miscellaneous Spring
|
||||
infrastructure classes for use in a web environment, for example setting
|
||||
the storage strategy of <literal>LogicalThreadContext</literal> to be
|
||||
<literal>HybridContextStorage</literal>.</para>
|
||||
|
||||
<para>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 <literal>.aspx</literal>
|
||||
<literal>Page</literal>, (possibly) inject dependencies into said
|
||||
<literal>Page</literal> (as required), and then forward the handling
|
||||
of the request to said <literal>Page</literal>.</para>
|
||||
<literal>Page</literal> (as required), and then forward the handling of
|
||||
the request to said <literal>Page</literal>.</para>
|
||||
|
||||
<para>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 @@
|
||||
|
||||
<listitem>
|
||||
<para>The custom configuration section handler is of the type
|
||||
<literal>Spring.Context.Support.WebContextHandler</literal>
|
||||
which will in turn instantiate an IoC container of the type
|
||||
<literal>Spring.Context.Support.WebContextHandler</literal> which
|
||||
will in turn instantiate an IoC container of the type
|
||||
<literal>Spring.Context.Support.WebApplicationContext</literal>.
|
||||
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 @@
|
||||
|
||||
<para>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 <literal>Page</literal> mechanism to
|
||||
satisfy the <literal>Controller</literal> portion of the MVC architectural
|
||||
the code-behind class of the <literal>Page</literal> mechanism to satisfy
|
||||
the <literal>Controller</literal> portion of the MVC architectural
|
||||
pattern. In MVC-based (web) applications, the
|
||||
<literal>Controller</literal> 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 <literal>Page</literal>
|
||||
<literal>Controller</literal>s. Accordingly, Spring.Web provides first
|
||||
class support for dependency injection in ASP.NET
|
||||
<literal>Page</literal>s. This allows application developers to inject
|
||||
any required service object dependencies (and indeed any other
|
||||
dependencies) into their <literal>Page</literal>s using standard
|
||||
Spring.NET configuration instead of having to rely on custom service
|
||||
locators or manual object lookups in a Spring.NET application
|
||||
context.</para>
|
||||
<literal>Page</literal>s. This allows application developers to inject any
|
||||
required service object dependencies (and indeed any other dependencies)
|
||||
into their <literal>Page</literal>s using standard Spring.NET
|
||||
configuration instead of having to rely on custom service locators or
|
||||
manual object lookups in a Spring.NET application context.</para>
|
||||
|
||||
<para>Once an application developer has <link
|
||||
linkend="web-configuration">configured</link> the Spring.NET web
|
||||
@@ -476,15 +585,14 @@
|
||||
pages from the configuration of other .NET classes is in the value passed
|
||||
to the <literal>type</literal> attribute. As can be seen in the above
|
||||
configuration snippet the <literal>type</literal> name is actually the
|
||||
path to the <literal>.aspx</literal> file for the
|
||||
<literal>Page</literal>, relative to the directory context it is
|
||||
defined in. In the case of the above example, those definitions are in the
|
||||
root context so <literal>Login.aspx</literal> and
|
||||
<literal>Default.aspx</literal> 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.</para>
|
||||
path to the <literal>.aspx</literal> file for the <literal>Page</literal>,
|
||||
relative to the directory context it is defined in. In the case of the
|
||||
above example, those definitions are in the root context so
|
||||
<literal>Login.aspx</literal> and <literal>Default.aspx</literal> 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.</para>
|
||||
|
||||
<para>The astute reader may have noticed that the definitions for the
|
||||
<literal>Login</literal> and <literal>Default</literal> pages don't
|
||||
@@ -493,13 +601,13 @@
|
||||
Spring.NET, where the <literal>id</literal> or <literal>name</literal>
|
||||
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 <literal>Page</literal>
|
||||
<literal>Controller</literal> instances one typically wants to use the
|
||||
name of the <literal>.aspx</literal> file name as the identifier. If an
|
||||
case of Spring.Web <literal>Page</literal> <literal>Controller</literal>
|
||||
instances one typically wants to use the name of the
|
||||
<literal>.aspx</literal> file name as the identifier. If an
|
||||
<literal>id</literal> is not specified, the Spring.Web infrastructure will
|
||||
simply use the name of the <literal>.aspx</literal> file as the object
|
||||
identifier (minus any leading path information, and minus the file
|
||||
extension too). </para>
|
||||
extension too).</para>
|
||||
|
||||
<para>Nothing prevents an application developer from specifying an
|
||||
<literal>id</literal> or <literal>name</literal> value explicitly; one use
|
||||
@@ -536,10 +644,10 @@
|
||||
|
||||
<para>You can perform dependency injection on custom HTTP modules
|
||||
through the use of the class
|
||||
<literal>Spring.Context.Support.HttpApplicationConfigurer</literal>.
|
||||
You register your custom HTTP module as you would normally, for example
|
||||
a module of the type <literal>HtmlCommentAppenderModule</literal>,
|
||||
taken from the Web Quickstart, appends additional comments into the http
|
||||
<literal>Spring.Context.Support.HttpApplicationConfigurer</literal>. You
|
||||
register your custom HTTP module as you would normally, for example a
|
||||
module of the type <literal>HtmlCommentAppenderModule</literal>, taken
|
||||
from the Web Quickstart, appends additional comments into the http
|
||||
response. It is registered as shown below</para>
|
||||
|
||||
<programlisting language="myxml"><httpModules>
|
||||
@@ -706,7 +814,7 @@ class MyControl : Control, ISupportsWebDependencyInjection
|
||||
</sect1>
|
||||
|
||||
<sect1 xml:id="web-objectscope">
|
||||
<title>Object Scope</title>
|
||||
<title>Web object scopes</title>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>Both the <literal>ContentPlaceHolder</literal> and
|
||||
<literal>Content</literal> controls can contain any valid ASP.NET
|
||||
markup: HTML, standard ASP.NET controls, user controls, etc.</para>
|
||||
<literal>Content</literal> controls can contain any valid ASP.NET markup:
|
||||
HTML, standard ASP.NET controls, user controls, etc.</para>
|
||||
|
||||
<tip>
|
||||
<title>VS.NET 2003 issue</title>
|
||||
@@ -840,9 +948,9 @@ class MyControl : Control, ISupportsWebDependencyInjection
|
||||
<sect2 xml:id="web-childpage-linking">
|
||||
<title>Linking child pages to their master</title>
|
||||
|
||||
<para>The <literal>Spring.Web.UI.Page</literal> class exposes a
|
||||
property called <literal>MasterPageFile</literal>, which can be used to
|
||||
specify the master page.</para>
|
||||
<para>The <literal>Spring.Web.UI.Page</literal> class exposes a property
|
||||
called <literal>MasterPageFile</literal>, which can be used to specify
|
||||
the master page.</para>
|
||||
|
||||
<para>The recommended way to do this is by leveraging the Spring.NET IoC
|
||||
container and creating definitions similar to the following:</para>
|
||||
@@ -905,7 +1013,8 @@ class MyControl : Control, ISupportsWebDependencyInjection
|
||||
management methods: <literal>InitializeModel</literal>,
|
||||
<literal>LoadModel</literal> and <literal>SaveModel</literal>. This is
|
||||
perhaps best illustrated by an example from the SpringAir reference
|
||||
application. First, let's take a look at the page markup:<programlisting language="myxml"><%@ Page Language="c#" Inherits="TripForm" CodeFile="TripForm.aspx.cs" %>
|
||||
application. First, let's take a look at the page markup:<programlisting
|
||||
language="myxml"><%@ 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
|
||||
<literal>TripPoint</literal> class to represent departure and return,
|
||||
which are exposed as <literal>StartingFrom</literal> and
|
||||
<literal>ReturningFrom</literal> properties. It also uses
|
||||
<literal>TripMode</literal> enumeration to specify whether the trip is
|
||||
one way or return trip, which is exposed as <literal>Mode</literal>
|
||||
<literal>TripMode</literal> enumeration to specify whether the trip is one
|
||||
way or return trip, which is exposed as <literal>Mode</literal>
|
||||
property.</para>
|
||||
|
||||
<para>Finally, let's see the code-behind class that ties everything
|
||||
@@ -1266,9 +1375,9 @@ class MyControl : Control, ISupportsWebDependencyInjection
|
||||
commonly used binding type, <literal>SimpleExpressionBinding</literal>.
|
||||
The <literal>SimpleExpressionBinding</literal> is what we used in the
|
||||
example at the beginning of this section to bind our web form to a
|
||||
<literal>Trip</literal> instance. It uses Spring.NET Expression
|
||||
Language to extract and to set values within source and target objects.
|
||||
We discussed <literal>sourceExpression</literal> and
|
||||
<literal>Trip</literal> instance. It uses Spring.NET Expression Language
|
||||
to extract and to set values within source and target objects. We
|
||||
discussed <literal>sourceExpression</literal> and
|
||||
<literal>targetExpression</literal> arguments earlier, so let's focus on
|
||||
the remaining ones.</para>
|
||||
|
||||
@@ -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 <literal>Airport</literal>
|
||||
class and modify our <literal>TripPoint</literal> class like
|
||||
the sake of discussion, let's add the <literal>Airport</literal> class
|
||||
and modify our <literal>TripPoint</literal> class like
|
||||
this:<programlisting language="csharp">namespace SpringAir.Domain
|
||||
{
|
||||
[Serializable]
|
||||
@@ -1346,14 +1455,14 @@ class MyControl : Control, ISupportsWebDependencyInjection
|
||||
}
|
||||
}
|
||||
}</programlisting>Instead of the string property
|
||||
<literal>AirportCode</literal>, our <literal>TripPoint</literal>
|
||||
class now exposes an <literal>Airport</literal> property of type
|
||||
<literal>AirportCode</literal>, our <literal>TripPoint</literal> class
|
||||
now exposes an <literal>Airport</literal> property of type
|
||||
<literal>Airport</literal>, 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 <literal>Airport</literal> binding, so let's see
|
||||
how we can solve this mismatch problem.</para>
|
||||
simple string to <literal>Airport</literal> binding, so let's see how
|
||||
we can solve this mismatch problem.</para>
|
||||
|
||||
<para>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 <literal>Code</literal> property of the
|
||||
<literal>Airport</literal> object, but that will likely make the
|
||||
<literal>Airport.Name</literal> property invalid. What we really want
|
||||
do is find an instance of the <literal>Airport</literal> class
|
||||
based on the airport code and set the
|
||||
<literal>TripPoint.Airport</literal> property to it. Fortunately, this
|
||||
is very simple to do with Spring.NET data binding, especially because
|
||||
we already have <literal>airportDao</literal> object defined in the
|
||||
Spring context, which has <literal>GetAirport(string
|
||||
airportCode)</literal> 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:<programlisting language="csharp">protected override void InitializeDataBindings()
|
||||
do is find an instance of the <literal>Airport</literal> class based
|
||||
on the airport code and set the <literal>TripPoint.Airport</literal>
|
||||
property to it. Fortunately, this is very simple to do with Spring.NET
|
||||
data binding, especially because we already have
|
||||
<literal>airportDao</literal> object defined in the Spring context,
|
||||
which has <literal>GetAirport(string airportCode)</literal> 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:<programlisting language="csharp">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:<programlisting language="csharp">public interface IFormatter
|
||||
is implement a very simple IFormatter interface:<programlisting
|
||||
language="csharp">public interface IFormatter
|
||||
{
|
||||
string Format(object value);
|
||||
object Parse(string value);
|
||||
@@ -1439,9 +1548,8 @@ class MyControl : Control, ISupportsWebDependencyInjection
|
||||
<sect3 xml:id="web-binding-events">
|
||||
<title>Data Binding Events</title>
|
||||
|
||||
<para>Spring.Web's base <literal>Page</literal> class adds two
|
||||
events to the standard .NET page lifecycle -
|
||||
<literal>DataBound</literal> and
|
||||
<para>Spring.Web's base <literal>Page</literal> class adds two events
|
||||
to the standard .NET page lifecycle - <literal>DataBound</literal> and
|
||||
<literal>DataUnbound</literal>.</para>
|
||||
|
||||
<para>The <literal>DataUnbound</literal> event is fired after the data
|
||||
@@ -1829,8 +1937,8 @@ protected override void InitializeDataBindings()
|
||||
</important>
|
||||
|
||||
<para>The global resources are cached within the Spring.NET
|
||||
<literal>IApplicationContext</literal> and are accessible through
|
||||
the Spring.NET <literal>IMessageSource</literal> interface.</para>
|
||||
<literal>IApplicationContext</literal> and are accessible through the
|
||||
Spring.NET <literal>IMessageSource</literal> interface.</para>
|
||||
|
||||
<para>The Spring.Web <literal>Page</literal> and
|
||||
<literal>UserControl</literal> classes have a reference to their owning
|
||||
@@ -1857,11 +1965,11 @@ protected override void InitializeDataBindings()
|
||||
|
||||
<para>A localizer is simply an object that implements the
|
||||
<literal>Spring.Globalization.ILocalizer</literal> interface.
|
||||
<literal>Spring.Globalization.AbstractLocalizer</literal> is
|
||||
provided as a convenient base class for localization: this class has one
|
||||
abstract method, <literal>LoadResources</literal>. This method must load
|
||||
and return a list of all the resources that must be automatically
|
||||
applied from the resource store.</para>
|
||||
<literal>Spring.Globalization.AbstractLocalizer</literal> is provided as
|
||||
a convenient base class for localization: this class has one abstract
|
||||
method, <literal>LoadResources</literal>. This method must load and
|
||||
return a list of all the resources that must be automatically applied
|
||||
from the resource store.</para>
|
||||
|
||||
<para>Spring.NET ships with one concrete implementation of a localizer,
|
||||
<literal>Spring.Globalization.Localizers.ResourceSetLocalizer</literal>,
|
||||
@@ -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 <literal>ILocalizer</literal> implementation that
|
||||
will load a list of resources to apply from a database.</para>
|
||||
write their own <literal>ILocalizer</literal> implementation that will
|
||||
load a list of resources to apply from a database.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>One last thing to note is that Spring.NET
|
||||
<literal>UserControl</literal> 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
|
||||
<literal>UserControl</literal> 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.</para>
|
||||
</sect2>
|
||||
|
||||
@@ -2011,17 +2119,16 @@ protected override void InitializeDataBindings()
|
||||
<para>In addition to global and local resource management, Spring.Web
|
||||
also adds support for user culture management by exposing the current
|
||||
<literal>CultureInfo</literal> through the
|
||||
<literal>UserCulture</literal> property on the
|
||||
<literal>Page</literal> and <literal>UserControl</literal>
|
||||
classes.</para>
|
||||
<literal>UserCulture</literal> property on the <literal>Page</literal>
|
||||
and <literal>UserControl</literal> classes.</para>
|
||||
|
||||
<para>The <literal>UserCulture</literal> property will simply delegate
|
||||
culture resolution to an implementation of
|
||||
<literal>Spring.Globalization.ICultureResolver</literal> interface.
|
||||
One can specify exactly which culture resolver to use by configuring the
|
||||
<literal>Spring.Globalization.ICultureResolver</literal> interface. One
|
||||
can specify exactly which culture resolver to use by configuring the
|
||||
<literal>CultureResolver</literal> property of the
|
||||
<literal>Page</literal> class in the relevant object definition as
|
||||
shown below.</para>
|
||||
<literal>Page</literal> class in the relevant object definition as shown
|
||||
below.</para>
|
||||
|
||||
<programlisting language="myxml"><object name="BasePage" abstract="true">
|
||||
<property name="CultureResolver">
|
||||
@@ -2030,43 +2137,42 @@ protected override void InitializeDataBindings()
|
||||
</object></programlisting>
|
||||
|
||||
<para>Several useful implementations of
|
||||
<literal>ICultureResolver</literal> 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
|
||||
<literal>ICultureResolver</literal> 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
|
||||
<literal>ICultureResolver</literal> interface.</para>
|
||||
each available implementation of the <literal>ICultureResolver</literal>
|
||||
interface.</para>
|
||||
|
||||
<sect3>
|
||||
<title>DefaultWebCultureResolver</title>
|
||||
|
||||
<para>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 <literal>DefaultWebCultureResolver</literal>
|
||||
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 <literal>DefaultWebCultureResolver</literal> 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
|
||||
<literal>DefaultCulture</literal> property on the resolver.</para>
|
||||
|
||||
<para>The <literal>DefaultWebCultureResolver</literal> will first
|
||||
look at the <literal>DefaultCulture</literal> property and return its
|
||||
value if said property value is not null. If it is null, the
|
||||
<literal>DefaultWebCultureResolver</literal> will fall back to
|
||||
request header inspection, and finally, if no
|
||||
<literal>'Accept-Lang'</literal> request headers are present it will
|
||||
return the UI culture of the currently executing thread.</para>
|
||||
<para>The <literal>DefaultWebCultureResolver</literal> will first look
|
||||
at the <literal>DefaultCulture</literal> property and return its value
|
||||
if said property value is not null. If it is null, the
|
||||
<literal>DefaultWebCultureResolver</literal> will fall back to request
|
||||
header inspection, and finally, if no <literal>'Accept-Lang'</literal>
|
||||
request headers are present it will return the UI culture of the
|
||||
currently executing thread.</para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>RequestCultureResolver</title>
|
||||
|
||||
<para>This resolver works in a similar way to the
|
||||
<literal>DefaultWebCultureResolver</literal> with the exception
|
||||
that it always checks request headers <emphasis>first</emphasis>, and
|
||||
only then falls back to the value of the
|
||||
<literal>DefaultCulture</literal> property or the culture code of the
|
||||
current thread.</para>
|
||||
<literal>DefaultWebCultureResolver</literal> with the exception that
|
||||
it always checks request headers <emphasis>first</emphasis>, and only
|
||||
then falls back to the value of the <literal>DefaultCulture</literal>
|
||||
property or the culture code of the current thread.</para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
@@ -2086,16 +2192,16 @@ protected override void InitializeDataBindings()
|
||||
of the <literal>DefaultWebCultureResolver</literal>.</para>
|
||||
|
||||
<warning>
|
||||
<para><literal>CookieCultureResolver</literal> will not work if
|
||||
your application uses <literal>localhost</literal> as the server
|
||||
URL, which is a typical setting in a development environment.</para>
|
||||
<para><literal>CookieCultureResolver</literal> will not work if your
|
||||
application uses <literal>localhost</literal> as the server URL,
|
||||
which is a typical setting in a development environment.</para>
|
||||
|
||||
<para>In order to work around this limitation you should use
|
||||
<literal>SessionCultureResolver</literal> during development and
|
||||
switch to <literal>CookieCultureResolver</literal> 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.</para>
|
||||
switch to <literal>CookieCultureResolver</literal> 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.</para>
|
||||
</warning>
|
||||
</sect3>
|
||||
</sect2>
|
||||
@@ -2106,14 +2212,14 @@ protected override void InitializeDataBindings()
|
||||
<para>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 <literal>SessionCultureResolver</literal> or
|
||||
<literal>CookieCultureResolver</literal>. One could also write a
|
||||
custom <literal>ICultureResolver</literal> that will persist culture
|
||||
<literal>CookieCultureResolver</literal>. One could also write a custom
|
||||
<literal>ICultureResolver</literal> that will persist culture
|
||||
information in a database, as part of a user's profile.</para>
|
||||
|
||||
<para>Once that requirement is satisfied, all that one need do is to set
|
||||
the <literal>UserCulture</literal> property to a new
|
||||
<literal>CultureInfo</literal> object before the page is rendered.
|
||||
In the following <literal>.aspx</literal> example, there are two link
|
||||
<literal>CultureInfo</literal> object before the page is rendered. In
|
||||
the following <literal>.aspx</literal> 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.</para>
|
||||
|
||||
<para>In Spring.Web, a logical result is encapsulated and defined by the
|
||||
<literal>Result</literal> class; because of this one can configure
|
||||
results just like any other object:</para>
|
||||
<literal>Result</literal> class; because of this one can configure results
|
||||
just like any other object:</para>
|
||||
|
||||
<programlisting language="myxml">
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
@@ -2242,10 +2348,10 @@ private void SetLanguage(object sender, CommandEventArgs e)
|
||||
|
||||
<para>The above example shows independent result object definitions, which
|
||||
are useful for global results such as a home- and login- page.
|
||||
<literal>Result</literal> 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:</para>
|
||||
<literal>Result</literal> 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:</para>
|
||||
|
||||
<programlisting language="myxml">
|
||||
<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.</para>
|
||||
|
||||
<sect2>
|
||||
<sect2 xml:id="web-validation-controls">
|
||||
<title>Validation Controls</title>
|
||||
|
||||
<para>The location in the web page where validation errors are to be
|
||||
@@ -2464,8 +2570,8 @@ protected override void OnInit(EventArgs e)
|
||||
<para>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 <literal>CheckBoxList</literal> and
|
||||
<literal>RadioButtonGroup</literal> controls. Databinding itself can
|
||||
be done using the <link
|
||||
<literal>RadioButtonGroup</literal> controls. Databinding itself can be
|
||||
done using the <link
|
||||
linkend="web-databindingpanel">DataBindingPanel</link> instead of the
|
||||
using the BindingManager API within the code behind page.</para>
|
||||
</sect2>
|
||||
@@ -2488,4 +2594,4 @@ protected override void OnInit(EventArgs e)
|
||||
injection</link> for more information.</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
||||
@@ -16,10 +16,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<chapter xml:id="webservices" xmlns="http://docbook.org/ns/docbook" version="5">
|
||||
<chapter version="5" xml:id="webservices"
|
||||
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>Web Services</title>
|
||||
|
||||
<sect1>
|
||||
<sect1 xml:id="web-services-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>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 '<link
|
||||
linkend="websvc-example">Web Services example</link>'.</para>
|
||||
|
||||
<sect2>
|
||||
<sect2 xml:id="web-services-noasmx">
|
||||
<title>Removing the need for .asmx files</title>
|
||||
|
||||
<para>Unlike web pages, which use <literal>.aspx</literal> files to
|
||||
@@ -107,8 +113,8 @@ namespace MyComany.MyApp.Services
|
||||
is:</para>
|
||||
|
||||
<para><emphasis> 1. Register the
|
||||
<literal>Spring.Web.Services.WebServiceFactoryHandler</literal> as
|
||||
the HTTP handler for <literal>*.asmx</literal> requests within one's
|
||||
<literal>Spring.Web.Services.WebServiceFactoryHandler</literal> as the
|
||||
HTTP handler for <literal>*.asmx</literal> requests within one's
|
||||
<literal>web.config</literal> file. </emphasis></para>
|
||||
|
||||
<programlisting language="myxml">
|
||||
@@ -156,7 +162,7 @@ namespace MyComany.MyApp.Services
|
||||
<programlisting>http://localhost/MyWebApp/HelloWorld.asmx</programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<sect2 xml:id="web-services-di">
|
||||
<title>Injecting dependencies into web services</title>
|
||||
|
||||
<para>For arguments sake, let's say that we want to change the
|
||||
@@ -228,8 +234,8 @@ namespace MyApp.Services
|
||||
</object>
|
||||
</programlisting>
|
||||
|
||||
<para>The <literal>WebServiceExporter</literal> copies the existing
|
||||
web service and method attribute values to the proxy implementation (if
|
||||
<para>The <literal>WebServiceExporter</literal> 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
|
||||
<literal>WebServiceExporter</literal>.</para>
|
||||
@@ -248,7 +254,7 @@ namespace MyApp.Services
|
||||
</tip>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<sect2 xml:id="web-services-exporter">
|
||||
<title>Exposing PONOs as Web Services</title>
|
||||
|
||||
<para>Now that we are generating a server-side proxy for the service,
|
||||
@@ -260,12 +266,12 @@ namespace MyApp.Services
|
||||
target service's methods.</para>
|
||||
|
||||
<para>This means that we can safely remove the
|
||||
<literal>WebService</literal> and <literal>WebMethod</literal>
|
||||
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
|
||||
<literal>WebMethod</literal> attributes to all methods of the
|
||||
exported interfaces.</para>
|
||||
<literal>WebService</literal> and <literal>WebMethod</literal> 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
|
||||
<literal>WebMethod</literal> attributes to all methods of the exported
|
||||
interfaces.</para>
|
||||
|
||||
<para>However, that is still not the ideal solution. You would lose
|
||||
information that the optional <literal>WebService</literal> and
|
||||
@@ -424,11 +430,10 @@ namespace MyApp.Services
|
||||
<para>Spring.NET provides a simple <literal>IFactoryObject</literal>
|
||||
implementation that will generate a <emphasis>"proxy for
|
||||
proxy"</emphasis> (however obtuse that may sound). Basically, the
|
||||
<literal>Spring.Web.Services.WebServiceProxyFactory</literal> 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).</para>
|
||||
<literal>Spring.Web.Services.WebServiceProxyFactory</literal> 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).</para>
|
||||
|
||||
<para>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
|
||||
|
||||
<para>What is important to notice is that the underlying implementation
|
||||
class for the web service does not have to implement the same
|
||||
<literal>IHelloWorld</literal> 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.</para>
|
||||
<literal>IHelloWorld</literal> 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.</para>
|
||||
|
||||
<para>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
|
||||
<literal>WebServiceExporter</literal>, which requires an interface
|
||||
in order to work.</para>
|
||||
exporting it using Spring.NET's <literal>WebServiceExporter</literal>,
|
||||
which requires an interface in order to work.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Generating proxies dynamically</title>
|
||||
|
||||
<para>The <literal>WebServiceProxyFactory</literal> can also
|
||||
dynamically generate a web-service proxy. The XML object definition for
|
||||
this factory object is shown below</para>
|
||||
<para>The <literal>WebServiceProxyFactory</literal> can also dynamically
|
||||
generate a web-service proxy. The XML object definition for this factory
|
||||
object is shown below</para>
|
||||
|
||||
<programlisting language="myxml">
|
||||
<object id="calculatorService" type="Spring.Web.Services.WebServiceProxyFactory, Spring.Services">
|
||||
@@ -507,8 +511,8 @@ namespace MyCompany.Services
|
||||
<sect2>
|
||||
<title>Configuring the proxy instance</title>
|
||||
|
||||
<para>The <literal>WebServiceProxyFactory</literal> also implements
|
||||
the interface,
|
||||
<para>The <literal>WebServiceProxyFactory</literal> also implements the
|
||||
interface,
|
||||
<literal>Spring.Objects.Factory.IConfigurableFactoryObject</literal>,
|
||||
allowing to specify configuration for the product that the
|
||||
<literal>WebServiceProxyFactory</literal> creates. This is done by
|
||||
@@ -550,4 +554,4 @@ namespace MyCompany.Services
|
||||
on our wiki.</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
||||
@@ -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/
|
||||
|
||||
|
||||
@@ -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("")]
|
||||
|
||||
@@ -394,6 +394,7 @@
|
||||
<Compile Include="Aspects\Cache\InvalidateCacheAdvisor.cs" />
|
||||
<Compile Include="Aspects\Cache\InvalidateCacheAdvice.cs" />
|
||||
<Compile Include="Aspects\Exceptions\ExceptionHandlerAdvice.cs" />
|
||||
<Compile Include="Aspects\Exceptions\ExecuteSpelExceptionHandler.cs" />
|
||||
<Compile Include="Aspects\Exceptions\LogExceptionHandler.cs" />
|
||||
<Compile Include="Aspects\Exceptions\ReturnValueExceptionHandler.cs" />
|
||||
<Compile Include="Aspects\Exceptions\SwallowExceptionHandler.cs" />
|
||||
|
||||
@@ -976,6 +976,7 @@
|
||||
<Compile Include="Util\AssertUtils.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Util\AttributeUtils.cs" />
|
||||
<Compile Include="Util\CollectionUtils.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
||||
@@ -590,6 +590,16 @@ namespace Spring.Messaging.Nms.Connections
|
||||
target.Rollback();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the request timeout.
|
||||
/// </summary>
|
||||
/// <value>The request timeout.</value>
|
||||
public TimeSpan RequestTimeout
|
||||
{
|
||||
get { return target.RequestTimeout; }
|
||||
set { target.RequestTimeout = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="CachedSession"/> is transacted.
|
||||
/// </summary>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -30,13 +30,27 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
/// <author>Mark Pollack</author>
|
||||
public interface ITypeMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the field in the message that has type information..
|
||||
/// </summary>
|
||||
/// <value>The name of the type id field.</value>
|
||||
string TypeIdFieldName
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert from a type to a string.
|
||||
/// </summary>
|
||||
/// <param name="typeOfObjectToConvert">The type of object to convert.</param>
|
||||
/// <returns></returns>
|
||||
string FromType(Type typeOfObjectToConvert);
|
||||
|
||||
/// <summary>
|
||||
/// Convert from a string to a type
|
||||
/// </summary>
|
||||
/// <param name="typeId">The type id.</param>
|
||||
/// <returns></returns>
|
||||
Type ToType(string typeId);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,22 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a layer of indirection when adding the 'type' of the object as a message property.
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeMapper"/> [ERROR: invalid expression DeclaringTypeKind].
|
||||
/// </summary>
|
||||
public TypeMapper()
|
||||
{
|
||||
idTypeMapping = new Hashtable();
|
||||
@@ -28,23 +51,40 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id type mapping.
|
||||
/// </summary>
|
||||
/// <value>The id type mapping.</value>
|
||||
public IDictionary IdTypeMapping
|
||||
{
|
||||
get { return idTypeMapping; }
|
||||
set { idTypeMapping = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the field in the message that has type information..
|
||||
/// </summary>
|
||||
/// <value>The name of the type id field.</value>
|
||||
public string TypeIdFieldName
|
||||
{
|
||||
get { return "__TypeId__"; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default hashtable class.
|
||||
/// </summary>
|
||||
/// <value>The default hashtable class.</value>
|
||||
public Type DefaultHashtableClass
|
||||
{
|
||||
set { defaultHashtableClass = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert from a type to a string.
|
||||
/// </summary>
|
||||
/// <param name="typeOfObjectToConvert">The type of object to convert.</param>
|
||||
/// <returns></returns>
|
||||
public string FromType(Type typeOfObjectToConvert)
|
||||
{
|
||||
|
||||
@@ -62,6 +102,11 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert from a string to a type
|
||||
/// </summary>
|
||||
/// <param name="typeId">The type id.</param>
|
||||
/// <returns></returns>
|
||||
public Type ToType(string typeId)
|
||||
{
|
||||
if (idTypeMapping.Contains(typeId))
|
||||
@@ -82,6 +127,10 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default namespace.
|
||||
/// </summary>
|
||||
/// <value>The default namespace.</value>
|
||||
public string DefaultNamespace
|
||||
{
|
||||
get
|
||||
@@ -95,6 +144,10 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default name of the assembly.
|
||||
/// </summary>
|
||||
/// <value>The default name of the assembly.</value>
|
||||
public string DefaultAssemblyName
|
||||
{
|
||||
get
|
||||
@@ -107,6 +160,9 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Afters the properties set.
|
||||
/// </summary>
|
||||
public void AfterPropertiesSet()
|
||||
{
|
||||
ValidateIdTypeMapping();
|
||||
|
||||
@@ -9,6 +9,10 @@ using Spring.Messaging.Nms.Support.Converter;
|
||||
|
||||
namespace Spring.Messaging.Nms.Support.Converter
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert an object via XML serialization for sending via an ITextMessage
|
||||
/// </summary>
|
||||
/// <author>Mark Pollack</author>
|
||||
public class XmlMessageConverter : IMessageConverter
|
||||
{
|
||||
private IMessageConverter defaultMessageConverter = new SimpleMessageConverter();
|
||||
@@ -17,11 +21,24 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
private ITypeMapper typeMapper;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the type mapper.
|
||||
/// </summary>
|
||||
/// <value>The type mapper.</value>
|
||||
public ITypeMapper TypeMapper
|
||||
{
|
||||
set { typeMapper = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a .NET object to a NMS Message using the supplied session
|
||||
/// to create the message object.
|
||||
/// </summary>
|
||||
/// <param name="objectToConvert">the object to convert</param>
|
||||
/// <param name="session">the Session to use for creating a NMS Message</param>
|
||||
/// <returns>the NMS Message</returns>
|
||||
/// <throws>NMSException if thrown by NMS API methods </throws>
|
||||
/// <throws>MessageConversionException in case of conversion failure </throws>
|
||||
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)
|
||||
/// <summary>
|
||||
/// Gets the XML string for an object
|
||||
/// </summary>
|
||||
/// <param name="objectToConvert">The object to convert.</param>
|
||||
/// <returns>XML string</returns>
|
||||
protected virtual string GetXmlString(object objectToConvert)
|
||||
{
|
||||
string xmlString;
|
||||
XmlTextWriter xmlTextWriter = null;
|
||||
@@ -72,6 +94,12 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
return xmlString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert from a NMS Message to a .NET object.
|
||||
/// </summary>
|
||||
/// <param name="messageToConvert">the message to convert</param>
|
||||
/// <returns>the converted .NET object</returns>
|
||||
/// <throws>MessageConversionException in case of conversion failure </throws>
|
||||
public object FromMessage(IMessage messageToConvert)
|
||||
{
|
||||
if (messageToConvert == null)
|
||||
@@ -108,13 +136,23 @@ namespace Spring.Messaging.Nms.Support.Converter
|
||||
}
|
||||
}
|
||||
|
||||
private Type GetTargetType(ITextMessage message)
|
||||
/// <summary>
|
||||
/// Gets the type of the target given the message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <returns>Type of the target</returns>
|
||||
protected virtual Type GetTargetType(ITextMessage message)
|
||||
{
|
||||
return typeMapper.ToType(message.Properties.GetString(typeMapper.TypeIdFieldName));
|
||||
}
|
||||
|
||||
|
||||
private String UTF8ByteArrayToString(Byte[] characters)
|
||||
/// <summary>
|
||||
/// Converts a byte array to a UTF8 string.
|
||||
/// </summary>
|
||||
/// <param name="characters">The characters.</param>
|
||||
/// <returns>UTF8 string</returns>
|
||||
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)
|
||||
/// <summary>
|
||||
/// Converts a UTF8 string to a byte array
|
||||
/// </summary>
|
||||
/// <param name="xmlString">The p XML string.</param>
|
||||
/// <returns></returns>
|
||||
protected virtual Byte[] StringToUTF8ByteArray(String xmlString)
|
||||
{
|
||||
UTF8Encoding encoding = new UTF8Encoding();
|
||||
|
||||
Byte[] byteArray = encoding.GetBytes(pXmlString);
|
||||
Byte[] byteArray = encoding.GetBytes(xmlString);
|
||||
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
@@ -83,8 +83,11 @@
|
||||
<Compile Include="Messaging\Nms\Listener\RecoveryTimeExceededException.cs" />
|
||||
<Compile Include="Messaging\Nms\Listener\SimpleMessageListenerContainer.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Converter\IMessageConverter.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Converter\ITypeMapper.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Converter\MessageConversionException.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Converter\SimpleMessageConverter.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Converter\TypeMapper.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Converter\XmlMessageConverter.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Destinations\DynamicDestinationResolver.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Destinations\IDestinationResolver.cs" />
|
||||
<Compile Include="Messaging\Nms\Support\Destinations\NmsDestinationAccessor.cs" />
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
<Compile Include="Messaging\Listener\TransactionAction.cs" />
|
||||
<Compile Include="Messaging\Listener\IExceptionHandler.cs" />
|
||||
<Compile Include="Messaging\Listener\IMessageListener.cs" />
|
||||
<Compile Include="Messaging\Listener\SimpleMessageListenerContainer.cs" />
|
||||
<Compile Include="Messaging\MessagingException.cs" />
|
||||
<Compile Include="Messaging\Support\Converters\ActiveXMessageConverter.cs" />
|
||||
<Compile Include="Messaging\Support\Converters\BinaryMessageConverter.cs" />
|
||||
|
||||
Reference in New Issue
Block a user