diff --git a/doc/reference/docbook.build b/doc/reference/docbook.build
new file mode 100644
index 00000000..d33af336
--- /dev/null
+++ b/doc/reference/docbook.build
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/reference/images/admons/Thumbs.db b/doc/reference/images/admons/Thumbs.db
deleted file mode 100644
index 29ceb9f7..00000000
Binary files a/doc/reference/images/admons/Thumbs.db and /dev/null differ
diff --git a/doc/reference/images/admons/blank.png b/doc/reference/images/admons/blank.png
deleted file mode 100644
index 764bf4f0..00000000
Binary files a/doc/reference/images/admons/blank.png and /dev/null differ
diff --git a/doc/reference/images/admons/caution.gif b/doc/reference/images/admons/caution.gif
deleted file mode 100644
index d9f5e5b1..00000000
Binary files a/doc/reference/images/admons/caution.gif and /dev/null differ
diff --git a/doc/reference/images/admons/caution.png b/doc/reference/images/admons/caution.png
deleted file mode 100644
index 5b7809ca..00000000
Binary files a/doc/reference/images/admons/caution.png and /dev/null differ
diff --git a/doc/reference/images/admons/caution.tif b/doc/reference/images/admons/caution.tif
deleted file mode 100644
index 4a282948..00000000
Binary files a/doc/reference/images/admons/caution.tif and /dev/null differ
diff --git a/doc/reference/images/admons/draft.png b/doc/reference/images/admons/draft.png
deleted file mode 100644
index 0084708c..00000000
Binary files a/doc/reference/images/admons/draft.png and /dev/null differ
diff --git a/doc/reference/images/admons/home.gif b/doc/reference/images/admons/home.gif
deleted file mode 100644
index 6784f5bb..00000000
Binary files a/doc/reference/images/admons/home.gif and /dev/null differ
diff --git a/doc/reference/images/admons/home.png b/doc/reference/images/admons/home.png
deleted file mode 100644
index cbb711de..00000000
Binary files a/doc/reference/images/admons/home.png and /dev/null differ
diff --git a/doc/reference/images/admons/important.gif b/doc/reference/images/admons/important.gif
deleted file mode 100644
index 6795d9a8..00000000
Binary files a/doc/reference/images/admons/important.gif and /dev/null differ
diff --git a/doc/reference/images/admons/important.png b/doc/reference/images/admons/important.png
deleted file mode 100644
index ad57f6f7..00000000
Binary files a/doc/reference/images/admons/important.png and /dev/null differ
diff --git a/doc/reference/images/admons/important.tif b/doc/reference/images/admons/important.tif
deleted file mode 100644
index 184de637..00000000
Binary files a/doc/reference/images/admons/important.tif and /dev/null differ
diff --git a/doc/reference/images/admons/next.gif b/doc/reference/images/admons/next.gif
deleted file mode 100644
index aa1516e6..00000000
Binary files a/doc/reference/images/admons/next.gif and /dev/null differ
diff --git a/doc/reference/images/admons/next.png b/doc/reference/images/admons/next.png
deleted file mode 100644
index 45835bf8..00000000
Binary files a/doc/reference/images/admons/next.png and /dev/null differ
diff --git a/doc/reference/images/admons/note.gif b/doc/reference/images/admons/note.gif
deleted file mode 100644
index f329d359..00000000
Binary files a/doc/reference/images/admons/note.gif and /dev/null differ
diff --git a/doc/reference/images/admons/note.png b/doc/reference/images/admons/note.png
deleted file mode 100644
index ad57f6f7..00000000
Binary files a/doc/reference/images/admons/note.png and /dev/null differ
diff --git a/doc/reference/images/admons/note.tif b/doc/reference/images/admons/note.tif
deleted file mode 100644
index 08644d6b..00000000
Binary files a/doc/reference/images/admons/note.tif and /dev/null differ
diff --git a/doc/reference/images/admons/prev.gif b/doc/reference/images/admons/prev.gif
deleted file mode 100644
index 64ca8f3c..00000000
Binary files a/doc/reference/images/admons/prev.gif and /dev/null differ
diff --git a/doc/reference/images/admons/prev.png b/doc/reference/images/admons/prev.png
deleted file mode 100644
index cf24654f..00000000
Binary files a/doc/reference/images/admons/prev.png and /dev/null differ
diff --git a/doc/reference/images/admons/tip.gif b/doc/reference/images/admons/tip.gif
deleted file mode 100644
index 823f2b41..00000000
Binary files a/doc/reference/images/admons/tip.gif and /dev/null differ
diff --git a/doc/reference/images/admons/tip.png b/doc/reference/images/admons/tip.png
deleted file mode 100644
index ad57f6f7..00000000
Binary files a/doc/reference/images/admons/tip.png and /dev/null differ
diff --git a/doc/reference/images/admons/tip.tif b/doc/reference/images/admons/tip.tif
deleted file mode 100644
index 4a3d8c75..00000000
Binary files a/doc/reference/images/admons/tip.tif and /dev/null differ
diff --git a/doc/reference/images/admons/toc-blank.png b/doc/reference/images/admons/toc-blank.png
deleted file mode 100644
index 6ffad17a..00000000
Binary files a/doc/reference/images/admons/toc-blank.png and /dev/null differ
diff --git a/doc/reference/images/admons/toc-minus.png b/doc/reference/images/admons/toc-minus.png
deleted file mode 100644
index abbb020c..00000000
Binary files a/doc/reference/images/admons/toc-minus.png and /dev/null differ
diff --git a/doc/reference/images/admons/toc-plus.png b/doc/reference/images/admons/toc-plus.png
deleted file mode 100644
index 941312ce..00000000
Binary files a/doc/reference/images/admons/toc-plus.png and /dev/null differ
diff --git a/doc/reference/images/admons/up.gif b/doc/reference/images/admons/up.gif
deleted file mode 100644
index aabc2d01..00000000
Binary files a/doc/reference/images/admons/up.gif and /dev/null differ
diff --git a/doc/reference/images/admons/up.png b/doc/reference/images/admons/up.png
deleted file mode 100644
index 07634de2..00000000
Binary files a/doc/reference/images/admons/up.png and /dev/null differ
diff --git a/doc/reference/images/admons/warning.gif b/doc/reference/images/admons/warning.gif
deleted file mode 100644
index 3adf1912..00000000
Binary files a/doc/reference/images/admons/warning.gif and /dev/null differ
diff --git a/doc/reference/images/admons/warning.png b/doc/reference/images/admons/warning.png
deleted file mode 100644
index 1c33db8f..00000000
Binary files a/doc/reference/images/admons/warning.png and /dev/null differ
diff --git a/doc/reference/images/admons/warning.tif b/doc/reference/images/admons/warning.tif
deleted file mode 100644
index 7b6611ec..00000000
Binary files a/doc/reference/images/admons/warning.tif and /dev/null differ
diff --git a/doc/reference/images/callouts/1.gif b/doc/reference/images/callouts/1.gif
deleted file mode 100644
index 0d669771..00000000
Binary files a/doc/reference/images/callouts/1.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/1.png b/doc/reference/images/callouts/1.png
deleted file mode 100644
index 7d473430..00000000
Binary files a/doc/reference/images/callouts/1.png and /dev/null differ
diff --git a/doc/reference/images/callouts/10.gif b/doc/reference/images/callouts/10.gif
deleted file mode 100644
index fb50b06d..00000000
Binary files a/doc/reference/images/callouts/10.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/10.png b/doc/reference/images/callouts/10.png
deleted file mode 100644
index 997bbc82..00000000
Binary files a/doc/reference/images/callouts/10.png and /dev/null differ
diff --git a/doc/reference/images/callouts/11.gif b/doc/reference/images/callouts/11.gif
deleted file mode 100644
index 9f5dba4f..00000000
Binary files a/doc/reference/images/callouts/11.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/11.png b/doc/reference/images/callouts/11.png
deleted file mode 100644
index ce47dac3..00000000
Binary files a/doc/reference/images/callouts/11.png and /dev/null differ
diff --git a/doc/reference/images/callouts/12.gif b/doc/reference/images/callouts/12.gif
deleted file mode 100644
index a373d0b4..00000000
Binary files a/doc/reference/images/callouts/12.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/12.png b/doc/reference/images/callouts/12.png
deleted file mode 100644
index 31daf4e2..00000000
Binary files a/doc/reference/images/callouts/12.png and /dev/null differ
diff --git a/doc/reference/images/callouts/13.gif b/doc/reference/images/callouts/13.gif
deleted file mode 100644
index b00b1637..00000000
Binary files a/doc/reference/images/callouts/13.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/13.png b/doc/reference/images/callouts/13.png
deleted file mode 100644
index 14021a89..00000000
Binary files a/doc/reference/images/callouts/13.png and /dev/null differ
diff --git a/doc/reference/images/callouts/14.gif b/doc/reference/images/callouts/14.gif
deleted file mode 100644
index 6d6642ee..00000000
Binary files a/doc/reference/images/callouts/14.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/14.png b/doc/reference/images/callouts/14.png
deleted file mode 100644
index 64014b75..00000000
Binary files a/doc/reference/images/callouts/14.png and /dev/null differ
diff --git a/doc/reference/images/callouts/15.gif b/doc/reference/images/callouts/15.gif
deleted file mode 100644
index cdd7072d..00000000
Binary files a/doc/reference/images/callouts/15.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/15.png b/doc/reference/images/callouts/15.png
deleted file mode 100644
index 0d65765f..00000000
Binary files a/doc/reference/images/callouts/15.png and /dev/null differ
diff --git a/doc/reference/images/callouts/2.gif b/doc/reference/images/callouts/2.gif
deleted file mode 100644
index 100ff79f..00000000
Binary files a/doc/reference/images/callouts/2.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/2.png b/doc/reference/images/callouts/2.png
deleted file mode 100644
index 5d09341b..00000000
Binary files a/doc/reference/images/callouts/2.png and /dev/null differ
diff --git a/doc/reference/images/callouts/3.gif b/doc/reference/images/callouts/3.gif
deleted file mode 100644
index 5008ca7d..00000000
Binary files a/doc/reference/images/callouts/3.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/3.png b/doc/reference/images/callouts/3.png
deleted file mode 100644
index ef7b7004..00000000
Binary files a/doc/reference/images/callouts/3.png and /dev/null differ
diff --git a/doc/reference/images/callouts/4.gif b/doc/reference/images/callouts/4.gif
deleted file mode 100644
index 0e5617d2..00000000
Binary files a/doc/reference/images/callouts/4.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/4.png b/doc/reference/images/callouts/4.png
deleted file mode 100644
index adb8364e..00000000
Binary files a/doc/reference/images/callouts/4.png and /dev/null differ
diff --git a/doc/reference/images/callouts/5.gif b/doc/reference/images/callouts/5.gif
deleted file mode 100644
index 9bc75ada..00000000
Binary files a/doc/reference/images/callouts/5.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/5.png b/doc/reference/images/callouts/5.png
deleted file mode 100644
index 4d7eb460..00000000
Binary files a/doc/reference/images/callouts/5.png and /dev/null differ
diff --git a/doc/reference/images/callouts/6.gif b/doc/reference/images/callouts/6.gif
deleted file mode 100644
index d3964070..00000000
Binary files a/doc/reference/images/callouts/6.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/6.png b/doc/reference/images/callouts/6.png
deleted file mode 100644
index 0ba694af..00000000
Binary files a/doc/reference/images/callouts/6.png and /dev/null differ
diff --git a/doc/reference/images/callouts/7.gif b/doc/reference/images/callouts/7.gif
deleted file mode 100644
index c90b2f3d..00000000
Binary files a/doc/reference/images/callouts/7.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/7.png b/doc/reference/images/callouts/7.png
deleted file mode 100644
index 472e96f8..00000000
Binary files a/doc/reference/images/callouts/7.png and /dev/null differ
diff --git a/doc/reference/images/callouts/8.gif b/doc/reference/images/callouts/8.gif
deleted file mode 100644
index 6fe3287d..00000000
Binary files a/doc/reference/images/callouts/8.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/8.png b/doc/reference/images/callouts/8.png
deleted file mode 100644
index 5e60973c..00000000
Binary files a/doc/reference/images/callouts/8.png and /dev/null differ
diff --git a/doc/reference/images/callouts/9.gif b/doc/reference/images/callouts/9.gif
deleted file mode 100644
index bc5c8125..00000000
Binary files a/doc/reference/images/callouts/9.gif and /dev/null differ
diff --git a/doc/reference/images/callouts/9.png b/doc/reference/images/callouts/9.png
deleted file mode 100644
index a0676d26..00000000
Binary files a/doc/reference/images/callouts/9.png and /dev/null differ
diff --git a/doc/reference/images/callouts/Thumbs.db b/doc/reference/images/callouts/Thumbs.db
deleted file mode 100644
index fc135009..00000000
Binary files a/doc/reference/images/callouts/Thumbs.db and /dev/null differ
diff --git a/doc/reference/src/ado.xml b/doc/reference/src/ado.xml
index 4be10ed1..4b245fb6 100644
--- a/doc/reference/src/ado.xml
+++ b/doc/reference/src/ado.xml
@@ -1,8 +1,25 @@
-
+
+Data access using ADO.NET
-
+ IntroductionSpring provides an abstraction for data access via ADO.NET that
@@ -113,7 +130,7 @@
-
+ MotivationsThere are a variety of motivations to create a higher level ADO.NET
@@ -249,7 +266,7 @@
well as mixing orm/ado.net operations within the same transaction.
-
+ Provider AbstractionBefore you get started executing queries against the database you
@@ -260,7 +277,7 @@
ADO.NET interfaces, such as IDbCommand or IDbParameter in your code.
However, In the .NET 1.1 BCL the only means to obtain references to
instances of these interfaces is to directly instantiate the classes, i.e.
- for SqlServer this would be IDbCommand command = new SqlCommand();
+ for SqlServer this would be IDbCommand command = new SqlCommand();
One of the classic creational patterns in the GoF Design Patterns book
addresses this situation directly, the Abstract Factory pattern. This
approach was applied in the .NET BCL with the introduction of the
@@ -288,7 +305,7 @@
For more information on configuring a Spring database provider refer
to
-
+ Creating an instance of IDbProviderEach database vendor is associated with a particular
@@ -298,14 +315,14 @@
configuration for database that is not yet provided. The programmatic
way to create an IDbProvider is shown below
- IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");
+ IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");Please refer to the for information on
how to create a IDbProvider in Spring's XML configuration file.
-
+ NamespacesThe ADO.NET framework consists of a few namespaces, namely
@@ -331,25 +348,25 @@
thread safe, reusable objects.Finally the Spring.Data.Support namespace is
- where you find the IAdoExceptionTransactor
+ where you find the IAdoExceptionTransactor
translation functionality and some utility classes.
-
+ Approaches to Data AccessSpring provides two styles to interact with ADO.NET. The first is a
'template' based approach in which you create an single instance of
- AdoTemplate to be used by all your DAO
+ AdoTemplate to be used by all your DAO
implementations. Your DAO methods are frequently implemented as a single
method call on the template class as described in detail in the following
section. The other approach a more object-oriented manner that models
database operations as objects. For example, one can encapsulate the
- functionality of a database query via an AdoQuery
+ functionality of a database query via an AdoQuery
class and a create/update/delete operation as a
- AdoNonQuery class. Stored procedures are also
+ AdoNonQuery class. Stored procedures are also
modelled in this manner via the class
- StoredProcedure. To use these classes you inherit
+ StoredProcedure. To use these classes you inherit
from them and define the details of the operation in the constructor and
implement an abstract method. This reads very cleanly when looking at DAO
method implementation as you can generally see all the details of what is
@@ -366,34 +383,34 @@
benefit for a particular situation.
-
+ Introduction to AdoTemplate
- The class AdoTemplate is at the heart of
+ The class AdoTemplate is at the heart of
Spring's ADO.NET support. It is based on an Inversion of Control (i.e.
callback) design with the central method 'Execute'
- handing you a IDbCommand instance that has
+ handing you a IDbCommand instance that has
its Connection and Transaction properties set based on the transaction
context of the calling code. All resource management is handled by the
framework, you only need to focus on dealing with the
- IDbCommand object. The other methods in
+ IDbCommand object. The other methods in
this class build upon this central 'Execute' method to provide you a quick
means to execute common data access scenarios.
- There are two implementations of AdoTemplate.
+ There are two implementations of AdoTemplate.
The one that uses Generics and is in the namespace
- Spring.Data.Generic and the other non-generic
+ Spring.Data.Generic and the other non-generic
version in Spring.Data. In either case you create an
- instance of an AdoTemplate by passing it a
- IDbProvider instance as shown below
+ instance of an AdoTemplate by passing it a
+ IDbProvider instance as shown below
- AdoTemplate adoTemplate = new AdoTemplate(dbProvider);
+ AdoTemplate adoTemplate = new AdoTemplate(dbProvider);
- AdoTemplate is a thread-safe class and as
+ AdoTemplate is a thread-safe class and as
such a single instance can be used for all data access operations in you
- applications DAOs. AdoTemplate implements an
- IAdoOperations interface. Although the
- IAdoOperations interface is more commonly
+ applications DAOs. AdoTemplate implements an
+ IAdoOperations interface. Although the
+ IAdoOperations interface is more commonly
used for testing scenarios you may prefer to code against it instead of
the direct class instance.
@@ -401,33 +418,33 @@
the non-generic version via the property ClassicAdoTemplate.The following two sections show basic usage of the
- AdoTemplate 'Execute' API for .NET 1.1 and
+ AdoTemplate 'Execute' API for .NET 1.1 and
2.0.
-
+ Execute CallbackThe Execute method and its associated
callback function/inteface is the basic method upon which all the other
- methods in AdoTemplate delegate their work. If
+ methods in AdoTemplate delegate their work. If
you can not find a suitable 'one-liner' method in
- AdoTemplate for your purpose you can always fall
+ AdoTemplate for your purpose you can always fall
back to the Execute method to perform any
database operation while benefiting from ADO.NET resource management and
transaction enlistment. This is commonly the case when you are using
special provider specific features, such as XML or BLOB support.
-
+ Execute Callback in .NET 2.0In this example a simple query against the 'Northwind' database is
done to determine the number of customers who have a particular postal
code.
- public int FindCountWithPostalCode(string postalCode)
+ public int FindCountWithPostalCode(string postalCode)
{
return adoTemplate.Execute<int>(delegate(DbCommand command)
{
@@ -443,11 +460,11 @@
});
-}The DbCommand that is passed into the
+}The DbCommand that is passed into the
anonymous delegate is already has it Connection property set to the
corresponding value of the dbProvider instance used to create the
template. Furthermore, the Transaction property
- of the DbCommand is set based on the
+ of the DbCommand is set based on the
transactional calling context of the code as based on the use of
Spring's transaction management features. Also note the feature of
anonymous delegates to access the variable 'postalCode' which is defined
@@ -456,20 +473,20 @@
data access code. If you find that your callback implementation is
getting very long, it may improve code clarity to use an interface based
version of the callback function, i.e. an
- ICommandCallback shown below.
+ ICommandCallback shown below.As you can see, only the most relevant portions of the data access
task at hand need to be coded. (Note that in this simple example you
would be better off using AdoTemplate's ExecuteScalar method directly.
This method is described in the following sections). As mentioned
before, the typical usage scenario for the Execute callback would
- involve downcasting the passed in DbCommand
+ involve downcasting the passed in DbCommand
object to access specific provider API features.There is also an interface based version of the execute method.
The signatures for the delegate and interface are shown below
- public delegate T CommandDelegate<T>(DbCommand command);
+ public delegate T CommandDelegate<T>(DbCommand command);
public interface ICommandCallback
@@ -482,7 +499,7 @@ public interface ICommandCallback
on Spring.Data.Generic.AdoTemplate are shown
below
- public class AdoTemplate : AdoAccessor, IAdoOperations
+ public class AdoTemplate : AdoAccessor, IAdoOperations
{
...
@@ -502,7 +519,7 @@ public interface ICommandCallback
IDbCommand and not DbCommand as callback arguments. The following
listing shows these methods on AdoTemplate.
- public class AdoTemplate : AdoAccessor, IAdoOperations
+ public class AdoTemplate : AdoAccessor, IAdoOperations
{
...
@@ -516,7 +533,7 @@ public interface ICommandCallback
where the signatures for the delegate and interface are shown
below
- public delegate T IDbCommandDelegate<T>(IDbCommand command);
+ public delegate T IDbCommandDelegate<T>(IDbCommand command);
public interface IDbCommandCallback<T>
@@ -524,25 +541,25 @@ public interface IDbCommandCallback<T>
T DoInCommand(IDbCommand command);
}
- Internally the AdoTemplate implementation
+ Internally the AdoTemplate implementation
delegates to implementations of
- IDbCommandCallback so that the 'lowest common
+ IDbCommandCallback so that the 'lowest common
denominator' API is used to have maximum portability. If you
accidentally call Execute<T>(ICommandCallback
action)and the command does not inherit from
- DbCommand, an
- InvalidDataAccessApiUsageException will be
+ DbCommand, an
+ InvalidDataAccessApiUsageException will be
thrown.Depending on how portable you would like your code to be, you can
choose among the two callback styles. The one based on
- DbCommand has the advantage of access to the more
- user friendly DbParameter class as compared to
- IDbParameter obtained from
- IDbCommand.
+ DbCommand has the advantage of access to the more
+ user friendly DbParameter class as compared to
+ IDbParameter obtained from
+ IDbCommand.
-
+
>
Execute Callback in .NET 1.1
@@ -550,19 +567,19 @@ public interface IDbCommandCallback<T>
AdoTemplate differs from its .NET 2.0 generic counterpart in that
- it exposes the interface IDbCommand in
+ it exposes the interface IDbCommand in
its 'Execute' callback methods and delegate as compared to the abstract
- base class DbProvider. Also, since anonymous
+ base class DbProvider. Also, since anonymous
delegates are not available in .NET 1.1, the typical usage pattern
requires you to create a explicitly delegate and/or class that
- implements the ICommandCallback
+ implements the ICommandCallback
interface. Example code to query In .NET 1.1 the 'Northwind' database is
done to determine the number of customers who have a particular postal
code is shown below.
- public virtual int FindCountWithPostalCode(string postalCode)
+ public virtual int FindCountWithPostalCode(string postalCode)
{
return (int) AdoTemplate.Execute(new PostalCodeCommandCallback(postalCode));
}
@@ -573,7 +590,7 @@ public interface IDbCommandCallback<T>
- private class PostalCodeCommandCallback : ICommandCallback
+ private class PostalCodeCommandCallback : ICommandCallback
{
private string cmdText = "select count(*) from Customer where PostalCode = @PostalCode";
@@ -610,7 +627,7 @@ public interface IDbCommandCallback<T>
- public delegate object CommandDelegate(IDbCommand command);
+ public delegate object CommandDelegate(IDbCommand command);
public interface ICommandCallback
{
@@ -624,7 +641,7 @@ public interface ICommandCallback
- public class AdoTemplate : AdoAccessor, IAdoOperations
+ public class AdoTemplate : AdoAccessor, IAdoOperations
{
...
@@ -644,7 +661,7 @@ public interface ICommandCallback
-
+ Quick Guide to AdoTemplate MethodsThere are many methods in AdoTemplate so it is easy to feel a bit
@@ -690,41 +707,41 @@ public interface ICommandCallback
QueryWithResultSetExtractor - Execute
a query mapping a result set to an object with an implementation of
- the IResultSetExtractor
+ the IResultSetExtractor
interface.QueryWithResultSetExtractorDelegate -
Same as QueryWithResultSetExtractor but using a
- ResultSetExtractorDelegate to perform
+ ResultSetExtractorDelegate to perform
result set mapping.QueryWithRowCallback - Execute a
query calling an implementation of
- IRowCallback for each row in the
+ IRowCallback for each row in the
result set.QueryWithRowCallbackDelegate - Same
as QueryWithRowCallback but calling a
- RowCallbackDelegate for each
+ RowCallbackDelegate for each
row.QueryWithRowMapper - Execute a query
mapping a result set on a row by row basis with an implementation of
- the IRowMapper interface.
+ the IRowMapper interface.QueryWithRowMapperDelegate - Same as
QueryWithRowMapper but using a
- RowMapperDelegate to perform result
+ RowMapperDelegate to perform result
set row to object mapping.
@@ -735,7 +752,7 @@ public interface ICommandCallback
QueryForObject - Execute a query
mapping the result set to an object using a
- IRowMapper. Exception is thrown if
+ IRowMapper. Exception is thrown if
the query does not return exactly one object.
@@ -748,7 +765,7 @@ public interface ICommandCallback
QueryWithCommandCreator - Execute a
query with a callback to
- IDbCommandCreator to create a
+ IDbCommandCreator to create a
IDbCommand object and using either a IRowMapper or
IResultSetExtractor to map the result set to an object. One
variation lets multiple result set 'processors' be specified to act
@@ -898,7 +915,7 @@ public interface ICommandCallback
type-safety.
-
+ Quick Guide to AdoTemplate PropertiesAdoTemplate has the following properties that you can
@@ -907,39 +924,39 @@ public interface ICommandCallback
LazyInit - Indicates if the
- IAdoExceptionTranslator should be created on
+ IAdoExceptionTranslator should be created on
first encounter of an exception from the data provider or when
- AdoTemplate is created. Default is true, i.e.
+ AdoTemplate is created. Default is true, i.e.
to lazily instantiate.ExceptionTranslator - Gets or sets the
- implementation of IAdoExceptionTranslator to
+ implementation of IAdoExceptionTranslator to
use. If no custom translator is provided, a default
- ErrorCodeExceptionTranslator is used.
+ ErrorCodeExceptionTranslator is used.DbProvider - Gets or sets the
- IDbProvider instance to use.
+ IDbProvider instance to use.
DataReaderWrapperType - Gets or set the
System.Type to use to create an instance of
- IDataReaderWrapper for the purpose of
+ IDataReaderWrapper for the purpose of
providing extended mapping functionality. Spring provides an
implementation to use as the basis for a mapping strategy that will
- map DBNull values to default values based on
- the standard IDataReader interface. See the
+ map DBNull values to default values based on
+ the standard IDataReader interface. See the
section custom IDataReader
implementations for more information.CommandTimeout - Gets or sets the command
- timeout for IDbCommands that this AdoTemplate
+ timeout for IDbCommands that this AdoTemplate
executes. Default is 0, indicating to use the database provider's
default.
@@ -947,11 +964,11 @@ public interface ICommandCallback
-
+ Transaction ManagementThe AdoTemplate is used in conjunction with an implementation of a
- IPlatformTransactionManager, which is Spring's
+ IPlatformTransactionManager, which is Spring's
portable transaction management API. This section gives a brief overview
of the transaction managers you can use with AdoTemplate and the details
of how you can retrieve the connection/transaction ADO.NET objects that
@@ -962,10 +979,10 @@ public interface ICommandCallback
To use local transactions, those with only one transactional
resource (i.e. the database) you will typically use
- AdoPlatformTransactionManager. If you need to mix
+ AdoPlatformTransactionManager. If you need to mix
Hibernate and ADO.NET data access operations within the same local
transaction you should use
- HibernatePlatformTransaction manager which is
+ HibernatePlatformTransaction manager which is
described more in the section on ORM
transaction management.
@@ -977,7 +994,7 @@ public interface ICommandCallback
some integration with other data access APIs. The can be done using the
utility class ConnectionUtils as shown below.
- IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");
+ IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");
ConnectionTxPair connectionTxPairToUse = ConnectionUtils.GetConnectionTxPair(dbProvider);
@@ -990,13 +1007,13 @@ command.Transaction = connectionTxPairToUse.Transaction;
conjunction with Spring's transaction management features.
If you are using
- ServiceDomainPlatformTransactionManager or
- TxScopePlatformTransactionManager then you can
+ ServiceDomainPlatformTransactionManager or
+ TxScopePlatformTransactionManager then you can
retrieve the currently executing transaction object via the standard .NET
APIs.
-
+ Exception TranslationAdoTemplate's methods throw exceptions within a Data Access Object
@@ -1009,7 +1026,7 @@ command.Transaction = connectionTxPairToUse.Transaction;
diagnose the issue.
-
+ Parameter ManagementA fair amount of the code in ADO.NET applications is related to the
@@ -1020,19 +1037,19 @@ command.Transaction = connectionTxPairToUse.Transaction;
collection. Spring provides two ways to make this mundane task easier and
more portable across providers.
-
+ IDbParametersBuilderInstead of creating a parameter on one line of code, then setting
its type on another and size on another, a builder and parameter
- interface, IDbParametersBuilder and
- IDbParameter respectfully, are provided
+ interface, IDbParametersBuilder and
+ IDbParameter respectfully, are provided
so that this declaration process can be condensed. The IDbParameter
support chaining calls to its methods, in effect a simple
language-constrained domain specific language, to be fancy about it.
Here is an example of it in use.
- IDbParametersBuilder builder = CreateDbParametersBuilder();
+ IDbParametersBuilder builder = CreateDbParametersBuilder();
builder.Create().Name("Country").Type(DbType.String).Size(15).Value(country);
builder.Create().Name("City").Type(DbType.String).Size(15).Value(city);
@@ -1042,8 +1059,8 @@ builder.Create().Name("City").Type(DbType.String).Size(15).Value(city);
IDbParameters parameters = builder.GetParameters();
- Please note that IDbParameters and
- IDbParameter are not part of the BCL, but part of
+ Please note that IDbParameters and
+ IDbParameter are not part of the BCL, but part of
the Spring.Data.Common namespace. The IDbParameters collection is a
frequent argument to the overloaded methods of AdoTemplate.
@@ -1063,7 +1080,7 @@ IDbParameters parameters = builder.GetParameters();
database providers just by a change in configuration files.
-
+ IDbParametersThis class is similar to the parameter collection class you find
@@ -1109,7 +1126,7 @@ IDbParameters parameters = builder.GetParameters();
Here a simple usage example
- // inside method has has local variable country and city...
+ // inside method has has local variable country and city...
IDbParameters parameters = CreateDbParameters();
parameters.AddWithValue("Country", country).DbType = DbType.String;
@@ -1125,12 +1142,12 @@ parameters.Add("City", DbType.String).Value = city;
-
+ Custom IDataReader implementations
- The passed in implementation of IDataReader
+ The passed in implementation of IDataReader
can be customized. This lets you add a strategy for handling null values
- to the standard methods in the IDataReader
+ to the standard methods in the IDataReader
interface or to provide sub-interface of IDataReader that contains
extended functionality, for example support for default values. In
callback code, i.e. IRowMapper and associated delegate, you would downcast
@@ -1138,21 +1155,21 @@ parameters.Add("City", DbType.String).Value = city;
Spring provides a class to map DBNull values to
default values. When reading from a IDataReader there is often the need to
- map DBNull values to some default values, i.e. null
+ map DBNull values to some default values, i.e. null
or say a magic number such as -1. This is usually done via a ternary
operator which decreases readability and also increases the likelihood of
mistakes. Spring provides an
- IDataReaderWrapper interface (which
- inherits from the standard IDataReader) so
+ IDataReaderWrapper interface (which
+ inherits from the standard IDataReader) so
that you can provide your own implementation of a IDataReader that will
perform DBNull mapping for you in a consistent and non invasive manner to
your result set reading code. A default implementation,
- NullMappingDataReader is provided which you can
+ NullMappingDataReader is provided which you can
subclass to customize or simply implement the
- IDataReaderWrapper interface directly. This
+ IDataReaderWrapper interface directly. This
interface is shown below
- public interface IDataReaderWrapper : IDataReader
+ public interface IDataReaderWrapper : IDataReader
{
IDataReader WrappedReader
{
@@ -1163,28 +1180,28 @@ parameters.Add("City", DbType.String).Value = city;
}All of AdoTemplates callback interfaces/delegates that have an
- IDataReader as an argument are wrapped with
- a IDataReaderWrapper if the AdoTemplate has
+ IDataReader as an argument are wrapped with
+ a IDataReaderWrapper if the AdoTemplate has
been configured with one via its
DataReaderWrapperType property. Your
implementation should support a zero-arg constructor.Frequently you will use a common mapper for DBNull across your
- application so only one instance of AdoTemplate and
- IDataReaderWrapper in required. If you need to use
+ application so only one instance of AdoTemplate and
+ IDataReaderWrapper in required. If you need to use
multiple null mapping strategies you will need to create multiple
- instances of AdoTemplate and configure them
+ instances of AdoTemplate and configure them
appropriately in the DAO objects.
-
+ Basic data access operationsThe 'ExecuteNonQuery' and 'ExecuteScalar' methods of
- AdoTemplate have the same functionality as the same
+ AdoTemplate have the same functionality as the same
named methods on the DbCommand object
-
+ ExecuteNonQueryExecuteNonQuery is used to perform create, update, and delete
@@ -1193,7 +1210,7 @@ parameters.Add("City", DbType.String).Value = city;
An example of using this method is shown below
- public void CreateCredit(float creditAmount)
+ public void CreateCredit(float creditAmount)
{
AdoTemplate.ExecuteNonQuery(CommandType.Text,
String.Format("insert into Credits(creditAmount) VALUES ({0})",
@@ -1201,17 +1218,17 @@ parameters.Add("City", DbType.String).Value = city;
}
-
+ ExecuteScalarAn example of using this method is shown below
- int iCount = (int)adoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects");
+ int iCount = (int)adoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects");
-
+ Queries and Lightweight Object MappingA common ADO.NET development task is reading in a result set and
@@ -1258,7 +1275,7 @@ parameters.Add("City", DbType.String).Value = city;
The following sections describe in more detail how to use Spring's
lightweight object mapping framework.
-
+ ResultSetExtractorThe ResultSetExtractor gives you control to iterate over the
@@ -1272,7 +1289,7 @@ parameters.Add("City", DbType.String).Value = city;
shown below for the generic version in the Spring.Data.Generic
namespace
- public interface IResultSetExtractor<T>
+ public interface IResultSetExtractor<T>
{
T ExtractData(IDataReader reader);
}
@@ -1282,7 +1299,7 @@ public delegate T ResultSetExtractorDelegate<T>(IDataReader reader);
The definition for the non-generic version is shown below
- public interface IResultSetExtractor
+ public interface IResultSetExtractor
{
object ExtractData(IDataReader reader);
}
@@ -1295,7 +1312,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
- public virtual IList<string> GetCustomerNameByCountryAndCityWithParamsBuilder(string country, string city)
+ public virtual IList<string> GetCustomerNameByCountryAndCityWithParamsBuilder(string country, string city)
{
IDbParametersBuilder builder = CreateDbParametersBuilder();
@@ -1311,7 +1328,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);The implementation of the ResultSetExtractor is shown
below.
- internal class CustomerNameResultSetExtractor<T> : IResultSetExtractor<T> where T : IList<string>, new()
+ internal class CustomerNameResultSetExtractor<T> : IResultSetExtractor<T> where T : IList<string>, new()
{
public T ExtractData(IDataReader reader)
@@ -1336,14 +1353,14 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
-
+ RowCallbackThe RowCallback is usually a stateful object itself or populates
another stateful object that is accessible to the calling code. Here is
a sample take from the Data QuickStart
- public class RowCallbackDao : AdoDaoSupport
+ public class RowCallbackDao : AdoDaoSupport
{
private string cmdText = "select ContactName, PostalCode from Customers";
@@ -1363,7 +1380,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
- internal class PostalCodeRowCallback : IRowCallback
+ internal class PostalCodeRowCallback : IRowCallback
{
private IDictionary<string, IList<string>> postalCodeMultimap =
new Dictionary<string, IList<string>>();
@@ -1391,7 +1408,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
-
+ RowMapperThe RowMapper lets you focus on just the logic to map a row of
@@ -1400,7 +1417,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
- public class RowMapperDao : AdoDaoSupport
+ public class RowMapperDao : AdoDaoSupport
{
private string cmdText = "select Address, City, CompanyName, ContactName, " +
"ContactTitle, Country, Fax, CustomerID, Phone, PostalCode, " +
@@ -1416,7 +1433,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);where the implementation of the RowMapper is
- public class CustomerRowMapper<T> : IRowMapper<T> where T : Customer, new()
+ public class CustomerRowMapper<T> : IRowMapper<T> where T : Customer, new()
{
public T MapRow(IDataReader dataReader, int rowNum)
{
@@ -1440,7 +1457,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
- public virtual IList<Customer> GetCustomersWithDelegate()
+ public virtual IList<Customer> GetCustomersWithDelegate()
{
return AdoTemplate.QueryWithRowMapperDelegate<Customer>(CommandType.Text, cmdText,
delegate(IDataReader dataReader, int rowNum)
@@ -1462,7 +1479,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
-
+ Query for a single objectThe QueryForObject method is used when you expect there to be
@@ -1470,7 +1487,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
- public class QueryForObjectDao : AdoDaoSupport
+ public class QueryForObjectDao : AdoDaoSupport
{
private string cmdText = "select Address, City, CompanyName, ContactName, " +
"ContactTitle, Country, Fax, CustomerID, Phone, PostalCode, " +
@@ -1485,12 +1502,12 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
-
+ Query using a CommandCreatorThere is a family of overloaded methods that allows you to
encapsulate and reuse a particular configuration of a
- IDbCommand object. These methods also allow for
+ IDbCommand object. These methods also allow for
access to returned out parameters as well as a method that allows
processing of multiple result sets. These methods are used internally to
support the classes in the Spring.Data.Objects
@@ -1539,7 +1556,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);The IDbCommandCreator callback interface is shown below
- public interface IDbCommandCreator
+ public interface IDbCommandCreator
{
IDbCommand CreateDbCommand();
}
@@ -1548,9 +1565,9 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
To process multiple result sets specify a list of named result set
- processors,( i.e. IResultSetExtractor,
- IRowCallback, or IRowMapper).
- This method is shown below
+ processors,( i.e. IResultSetExtractor,
+ IRowCallback, or IRowMapper).
+ This method is shown below
@@ -1560,11 +1577,11 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
The list must contain objects of the type
- Spring.Data.Support.NamedResultSetProcessor. This
+ Spring.Data.Support.NamedResultSetProcessor. This
is the class responsible for associating a name with a result set
processor. The constructors are listed below.
- public class NamedResultSetProcessor {
+ public class NamedResultSetProcessor {
public NamedResultSetProcessor(string name, IRowMapper rowMapper) { ... }
@@ -1651,7 +1668,7 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
-
+ DataTable and DataSetAdoTemplate contains several 'families' of methods to help remove
@@ -1677,22 +1694,22 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);
- Where IDataAdapterCallback is defined
+ Where IDataAdapterCallback is defined
as
- public interface IDataAdapterCallback
+ public interface IDataAdapterCallback
{
object DoInDataAdapter(IDbDataAdapter dataAdapter);
}
- The passed in IDbDataAdapter will have its
+ The passed in IDbDataAdapter will have its
SelectCommand property created and set with its
Connection and Transaction
values based on the calling transaction context. The return value is the
result of processing or null.There are type-safe versions of this method in
- Spring.Data.Generic.AdoTemplate
+ Spring.Data.Generic.AdoTemplate
@@ -1711,20 +1728,20 @@ public delegate object ResultSetExtractorDelegate(IDataReader reader);Where IDataAdapterCallback<T> and DataAdapterDelegate<T>
are defined as
- public interface IDataAdapterCallback<T>
+ public interface IDataAdapterCallback<T>
{
T DoInDataAdapter(IDbDataAdapter dataAdapter);
}
public delegate T DataAdapterDelegate<T>(IDbDataAdapter dataAdapter);
-
+ DataTablesDataTable operations are available on the class
- Spring.Data.Core.AdoTemplate. If you are using
+ Spring.Data.Core.AdoTemplate. If you are using
the generic version,
- Spring.Data.Generic.AdoTemplate, you can access
+ Spring.Data.Generic.AdoTemplate, you can access
these methods through the property
ClassicAdoTemplate, which returns the non-generic
version of AdoTemplate. DataTable operations available fall into the
@@ -1764,13 +1781,13 @@ public delegate T DataAdapterDelegate<T>(IDbDataAdapter dataAdapter);
-
+ DataSetsDataSet operations are available on the class
- Spring.Data.Core.AdoTemplate. If you are using
+ Spring.Data.Core.AdoTemplate. If you are using
the generic version,
- Spring.Data.Generic.AdoTemplate, you can access
+ Spring.Data.Generic.AdoTemplate, you can access
these methods through the property
ClassicAdoTemplate, which returns the non-generic
version of AdoTemplate. DataSet operations available fall into the
@@ -1813,7 +1830,7 @@ public delegate T DataAdapterDelegate<T>(IDbDataAdapter dataAdapter);
- public class DataSetDemo : AdoDaoSupport
+ public class DataSetDemo : AdoDaoSupport
{
private string selectAll = @"select Address, City, CompanyName, ContactName, " +
"ContactTitle, Country, Fax, CustomerID, Phone, PostalCode, " +
@@ -1857,7 +1874,7 @@ public delegate T DataAdapterDelegate<T>(IDbDataAdapter dataAdapter);
- public class DataSetDemo : AdoDaoSupport
+ public class DataSetDemo : AdoDaoSupport
{
private string selectAll = @"select Address, City, CompanyName, ContactName, " +
"ContactTitle, Country, Fax, CustomerID, Phone, PostalCode, " +
@@ -1925,7 +1942,7 @@ public delegate T DataAdapterDelegate<T>(IDbDataAdapter dataAdapter);
-
+ TableAdapters and participation in transactional contextTyped DataSets need to have commands in their internal DataAdapters
@@ -1939,12 +1956,12 @@ public delegate T DataAdapterDelegate<T>(IDbDataAdapter dataAdapter);Spring.Data.Support.TypedDataSetUtils and is named
+ Spring.Data.Support.TypedDataSetUtils and is named
ApplyConnectionAndTx. Here is sample usage of a
DAO method that uses a VS.NET 2005 generated typed dataset for a
PrintGroupMapping table.
- public PrintGroupMappingDataSet FindAll()
+ public PrintGroupMappingDataSet FindAll()
{
PrintGroupMappingTableAdapter adapter = new PrintGroupMappingTableAdapter();
@@ -1971,7 +1988,7 @@ public delegate T DataAdapterDelegate<T>(IDbDataAdapter dataAdapter);
- public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbCommand sourceCommand)
+ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbCommand sourceCommand)
public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider dbProvider)
@@ -1987,7 +2004,7 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
techniques or via a service locator style lookup.
-
+ Database operations as ObjectsThe Spring.Data.Objects and Spring.Data.Objects.Generic
@@ -2003,9 +2020,9 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
amongst some of the Spring developers that the various RDBMS operation
classes described below (with the exception of the StoredProcedure class) can often be
- replaced with straight AdoTemplate calls...
+ replaced with straight AdoTemplate calls...
often it is simpler to use and plain easier to read a DAO method that
- simply calls a method on a AdoTemplate direct
+ simply calls a method on a AdoTemplate direct
(as opposed to encapsulating a query as a full-blown class).It must be stressed however that this is just a
@@ -2014,29 +2031,29 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
continue using these classes.
-
+ AdoQuery
- AdoQuery is a reusable, threadsafe class
+ AdoQuery is a reusable, threadsafe class
that encapsulates an SQL query. Subclasses must implement the
NewRowMapper(..) method to provide a
- IRowMapper instance that can create one
+ IRowMapper instance that can create one
object per row obtained from iterating over the
- IDataReader that is created during the
- execution of the query. The AdoQuery class is
- rarely used directly since the MappingAdoQuery
+ IDataReader that is created during the
+ execution of the query. The AdoQuery class is
+ rarely used directly since the MappingAdoQuery
subclass provides a much more convenient implementation for mapping rows
to .NET classes. Another implementations that extends
- AdoQuery is
- MappingadoQueryWithParameters (See SDK docs for
+ AdoQuery is
+ MappingadoQueryWithParameters (See SDK docs for
details).
- The AdoNonQuery class encapsulates an
+ The AdoNonQuery class encapsulates an
IDbCommand 's ExecuteNonQuery method functionality. Like the
- AdoQuery object, an
- AdoNonQuery object is reusable, and like all
- AdoOperation classes, an
- AdoNonQuery can have parameters and is defined in
+ AdoQuery object, an
+ AdoNonQuery object is reusable, and like all
+ AdoOperation classes, an
+ AdoNonQuery can have parameters and is defined in
SQL. This class provides two execute methods
@@ -2059,7 +2076,7 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
statement for a 'TestObject' (consisting only name and age columns) is
shown below
- public class CreateTestObjectNonQuery : AdoNonQuery
+ public class CreateTestObjectNonQuery : AdoNonQuery
{
private static string sql = "insert into TestObjects(Age,Name) values (@Age,@Name)";
@@ -2078,18 +2095,18 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
}
-
+ MappingAdoQuery
- MappingAdoQuery is a reusable query in
+ MappingAdoQuery is a reusable query in
which concrete subclasses must implement the abstract
MapRow(..) method to convert each row of the
- supplied IDataReader into an object. Find
+ supplied IDataReader into an object. Find
below a brief example of a custom query that maps the data from a
- relation to an instance of the Customer
+ relation to an instance of the Customer
class.
- public class TestObjectQuery : MappingAdoQuery
+ public class TestObjectQuery : MappingAdoQuery
{
private static string sql = "select TestObjectNo, Age, Name from TestObjects";
@@ -2110,15 +2127,15 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
}
-
+ AdoNonQuery
- The AdoNonQuery class encapsulates an
+ The AdoNonQuery class encapsulates an
IDbCommand 's ExecuteNonQuery method functionality. Like the
- AdoQuery object, an
- AdoNonQuery object is reusable, and like all
- AdoOperation classes, an
- AdoNonQuery can have parameters and is defined in
+ AdoQuery object, an
+ AdoNonQuery object is reusable, and like all
+ AdoOperation classes, an
+ AdoNonQuery can have parameters and is defined in
SQL. This class provides two execute methods
@@ -2137,7 +2154,7 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
to add a custom update method) it can easily be parameterized by setting
SQL and declaring parameters.
- public class CreateTestObjectNonQuery : AdoNonQuery
+ public class CreateTestObjectNonQuery : AdoNonQuery
{
private static string sql = "insert into TestObjects(Age,Name) values (@Age,@Name)";
@@ -2156,8 +2173,8 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
}
-
- Stored Procedure
+
+ Stored ProcedureThe StoredProcedure class is designed to make it as simple as
possible to call a stored procedure. It takes advantage of metadata
@@ -2206,7 +2223,7 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
Each of these methods returns an
- IDictionary that contains the output parameters
+ IDictionary that contains the output parameters
and/or any results from Spring's object mapping framework. The arguments
to these methods can be a variable length argument list, in which case
the order must match the parameter order of the stored procedure. If the
@@ -2218,18 +2235,18 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
programmatically by adding to the parameter collection exposed by the
property DeclaredParameters. For each result sets that is returned by
the stored procedures you can registering either an
- IResultSetExtractor,
- IRowCallback, or
- IRowMapper by name, which is used later to
+ IResultSetExtractor,
+ IRowCallback, or
+ IRowMapper by name, which is used later to
extract the mapped results from the returned
- IDictionary.
+ IDictionary.Lets take a look at an example. The following stored procedure
class will call the CustOrdersDetail stored procedure in the Northwind
database, passing in the OrderID as a stored procedure argument and
returning a collection of OrderDetails business objects.
- public class CustOrdersDetailStoredProc : StoredProcedure
+ public class CustOrdersDetailStoredProc : StoredProcedure
{
private static string procedureName = "CustOrdersDetail";
@@ -2262,15 +2279,15 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
DeriveParameters().
- The StoredProcedure class is threadsafe
+ The StoredProcedure class is threadsafe
once 'compiled', an act which is usually done in the constructor. This
sets up the cache of database parameters that can be used on each call
to Query or QueryByNamedParam. The implementation of
- IRowMapper that is used to extract the business
+ IRowMapper that is used to extract the business
objects is 'registered' with the class and then later retrieved by name
as a fictional output parameter. You may also register
- IRowCallback and
- IResultSetExtractor callback interfaces via the
+ IRowCallback and
+ IResultSetExtractor callback interfaces via the
AddRowCallback and
AddResultSetExtractor methods.
@@ -2279,7 +2296,7 @@ public static void ApplyConnectionAndTx(object typedDataSetAdapter, IDbProvider
type parameters that will be used to process result sets returned from
the stored procedure. An example is shown below
- public class CustOrdersDetailStoredProc : StoredProcedure
+ public class CustOrdersDetailStoredProc : StoredProcedure
{
private static string procedureName = "CustOrdersDetail";
diff --git a/doc/reference/src/ajax.xml b/doc/reference/src/ajax.xml
index 71ee9a06..76e0e16c 100644
--- a/doc/reference/src/ajax.xml
+++ b/doc/reference/src/ajax.xml
@@ -1,7 +1,7 @@
-
+ASP.NET AJAX
-
+ IntroductionSpring's ASP.NET AJAX integration allows for a plain .NET object
@@ -29,40 +29,40 @@
JavaScript.
-
+ Web ServicesSpring.NET, and particularly Spring.Web, improved support
for web services in .NET with the
- WebServiceExporter. Exporting of an ordinary plain
+ WebServiceExporter. Exporting of an ordinary plain
.NET object as a web service is achieved by registering a custom
- implementation of the WebServiceHandlerFactory
+ implementation of the WebServiceHandlerFactory
class as the HTTP handler for *.asmx requests.Microsoft
ASP.NET AJAX introduced a new HTTP handler
- System.Web.Script.Services.ScriptHandlerFactory to
+ System.Web.Script.Services.ScriptHandlerFactory to
allow a Web Service to be invoked from the browser by using
JavaScript.Spring's integration allows for both Spring.Web and ASP.NET AJAX
functionality to be used together by creating a new HTTP handler.
-
+ Exposing Web Services
- The WebServiceExporter combined with the
+ The WebServiceExporter combined with the
new HTTP handler exposes PONOs as Web Services in your ASP.NET AJAX
application.In order for a Web service to be accessed from script, the
- WebServiceExporter should decorate the Web
- Service class with the ScriptServiceAttribute.
+ WebServiceExporter should decorate the Web
+ Service class with the ScriptServiceAttribute.
The code below is taken from the sample application
Spring.Web.Extensions.Sample, aka the 'AJAX' shortcut in the
- installation. :
+ installation. :
<object id="ContactWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
<property name="TargetName" value="ContactService"/>
<property name="Namespace" value="http://Spring.Examples.Atlas/ContactService"/>
@@ -77,15 +77,17 @@
All that one needs to do in order to use the
- WebServiceExporter is:
+ WebServiceExporter is: 1. Configure the Web.config file of your ASP.NET AJAX
- application as a Spring.Web application.
+ application as a Spring.Web application.
+
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
</sectionGroup>
-
+
+
<spring>
<context>
<resource uri="~/Spring.config"/>
@@ -96,7 +98,7 @@
2. Register the HTTP handler and the Spring HttpModule
under the system.web section.
-
+
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false" type="Spring.Web.Script.Services.ScriptHandlerFactory, Spring.Web.Extensions"/>
@@ -113,7 +115,7 @@
3. Register the HTTP handler and the Spring HttpModule
under system.webServer section.
-
+
<modules>
<add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add name="SpringModule" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
@@ -133,14 +135,14 @@
this integration.
-
+ Calling Web Services by using JavaScriptA proxy class is generated for each Web Service. Calls to Web
Services methods are made by using this proxy class. When using the
- WebServiceExporter, the name of the proxy class
- is equal to the WebServiceExporter's id.
-
+ WebServiceExporter, the name of the proxy class
+ is equal to the WebServiceExporter's id.
+
// This function calls the Contact Web service method
// passing simple type parameters and the callback function
function GetEmails(prefix, count)
diff --git a/doc/reference/src/aop-aspect-library.xml b/doc/reference/src/aop-aspect-library.xml
index 845addff..a7d9a9b2 100644
--- a/doc/reference/src/aop-aspect-library.xml
+++ b/doc/reference/src/aop-aspect-library.xml
@@ -1,8 +1,25 @@
-
+
+Aspect Library
-
+ IntroductionSpring provides several aspects in the distribution. The most
@@ -15,7 +32,7 @@
release.
-
+ CachingCaching the return value of a method or the value of a method
@@ -34,12 +51,12 @@
functionality and its configuration.The base cache interface that any cache implementation should
- implement is Spring.Caching.ICache located in
- Spring.Core. Two implementations are provided,
- Spring.Caching.AspNetCache located in
- Spring.Web which stores cache entries within an
+ implement is Spring.Caching.ICache located in
+ Spring.Core. Two implementations are provided,
+ Spring.Caching.AspNetCache located in
+ Spring.Web which stores cache entries within an
ASP.NET cache and a simple implementation,
- Spring.Caching.NonExpiringCache that stores cache
+ Spring.Caching.NonExpiringCache that stores cache
entries in memory and never expires these entries. Custom implementations
based on 3rd party implementations, such as Oracle Coherence, or
memcached, can be used by implementing the ICache
@@ -59,18 +76,18 @@
- CacheResult - used to cache the return
- value
+ CacheResult - used to cache the return
+ value
- CacheResultItems - used when returning a collection as
- a return value
+ CacheResultItems - used when returning a collection as
+ a return value
- CacheParameter - used to cache a method
- parameter
+ CacheParameter - used to cache a method
+ parameter
@@ -79,9 +96,9 @@
- Each CacheResult,
- CacheResultItems, and
- CacheParameter attributes define the following
+ Each CacheResult,
+ CacheResultItems, and
+ CacheParameter attributes define the following
properties.
@@ -108,13 +125,13 @@
- The InvalidateCache attribute has properties
+ The InvalidateCache attribute has properties
for the CacheName, the Key as well as the Condition, with the same
meanings as listed previously.
- Each ICache implementation will have
+ Each ICache implementation will have
properties that are specific to a caching technology. In the case of
- AspNetCache, the two important properties to
+ AspNetCache, the two important properties to
configure are:
@@ -166,12 +183,11 @@
sample application of the AirportDao implementation that implements an
interface with the method GetAirport(long id).
- [CacheResult("AspNetCache", "'Airport.Id=' + #id", TimeToLive = "0:1:0")]
- public Airport GetAirport(long id)
- {
- // implementation not shown...
- }
-
+ [CacheResult("AspNetCache", "'Airport.Id=' + #id", TimeToLive = "0:1:0")]
+public Airport GetAirport(long id)
+{
+ // implementation not shown...
+}The first parameter is the cache name. The second string parameter
is the cache key and is a string expression that incorporates the argument
@@ -186,35 +202,35 @@
The configuration to enable the caching aspect is shown below
- <object id="CacheAspect" type="Spring.Aspects.Cache.CacheAspect, Spring.Aop"/>
- <object id="AspNetCache" type="Spring.Caching.AspNetCache, Spring.Web">
- <property name="SlidingExpiration" value="true"/>
- <property name="Priority" value="Low"/>
- <property name="TimeToLive" value="00:02:00"/>
- </object>
+
+
- <!-- Apply aspects to DAOs -->
- <object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
- <property name="ObjectNames">
- <list>
- <value>*Dao</value>
- </list>
- </property>
- <property name="InterceptorNames">
- <list>
- <value>CacheAspect</value>
- </list>
- </property>
- </object>
+
+]]>
- in this example an ObjectNameAutoProxyCreator
+ in this example an ObjectNameAutoProxyCreator
was used to apply the cache aspect to objects that have Dao in their name.
The AspNetCache setting for TimeToLive will override the TimeToLive value
set at the method level via the attribute.
-
+ Exception HandlingIn some cases existing code can be easily adopted to a simple error
@@ -252,13 +268,13 @@
could be referred to as a Domain Specific Language (DSL). Here is a simple
example, which should hopefully be self explanatory.
- <object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
- <property name="exceptionHandlers">
- <list>
- <value>on exception name ArithmeticException wrap System.InvalidOperationException</value>
- </list>
- </property>
-</object>What this is instructing the advice to do is
+
+
+
+ on exception name ArithmeticException wrap System.InvalidOperationException
+
+
+]]>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
@@ -283,7 +299,7 @@ on exception name ArithmeticException replace System.InvalidOperationException '
on exception name ArithmeticException translate new System.InvalidOperationException('My Message, Method Name ' + #method.Name, #e)What
we see here after the translate keyword is text that will be passed into
Spring's expression language (SpEL) for evaluation. Refer to the chapter
- on the expression language for more
+ on the expression language for more
details. One important feature of the expression evaluation is the
availability of variables relating to the calling context when the
exception was thrown. These are
@@ -340,7 +356,7 @@ on exception name ArithmeticException return 12
action, i.e. log(Debug,"LoggerName").Multiple exception handling statements can be specified within the
- <list> shown above. The processing flow is on exception, the name of
+ 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
@@ -383,17 +399,17 @@ on exception name ArithmeticException return 12
for example setting the logging level and pass the exception into the
logging subsystem
- <object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
- <property name="exceptionHandlers">
- <list>
- <object type="Spring.Aspects.Exceptions.LogExceptionHandler">
- <property name="LogName" value="Cms.Session.ExceptionHandler" />
- <property name="ConstraintExpressionText" value="#e is T(System.Threading.ThreadAbortException)" />
- <property name="ActionExpressionText" value="#log.Fatal('Request Timeout occured', #e)" />
- </object>
- </list>
- </property>
-</object>
+
+
+
+
+
+
+]]>The configuration of the logger name, level, and weather or not to
pass the thrown exception as the second argument to the log method will be
@@ -455,12 +471,12 @@ on exception name ArithmeticException return 12
-
+ LoggingThe logging advice lets you log the information on method entry,
exit and thrown exception (if any). The implementation is based on the
- logging library, Common.Logging, that provides
+ logging library, Common.Logging, that provides
portability across different logging libraries. There are a number of
configuration options available, listed below
@@ -492,21 +508,21 @@ on exception name ArithmeticException return 12
You declare the logging advice in IoC container with the following
XML fragment. Alternatively, you can use the class
- SimpleLoggingAdvice programatically.
+ SimpleLoggingAdvice programatically.
- <object name="loggingAdvice" type="Spring.Aspects.Logging.SimpleLoggingAdvice, Spring.Aop">
- <property name="logUniqueIdentifier" value="true"/>
- <property name="logExecutionTime" value="true"/>
- <property name="logMethodArguments" value="true"/>
- <property name="LogReturnValue" value="true"/>
+
+
+
+
+
- <property name="Separator" value=";"/>
- <property name="LogLevel" value="Info"/>
+
+
- <property name="HideProxyTypeNames" value="true"/>
- <property name="UseDynamicLogger" value="true"/>
-</object>
+
+
+]]>The default values for LogUniqueIdentifier, LogExecutionTime,
LogMethodArguments and LogReturnValue are false. The default separator
@@ -526,8 +542,8 @@ on exception name ArithmeticException return 12
true target type and not the proxy type.To further extend the functionality of the
- SimpleLoggingAdvice you can subclass
- SimpleLoggingAdvice and override the methods
+ SimpleLoggingAdvice you can subclass
+ SimpleLoggingAdvice and override the methods
@@ -551,19 +567,19 @@ on exception name ArithmeticException return 12
The default implementation to calculate a unique identifier is to
use a GUID. You can alter this behavior by overriding the method
string CreateUniqueIdentifier(). The
- SimpleLoggingAdvice class inherits from
- AbstractLoggingAdvice, which has the abstract
+ SimpleLoggingAdvice class inherits from
+ AbstractLoggingAdvice, which has the abstract
method object InvokeUnderLog(IMethodInvocation invocation, ILog
log) and you can also override the method ILog
GetLoggerForInvocation(IMethodInvocation invocation) to
customize the logger instance used for logging. Refer to the SDK
documentation for more details on subclassing
- AbstractLoggingAdvice.
+ AbstractLoggingAdvice.
As an example of the Logging advice's output, adding the advice to
the method
- public int Bark(string message, int[] luckyNumbers)
+ public int Bark(string message, int[] luckyNumbers)
{
return 4;
}
@@ -586,7 +602,7 @@ Exiting Bark, 5d2bad47-62cd-435b-8de7-91f12b7f433e, 30453.125 ms, return=4
-
+ RetryWhen making a distributed call it is often a common requirement to
@@ -657,11 +673,11 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)
You declare the advice in IoC container with the
following XML fragment. Alternatively, you can use the
- RetryAdvice class programatically.
+ RetryAdvice class programatically.
- <object name="exceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
- <property name="retryExpression" value="on exception name ArithmeticException retry 3x delay 1s"/>
-</object>
+
+
+]]>Language Reference
@@ -679,14 +695,14 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)
-
+ TransactionsThe transaction aspect is more fully described in the section on
transaction management.
-
+ Parameter ValidationSpring provides a UI-agnostic validation
@@ -705,15 +721,15 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)To address some of the common needs for validation on the server
side, Spring provides parameter validation advice so that applies Spring's
validation rules to the method parameters. The class
- ParameterValidationAdvice is used in conjunction
- with the Validated attribute to specify which
+ ParameterValidationAdvice is used in conjunction
+ with the Validated attribute to specify which
validation rules are applied to method parameters. For example, to apply
parameter validation to the method SuggestFlights in the BookingAgent
class used in the SpringAir sample
- application, you would apply the Validated
+ application, you would apply the Validated
attribute to the method parameters as shown below.
- public FlightSuggestions SuggestFlights( [Validated("tripValidator")] Trip trip)
+ public FlightSuggestions SuggestFlights( [Validated("tripValidator")] Trip trip)
{
// unmodified implementation goes here
}
@@ -721,34 +737,34 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)The Validated attribute takes a string name that
specifies the name of the validation rule, i.e. the name of the IValidator
object in the Spring application context. The
- Validated attribute is located in the namespace
+ Validated attribute is located in the namespace
Spring.Validation of the Spring.Core
assembly.
The configuration of the advice is to simply define the an instance
of the ParameterValidationAdvice class and apply the
advice, for example based on object names using an
- ObjectNameAutoProxyCreator, as shown below,
+ ObjectNameAutoProxyCreator, as shown below,
- <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>
+]]>When the advised method is invoked first the validation of each
method parameter is performed. If all validation succeeds, then the method
body is executed. If validation fails an exception of the type
- ValidationException is thrown and you can retrieve
+ ValidationException is thrown and you can retrieve
errors information from its property ValidationErrors.
See the SDK documentation for details.
diff --git a/doc/reference/src/aop-quickstart.xml b/doc/reference/src/aop-quickstart.xml
index 90e107ae..dd7a6b11 100644
--- a/doc/reference/src/aop-quickstart.xml
+++ b/doc/reference/src/aop-quickstart.xml
@@ -1,8 +1,25 @@
-
+
+AOP Guide
-
+ IntroductionThis is an introductory guide to Aspect Oriented Programming (AOP)
@@ -37,13 +54,13 @@
linkend="springair" />).
-
+ The basicsThis initial section introduces the basics of defining and then
applying some simple advice.
-
+ Applying adviceLets see (a very basic) example of using Spring.NET AOP. The
@@ -59,27 +76,27 @@
terminology, an instance of the following class is going to be the
advised object.
- public interface ICommand
+ public interface ICommand
+{
+ object Execute(object context);
+}
+
+public class ServiceCommand : ICommand
+{
+ public object Execute(object context)
{
- object Execute(object context);
+ Console.Out.WriteLine("Service implementation : [{0}]", context);
+ return null;
}
-
- public class ServiceCommand : ICommand
- {
- public object Execute(object context)
- {
- Console.Out.WriteLine("Service implementation : [{0}]", context);
- return null;
- }
- }
+}Find below the advice that is going to be applied to the
object Execute(object context) method of the
- ServiceCommand class. As you can see, this is an
+ ServiceCommand class. As you can see, this is an
example of around advice (see ).
- public class ConsoleLoggingAroundAdvice : IMethodInterceptor
+ public class ConsoleLoggingAroundAdvice : IMethodInterceptor
{
public object Invoke(IMethodInvocation invocation)
{
@@ -129,16 +146,16 @@
So thus far we have three artifacts: an interface
- (ICommand); an implementation of said interface
- (ServiceCommand); and some (trivial) advice
- (encapsulated by the ConsoleLoggingAroundAdvice
+ (ICommand); an implementation of said interface
+ (ServiceCommand); and some (trivial) advice
+ (encapsulated by the ConsoleLoggingAroundAdvice
class). All that remains is to actually apply the
- ConsoleLoggingAroundAdvice advice to the
+ ConsoleLoggingAroundAdvice advice to the
invocation of the Execute() method of the
- ServiceCommand class. Lets look at how to effect
+ ServiceCommand class. Lets look at how to effect
this programmatically...
- ProxyFactory factory = new ProxyFactory(new ServiceCommand());
+ ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingAroundAdvice());
ICommand command = (ICommand) factory.GetProxy();
command.Execute("This is the argument");
@@ -152,23 +169,23 @@
The output shows that the advice (the
Console.Out statements from the
- ConsoleLoggingAroundAdvice was applied
+ ConsoleLoggingAroundAdvice was applied
around the invocation of the advised method.So what is happening here? The fact that the preceding code used a
- class called ProxyFactory may have clued you in.
- The constructor for the ProxyFactory class took
+ class called ProxyFactory may have clued you in.
+ The constructor for the ProxyFactory class took
as an argument the object that we wanted to advise (in this case, an
- instance of the ServiceCommand class). We then
- added some advice (a ConsoleLoggingAroundAdvice
+ instance of the ServiceCommand class). We then
+ added some advice (a ConsoleLoggingAroundAdvice
instance) using the AddAdvice() method of the
- ProxyFactory instance. We then called the
+ ProxyFactory instance. We then called the
GetProxy() method of the
- ProxyFactory instance which gave us a proxy... an
+ ProxyFactory instance which gave us a proxy... an
(AOP) proxy that proxied the target object (the
- ServiceCommand instance), and called the advice
+ ServiceCommand instance), and called the advice
(a single instance of the
- ConsoleLoggingAroundAdvice in this case). When we
+ ConsoleLoggingAroundAdvice in this case). When we
invoked the Execute(object context) method of the
proxy, the advice was 'applied' (executed), as can be
seen from the attendant output.
@@ -184,9 +201,9 @@
One thing to note here is that the AOP proxy that was returned
from the call to the GetProxy() method of the
- ProxyFactory instance was cast to the
- ICommand interface that the
- ServiceCommand target object implemented. This is
+ ProxyFactory instance was cast to the
+ ICommand interface that the
+ ServiceCommand target object implemented. This is
very important... currently, Spring.NET's AOP implementation mandates
the use of an interface for advised objects. In short, this means that
in order for your classes to leverage Spring.NET's AOP support, those
@@ -208,7 +225,7 @@
should also be added that this declarative style approach to Spring.NET
AOP is preferred to the programmatic style.
- <object id="consoleLoggingAroundAdvice"
+ <object id="consoleLoggingAroundAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>
<object id="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="target">
@@ -222,50 +239,50 @@
</property>
</object>
- ICommand command = (ICommand) ctx["myServiceObject"];
+ ICommand command = (ICommand) ctx["myServiceObject"];
command.Execute();Some comments are warranted concerning the above XML configuration
snippet. Firstly, note that the
- ConsoleLoggingAroundAdvice is itself a plain
+ ConsoleLoggingAroundAdvice is itself a plain
vanilla object, and is eligible for configuration just like any other
class... if the advice itself needed to be injected with any
dependencies, any such dependencies could be injected as normal.Secondly, notice that the object definition corresponding to the
object that is retrieved from the IoC container is a
- ProxyFactoryObject. The
- ProxyFactoryObject class is an implementation of
- the IFactoryObject interface;
- IFactoryObject implementations are treated
+ ProxyFactoryObject. The
+ ProxyFactoryObject class is an implementation of
+ the IFactoryObject interface;
+ IFactoryObject implementations are treated
specially by the Spring.NET IoC container... in this specific case, it
- is not a reference to the ProxyFactoryObject
+ is not a reference to the ProxyFactoryObject
instance itself that is returned, but rather the object that the
- ProxyFactoryObject produces. In this case, it
- will be an advised instance of the ServiceCommand
+ ProxyFactoryObject produces. In this case, it
+ will be an advised instance of the ServiceCommand
class.Thirdly, notice that the target of the
- ProxyFactoryObject is an instance of the
- ServiceCommand class; this is the object that is
+ ProxyFactoryObject is an instance of the
+ ServiceCommand class; this is the object that is
going to be advised (i.e. invocations of its methods are going to be
intercepted). This object instance is defined as an inner object
definition... this is the preferred idiom for using the
- ProxyFactoryObject, as it means that other
+ ProxyFactoryObject, as it means that other
objects cannot acquire a reference to the raw object, but rather only
the advised object.Finally, notice that the advice that is to be applied to the
target object is referred to by its object name in the list of the names
- of interceptors for the ProxyFactoryObject's
+ of interceptors for the ProxyFactoryObject's
interceptorNames property. In this particular case,
there is only one instance of advice being applied... the
- ConsoleLoggingAroundAdvice defined in an object
+ ConsoleLoggingAroundAdvice defined in an object
definition of the same name. The reason for using a list of object names
as opposed to references to the advice objects themselves is explained
in the reference documentation...
- '... if the ProxyFactoryObject's
+ '... if the ProxyFactoryObject's
singleton property is set to false, it must be able to return
independent proxy instances. If any of the advisors is itself a
prototype, an independent instance would need to be returned, so it is
@@ -273,12 +290,12 @@
context; holding a reference isn't sufficient.'
-
+ Using Pointcuts - the basicsThe advice that was applied in the previous section was rather
indiscriminate with regard to which methods on the advised object were
- to be advised... the ConsoleLoggingAroundAdvice
+ to be advised... the ConsoleLoggingAroundAdvice
simply intercepted all methods (that
were part of an interface implementation) on the target object.
@@ -292,22 +309,22 @@
The mechanism that Spring.NET AOP uses to discriminate about where
advice is applied (i.e. which method invocations are intercepted) is
- encapsulated by the IPointcut interface (see
+ encapsulated by the IPointcut interface (see
). Spring.NET provides many
- out-of-the-box implementations of the IPointcut
+ out-of-the-box implementations of the IPointcut
interface... the implementation that is used if none is explicitly
supplied (as was the case with the first example) is the canonical
- TruePointcut : as the name suggests, this
+ TruePointcut : as the name suggests, this
pointcut always matches, and hence all
methods that can be advised will be advised.So let's change the configuration of the advice such that it is
only applied to methods that contain the letters
'Do'. We'll change the
- ICommand interface (and it's attendant
+ ICommand interface (and it's attendant
implementation) to accommodate this...
- public interface ICommand
+ public interface ICommand
{
void Execute();
@@ -328,7 +345,7 @@
}Please note that the advice itself (encapsulated within the
- ConsoleLoggingAroundAdvice class) does not need
+ ConsoleLoggingAroundAdvice class) does not need
to change; we are changing where this advice is
applied, and not the advice itself.
@@ -336,7 +353,7 @@
fact that we only want methods that contain the letters
'Do' to be advised, looks like this...
- ProxyFactory factory = new ProxyFactory(new ServiceCommand());
+ ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvisor(new DefaultPointcutAdvisor(
new SdkRegularExpressionMethodPointcut("Do"),
new ConsoleLoggingAroundAdvice()));
@@ -346,7 +363,7 @@
The result of executing the above snippet of code will look
something like this...
- Intercepted call : about to invoke next item in chain...
+ Intercepted call : about to invoke next item in chain...
Service implementation...
Intercepted call : returned
@@ -356,7 +373,7 @@
the pertinent code snippet to invoke the Execute()
method, like so...
- ProxyFactory factory = new ProxyFactory(new ServiceCommand());
+ ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvisor(
new DefaultPointcutAdvisor(
new SdkRegularExpressionMethodPointcut("Do"),
@@ -376,7 +393,7 @@
XML configuration that accomplishes exactly the same thing as the
previous programmatic configuration example can be seen below...
- <object id="consoleLoggingAroundAdvice"
+ <object id="consoleLoggingAroundAdvice"
type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor">
<property name="pattern" value="Do"/>
<property name="advice">
@@ -407,12 +424,12 @@
that match the pattern 'Do' (the pointcut). The
pattern to match against is supplied as a simple string value to the
pattern property of the
- RegularExpressionMethodPointcutAdvisor
+ RegularExpressionMethodPointcutAdvisor
class.
-
+ Going deeperThe first section should (hopefully) have demonstrated the basics of
@@ -423,18 +440,18 @@
describes the various advice and pointcuts that are available for you to
use (yes, there is more than one type of advice and pointcut).
-
+ Other types of AdviceThe advice that was demonstrated and explained in the preceding
section is what is termed 'around advice'. The name
'around advice' is used because the advice is
applied around the target method invocation. In the
- specific case of the ConsoleLoggingAroundAdvice
+ specific case of the ConsoleLoggingAroundAdvice
advice that was defined previously, the target was made available to the
- advice as an IMethodInvocation object... a call
- was made to the Console class before the target
- was invoked, and a call was made to the Console
+ advice as an IMethodInvocation object... a call
+ was made to the Console class before the target
+ was invoked, and a call was made to the Console
class after the target method invocation was invoked. The advice
surrounded the target, one could even say that the advice was totally
'around' the target... hence the name, 'around
@@ -448,14 +465,14 @@
value.Sometimes you don't need all that power though. If we stick with
- the example of the ConsoleLoggingAroundAdvice
+ the example of the ConsoleLoggingAroundAdvice
advice, what if one just wants to log the fact that a method was called?
In that case one doesn't need to do anything after
the target method invocation is to be invoked, nor do you need access to
the return value of the target method invocation. In fact, you only want
to do something before the target is to be invoked
(in this case, print out a message to the system
- Console detailing the name of the method). In the
+ Console detailing the name of the method). In the
tradition of good programming that says one should use only what one
needs and no more, Spring.NET has another type of advice that one can
use... if one only wants to do something before the
@@ -463,7 +480,7 @@
call the Proceed() method? The most expedient
solution simply is to use 'before advice'.
-
+ Before advice'before advice' is just that... it is
@@ -479,13 +496,13 @@
advice' is just what you need.'before advice' in Spring.NET is defined by
- the IMethodBeforeAdvice interface in the
+ the IMethodBeforeAdvice interface in the
Spring.Aop namespace. Lets just dive in with an
example... we'll use the same scenario as before to keep things
simple. Let's define the 'before advice'
implementation first.
- public class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice
+ public class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice
{
public void Before(MethodInfo method, object[] args, object target)
{
@@ -503,15 +520,15 @@
}Let's apply a single instance of the
- ConsoleLoggingBeforeAdvice advice to the
+ ConsoleLoggingBeforeAdvice advice to the
invocation of the Execute() method of the
- ServiceCommand. What follows is programmatic
+ ServiceCommand. What follows is programmatic
configuration; as you can see, its pretty much identical to the
previous version... the only difference is that we're using our new
'before advice' (encapsulated as an instance of
- the ConsoleLoggingBeforeAdvice class).
+ the ConsoleLoggingBeforeAdvice class).
- ProxyFactory factory = new ProxyFactory(new ServiceCommand());
+ ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
ICommand command = (ICommand) factory.GetProxy();
command.Execute();
@@ -529,7 +546,7 @@
advice', with 'before advice' there is
no chance of forgetting to call the Proceed()
method on the target, because one does not have access to the
- IMethodInvocation (as is the case with
+ IMethodInvocation (as is the case with
'around advice')... similarly, you cannot forget
to return the return value either.
@@ -541,7 +558,7 @@
Here is the Spring.NET XML configuration for applying our
'before advice' declaratively...
- <object id="beforeAdvice"
+ <object id="beforeAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
<object id="myServiceObject"
@@ -558,7 +575,7 @@
</object>
-
+ After adviceJust as 'before advice' defines advice that
@@ -567,12 +584,12 @@
role="bold">after a target has been executed.'after advice' in Spring.NET is defined by
- the IAfterReturningAdvice interface in the
+ the IAfterReturningAdvice interface in the
Spring.Aop namespace. Again, lets just fire on
ahead with an example... again, we'll use the same scenario as before
to keep things simple.
- public class ConsoleLoggingAfterAdvice : IAfterReturningAdvice
+ public class ConsoleLoggingAfterAdvice : IAfterReturningAdvice
{
public void AfterReturning(
object returnValue, MethodInfo method, object[] args, object target)
@@ -592,17 +609,17 @@
}Let's apply a single instance of the
- ConsoleLoggingAfterAdvice advice to the
+ ConsoleLoggingAfterAdvice advice to the
invocation of the Execute() method of the
- ServiceCommand. What follows is programmatic
+ ServiceCommand. What follows is programmatic
configuration; as you can, its pretty much identical to the
'before advice' version (which in turn was pretty
much identical to the original 'around advice'
version)... the only real difference is that we're using our new
'after advice' (encapsulated as an instance of
- the ConsoleLoggingAfterAdvice class).
+ the ConsoleLoggingAfterAdvice class).
- ProxyFactory factory = new ProxyFactory(new ServiceCommand());
+ ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingAfterAdvice());
ICommand command = (ICommand) factory.GetProxy();
command.Execute();
@@ -624,7 +641,7 @@
advice' there is no chance of forgetting to call the
Proceed() method on the target, because just like
'before advice' you don't have access to the
- IMethodInvocation... similarly, although you
+ IMethodInvocation... similarly, although you
get access to the return value of the target, you cannot forget to
return the return value either. You can however change the state of
the return value, typically by setting some of its properties, or by
@@ -652,7 +669,7 @@
Here is the Spring.NET XML configuration for applying the
'after advice' declaratively...
- <object id="afterAdvice"
+ <object id="afterAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/>
<object id="myServiceObject"
@@ -669,7 +686,7 @@
</object>
-
+ Throws adviceSo far we've covered 'around advice',
@@ -697,13 +714,13 @@
possible uses cases is of course endless.The 'throws advice' type in Spring.NET is
- defined by the IThrowsAdvice interface in the
+ defined by the IThrowsAdvice interface in the
Spring.Aop namespace... basically, one defines on
one's 'throws advice' implementation class what
types of exception are going to be handled. Lets take a quick look at
- the IThrowsAdvice interface...
+ the IThrowsAdvice interface...
- public interface IThrowsAdvice : IAdvice
+ public interface IThrowsAdvice : IAdvice
{
}
@@ -714,7 +731,7 @@
point, so here is some simple Spring.NET style 'throws
advice'...
- public class ConsoleLoggingThrowsAdvice : IThrowsAdvice
+ public class ConsoleLoggingThrowsAdvice : IThrowsAdvice
{
public void AfterThrowing(Exception ex)
{
@@ -724,11 +741,11 @@
Lets also change the implementation of the
Execute() method of the
- ServiceCommand class such that it throws an
+ ServiceCommand class such that it throws an
exception. This will allow the advice encapsulated by the above
- ConsoleLoggingThrowsAdvice to kick in.
+ ConsoleLoggingThrowsAdvice to kick in.
- public class ServiceCommand : ICommand
+ public class ServiceCommand : ICommand
{
public void Execute()
{
@@ -738,11 +755,11 @@
Let's programmatically apply the 'throws
advice' (an instance of our
- ConsoleLoggingThrowsAdvice) to the invocation
+ ConsoleLoggingThrowsAdvice) to the invocation
of the Execute() method of the above
- ServiceCommand class; to wit...
+ ServiceCommand class; to wit...
- ProxyFactory factory = new ProxyFactory(new ServiceCommand());
+ ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
ICommand command = (ICommand) factory.GetProxy();
command.Execute();
@@ -754,19 +771,19 @@
Attempted to perform an unauthorized operation.As can be seen from the output, the
- ConsoleLoggingThrowsAdvice kicked in when the
+ ConsoleLoggingThrowsAdvice kicked in when the
advised method invocation threw an exception. There are a number of
things to note about the
- ConsoleLoggingThrowsAdvice advice class, so
+ ConsoleLoggingThrowsAdvice advice class, so
lets take them each in turn.In Spring.NET, 'throws advice' means that
you have to define a class that implements the
- IThrowsAdvice interface. Then, for each type of
+ IThrowsAdvice interface. Then, for each type of
exception that your 'throws advice' is going to
handle, you have to define a method with this signature...
- void AfterThrowing(Exception ex)
+ void AfterThrowing(Exception ex)Basically, your exception handling method has to be named
AfterThrowing. This name is important... your
@@ -779,19 +796,19 @@
in the future).Your exception handling method must (at the very least) declare
- a parameter that is an Exception type... this
- parameter can be the root Exception class (as
+ a parameter that is an Exception type... this
+ parameter can be the root Exception class (as
in the case of the above example), or it can be an
- Exception subclass if you only want to handle
+ Exception subclass if you only want to handle
certain types of exception. It is good practice to always make your
- exception handling methods have an Exception
+ exception handling methods have an Exception
parameter that is the most specialized
- Exception type possible... i.e. if you are
+ Exception type possible... i.e. if you are
applying 'throws advice' to a method that could
- only ever throw ArgumentExceptions, then
+ only ever throw ArgumentExceptions, then
declare the parameter of your exception handling method as...
- void AfterThrowing(ArgumentException ex)
+ void AfterThrowing(ArgumentException ex)Note that your exception handling method can have any return
type, but returning any value from a Spring.NET 'throws
@@ -803,7 +820,7 @@
Finally, here is the Spring.NET XML configuration for applying
the 'throws advice' declaratively...
- <object id="throwsAdvice"
+ <object id="throwsAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/>
<object id="myServiceObject"
@@ -830,14 +847,14 @@
wrapped exception in the body of one's exception handling method. One
can use this to implement some sort of exception translation or
exception scrubbing policy, in which implementation specific
- exceptions (such as SqlException or
- OracleException exceptions being thrown by an
+ exceptions (such as SqlException or
+ OracleException exceptions being thrown by an
advised data access object) get replaced with a business exception
that has meaning to the service objects in one's business layer. A toy
example of this type of 'throws advice' can be
seen below.
- public class DataAccessExceptionScrubbingThrowsAdvice : IThrowsAdvice
+ public class DataAccessExceptionScrubbingThrowsAdvice : IThrowsAdvice
{
public void AfterThrowing (SqlException ex)
{
@@ -862,11 +879,11 @@
reference documentation, which describes how to declare an exception
handling method that gives one access to the above extra objects, and
how to declare multiple exception handling methods on the same
- IThrowsAdvice implementation class (see IThrowsAdvice implementation class (see ).
-
+ Introductions (mixins)In a nutshell, introductions are all about adding new state and
@@ -877,7 +894,7 @@
don't share the same inheritance hierarchy.
-
+ Layering adviceThe examples shown so far have all demonstrated the application
@@ -898,18 +915,18 @@
Please do consult the class definitions for the following
previously defined advice types to see exactly what each advice type
implementation does... we're going to be using single instances of the
- ConsoleLoggingAroundAdvice,
- ConsoleLoggingBeforeAdvice,
- ConsoleLoggingAfterAdvice, and
- ConsoleLoggingThrowsAdvice advice to advise a
- single instance of the ServiceCommand
+ ConsoleLoggingAroundAdvice,
+ ConsoleLoggingBeforeAdvice,
+ ConsoleLoggingAfterAdvice, and
+ ConsoleLoggingThrowsAdvice advice to advise a
+ single instance of the ServiceCommand
class.You can find the following listing and executable application in
the AopQuickStart solution in the project
Spring.AopQuickStart.Step1.
- ProxyFactory factory = new ProxyFactory(new ServiceCommand());
+ ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
factory.AddAdvice(new ConsoleLoggingAfterAdvice());
factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
@@ -924,7 +941,7 @@
the AopQuickStart solution in the project
Spring.AopQuickStart.Step2.
- <object id="throwsAdvice"
+ <object id="throwsAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/>
<object id="afterAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/>
@@ -950,7 +967,7 @@
</object>
-
+ Configuring adviceIn case it is not immediately apparent, remember that advice is
@@ -978,14 +995,14 @@
-
+ Using Attributes to define Pointcuts
-
+ The Spring.NET AOP CookbookThe preceding treatment of Spring.NET AOP has (quite intentionally)
@@ -993,7 +1010,7 @@
Spring.NET AOP... this section of the Spring.NET AOP guide contains a
number of real world examples of the application of Spring.NET AOP.
-
+ CachingThis example illustrates one of the more common usages of AOP...
@@ -1005,26 +1022,26 @@
it exists only in the database to satisfy referential integrity amongst
the various relations in the database schema. An example of such static
(and typically immutable) reference data would be a collection of
- Country objects (comprising a country name and a
+ Country objects (comprising a country name and a
code). What we would like to do is suck in the collection of
- Country objects and then pin them in a cache.
+ Country objects and then pin them in a cache.
This saves us having to hit the back end database again and again every
time we need to reference a country in our application (for example, to
populate dropdown controls in a Windows Forms desktop
application).The Data Access Object (DAO) that will load the collection of
- Country objects is called
- AdoCountryDao (it is an implementation of the
+ Country objects is called
+ AdoCountryDao (it is an implementation of the
data-access-technology agnostic DAO interface called
- ICountryDao). The implementation of the
- AdoCountryDao is quite simple, in that every time
+ ICountryDao). The implementation of the
+ AdoCountryDao is quite simple, in that every time
the FindAllCountries instance method is called, an
instance will query the database for an
- IDataReader and hydrate zero or more
- Country objects using the returned data.
+ IDataReader and hydrate zero or more
+ Country objects using the returned data.
- public class AdoCountryDao : ICountryDao
+ public class AdoCountryDao : ICountryDao
{
public IList FindAllCountries ()
{
@@ -1044,15 +1061,15 @@
The mechanism that this example is going to use to identify (or
pick out) areas in our application that we would like to apply caching
- to is a .NET Attribute. Spring.NET ships with a
- number of useful custom .NET Attribute
+ to is a .NET Attribute. Spring.NET ships with a
+ number of useful custom .NET Attribute
implementations, one of which is the cunningly named
- CacheAttribute. In the specific case of this
+ CacheAttribute. In the specific case of this
example, we are simply going to decorate the definition of the
FindAllCountries instance method with the
- CacheAttribute.
+ CacheAttribute.
- public class AdoCountryDao : ICountryDao
+ public class AdoCountryDao : ICountryDao
{
[Cache]
public IList FindAllCountries ()
@@ -1067,7 +1084,7 @@
applied using Spring.NET AOP (see ).
-
+ Performance MonitoringThis recipe show how easy it is to instrument the classes and
@@ -1076,7 +1093,7 @@
counters to display and track the performance data.
-
+ Retry RulesThis final recipe describes a simple (but really quite useful)
@@ -1087,7 +1104,7 @@
-
+ Spring.NET AOP Best PracticesSpring.NET AOP is an 80% AOP solution, in that it only tries to
diff --git a/doc/reference/src/aop.xml b/doc/reference/src/aop.xml
index 4880569f..83234c43 100644
--- a/doc/reference/src/aop.xml
+++ b/doc/reference/src/aop.xml
@@ -1,8 +1,25 @@
-
+
+Aspect Oriented Programming with Spring.NET
-
+ IntroductionAspect-Oriented Programming
@@ -46,7 +63,7 @@
exploring how to use Spring's AOP functionality, head on over to .
-
+ AOP conceptsLet us begin by defining some central AOP concepts. These terms
@@ -88,7 +105,7 @@
Introduction: Adding methods or fields to
an advised class. Spring.NET allows you to introduce new interfaces
to any advised object. For example, you could use an introduction to
- make any object implement an IAuditable
+ make any object implement an IAuditable
interface, to simplify the tracking of changes to an object's
state.
@@ -155,7 +172,7 @@
accomplish the same thing. Using the most specific advice type provides
a simpler programming model with less potential for errors. For example,
you don't need to invoke the proceed() method on the
- IMethodInvocation used for around advice, and
+ IMethodInvocation used for around advice, and
hence can't fail to invoke it.The pointcut concept is the key to AOP, distinguishing AOP from
@@ -166,7 +183,7 @@
structural element of AOP.
-
+ Spring.NET AOP capabilitiesSpring.NET AOP is implemented in pure C#. There is no need for a
@@ -189,21 +206,21 @@
pointcut targeting it to specific joinpoints.Different advice types are
- IMethodInterceptor (from the AOP Alliance
+ IMethodInterceptor (from the AOP Alliance
interception API); and the advice interfaces defined in the
Spring.Aop namespace. All advices must implement the
- AopAlliance.Aop.IAdvice tag interface. Advices
- supported out the box are IMethodInterceptor ;
- IThrowsAdvice;
- IBeforeAdvice; and
- IAfterReturningAdvice. We'll discuss advice types
+ AopAlliance.Aop.IAdvice tag interface. Advices
+ supported out the box are IMethodInterceptor ;
+ IThrowsAdvice;
+ IBeforeAdvice; and
+ IAfterReturningAdvice. We'll discuss advice types
in detail below.Spring.NET provides a .NET translation of the Java interfaces
defined by the AOP Alliance. Around advice must implement
the AOP Alliance
- AopAlliance.Interceptr.IMethodInterceptor
+ AopAlliance.Interceptr.IMethodInterceptor
interface. Whilst there is wide support for the AOP Alliance in Java,
Spring.NET is currently the only .NET AOP framework that makes use of
these interfaces. In the short term, this will provide a consistent
@@ -223,7 +240,7 @@
managed by Spring.NET IoC.
-
+ AOP Proxies in Spring.NETSpring.NET generates AOP proxies at runtime using classes from the
@@ -272,49 +289,49 @@
-
+ Pointcut API in Spring.NETLet's look at how Spring.NET handles the crucial pointcut
concept.
-
+ ConceptsSpring.NET's pointcut model enables pointcut reuse independent of
advice types. It's possible to target different advice using the same
pointcut.
- The Spring.Aop.IPointcut interface is the
+ The Spring.Aop.IPointcut interface is the
central interface, used to target advices to particular types and
methods. The complete interface is shown below:
- public interface IPointcut
+ public interface IPointcut
{
ITypeFilter TypeFilter { get; }
IMethodMatcher MethodMatcher { get; }
}
- Splitting the IPointcut interface into two
+ Splitting the IPointcut interface into two
parts allows reuse of type and method matching parts, and fine-grained
composition operations (such as performing a "union" with another method
matcher).
- The ITypeFilter interface is used to
+ The ITypeFilter interface is used to
restrict the pointcut to a given set of target classes. If the
Matches() method always returns true, all target
types will be matched:
- public interface ITypeFilter
+ public interface ITypeFilter
{
bool Matches(Type type);
}
- The IMethodMatcher interface is normally
+ The IMethodMatcher interface is normally
more important. The complete interface is shown below:
- public interface IMethodMatcher
+ public interface IMethodMatcher
{
bool IsRuntime { get; }
@@ -329,7 +346,7 @@
avoid the need for a test on every method invocation. If the 2-argument
matches method returns true for a given method, and the
IsRuntime property for the
- IMethodMatcher returns true, the 3-argument
+ IMethodMatcher returns true, the 3-argument
matches method will be invoked on every method invocation. This enables
a pointcut to look at the arguments passed to the method invocation
immediately before the target advice is to execute.
@@ -344,7 +361,7 @@
AOP proxy is created.
-
+ Operations on pointcutsSpring.NET supports operations on pointcuts: notably,
@@ -362,14 +379,14 @@
namespace.
-
+ Convenience pointcut implementationsSpring.NET provides several convenient pointcut implementations.
Some can be used out of the box; others are intended to be subclassed in
application-specific pointcuts.
-
+ Static pointcutsStatic pointcuts are based on method and target class, and
@@ -382,7 +399,7 @@
Let's consider some static pointcut implementations included
with Spring.NET.
-
+ Regular expression pointcuts
@@ -392,7 +409,7 @@
One obvious way to specify static pointcuts is using regular
expressions. Several AOP frameworks besides Spring.NET make this
possible. The
- Spring.Aop.Support.SdkRegularExpressionMethodPointcut
+ Spring.Aop.Support.SdkRegularExpressionMethodPointcut
class is a generic regular expression pointcut, that uses the
regular expression classes from the .NET BCL.
@@ -411,7 +428,7 @@
- <object id="settersAndAbsquatulatePointcut"
+ <object id="settersAndAbsquatulatePointcut"
type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop">
<property name="patterns">
<list>
@@ -424,17 +441,17 @@
As a convenience, Spring provides the
- RegularExpressionMethodPointcutAdvisor class
- that allows us to reference an IAdvice
+ RegularExpressionMethodPointcutAdvisor class
+ that allows us to reference an IAdvice
instance as well as defining the pointcut rules (remember that an
- IAdvice instance can be an interceptor,
+ IAdvice instance can be an interceptor,
before advice, throws advice etc.) This simplifies wiring, as the
one object serves as both pointcut and advisor, as shown
below:
- <object id="settersAndAbsquatulateAdvisor"
+ <object id="settersAndAbsquatulateAdvisor"
type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
<property name="advice">
<ref local="objectNameOfAopAllianceInterceptor"/>
@@ -450,8 +467,8 @@
The
- RegularExpressionMethodPointcutAdvisor class
- can be used with any Advice type.
+ RegularExpressionMethodPointcutAdvisor class
+ can be used with any Advice type.
If you only have one pattern you can use the property name
@@ -463,16 +480,16 @@
and specifying a list.
- You may also specify a Regex object
+ You may also specify a Regex object
from the System.Text.RegularExpressions
- namespace. The built in RegexConverter class
+ namespace. The built in RegexConverter class
will perform the conversion. See for more information
on Spring's build in type converters. The Regex object is created as
any other object within the IoC container. Using an inner-object
definition for the Regex object is a handy way to keep the
definition close to the PointcutAdvisor declaration. Note that the
- class SdkRegularExpressionMethodPointcut has
+ class SdkRegularExpressionMethodPointcut has
a DefaultOptions property to set the
regular expression options if they are not explicitly specified in
the constructor.
@@ -480,24 +497,24 @@
-
+ Attribute pointcutsPointcuts can be specified by matching an attribute type that
is associated with a method. Advice associated with this pointcut
can then read the metadata associated with the attribute to
configure itself. The class
- AttributeMatchMethodPointcut provides this
+ AttributeMatchMethodPointcut provides this
functionality. Sample usage that will match all methods that have
the attribute
- Spring.Attributes.CacheAttribute is shown
- below. <object id="cachePointcut" type="Spring.Aop.Support.AttributeMatchMethodPointcut, Spring.Aop">
+ Spring.Attributes.CacheAttribute is shown
+ below. <object id="cachePointcut" type="Spring.Aop.Support.AttributeMatchMethodPointcut, Spring.Aop">
<property name="Attribute" value="Spring.Attributes.CacheAttribute, Spring.Core"/>
</object>This can be used with a
- DefaultPointcutAdvisor as shown
- below<object id="cacheAspect" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
+ DefaultPointcutAdvisor as shown
+ below<object id="cacheAspect" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
<property name="Pointcut">
<object type="Spring.Aop.Support.AttributeMatchMethodPointcut, Spring.Aop">
<property name="Attribute" value="Spring.Attributes.CacheAttribute, Spring.Core"/>
@@ -505,16 +522,16 @@
</property>
<property name="Advice" ref="aspNetCacheAdvice"/>
</object> where aspNetCacheAdvice is an implementation
- of an IMethodInterceptor that caches method
+ of an IMethodInterceptor that caches method
return values. See the SDK docs for
- Spring.Aop.Advice.CacheAdvice for more
+ Spring.Aop.Advice.CacheAdvice for more
information on this particular advice.As a convenience the class
- AttributeMatchMethodPointcutAdvisor is
+ AttributeMatchMethodPointcutAdvisor is
provided to defining an attribute based Advisor as a somewhat
shorter alternative to using the generic DefaultPointcutAdvisor. An
- example is shown below.<object id="AspNetCacheAdvice" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
+ example is shown below.<object id="AspNetCacheAdvice" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
<property name="advice">
<object type="Aspect.AspNetCacheAdvice, Aspect"/>
</property>
@@ -523,7 +540,7 @@
-
+ Dynamic PointcutsDynamic pointcuts are costlier to evaluate than static
@@ -590,7 +607,7 @@
it will not match a control flow pointcut for the method
"GetAge".
- public int GetAge(IPerson person)
+ public int GetAge(IPerson person)
{
return person.GetAge();
}
@@ -598,7 +615,7 @@
However, applying the attributes as shown below will prevent
the method from being inlined even in a release build.
- [MethodImpl(MethodImplOptions.NoInlining)]
+ [MethodImpl(MethodImplOptions.NoInlining)]
public int GetAge(IPerson person)
{
return person.GetAge();
@@ -622,11 +639,11 @@ public int GetAge(IPerson person)
Because static pointcuts are the most common and generally useful
pointcut type, you'll probably subclass
- StaticMethodMatcherPointcut, as shown below. This
+ StaticMethodMatcherPointcut, as shown below. This
requires you to implement just one abstract method (although it is
possible to override other methods to customize behaviour):
- public class TestStaticPointcut : StaticMethodMatcherPointcut {
+ public class TestStaticPointcut : StaticMethodMatcherPointcut {
public override bool Matches(MethodInfo method, Type targetType) {
// return true if custom criteria match
@@ -635,12 +652,12 @@ public int GetAge(IPerson person)
-
+ Advice API in Spring.NETLet's now look at how Spring.NET AOP handles advice.
-
+ Advice LifecycleSpring.NET advices can be shared across all advised objects, or
@@ -661,7 +678,7 @@ public int GetAge(IPerson person)
the same AOP proxy.
-
+ Advice typesSpring.NET provides several advice types out of the box, and is
@@ -678,7 +695,7 @@ public int GetAge(IPerson person)
around advice using method interception. Around advice is implemented
using the following interface:
- public interface IMethodInterceptor : IInterceptor
+ public interface IMethodInterceptor : IInterceptor
{
object Invoke(IMethodInvocation invocation);
}
@@ -692,7 +709,7 @@ public int GetAge(IPerson person)
A simple IMethodInterceptor implementation
looks as follows:
- public class DebugInterceptor : IMethodInterceptor {
+ public class DebugInterceptor : IMethodInterceptor {
public object Invoke(IMethodInvocation invocation) {
Console.WriteLine("Before: invocation=[{0}]", invocation);
@@ -725,10 +742,10 @@ public int GetAge(IPerson person)
possibility of inadvertently failing to proceed down the interceptor
chain.
- The IMethodBeforeAdvice interface is
+ The IMethodBeforeAdvice interface is
shown below.
- public interface IMethodBeforeAdvice : IBeforeAdvice
+ public interface IMethodBeforeAdvice : IBeforeAdvice
{
void Before(MethodInfo method, object[] args, object target);
}
@@ -745,7 +762,7 @@ public int GetAge(IPerson person)
An example of a before advice in Spring.NET, which counts all
methods that return normally:
- public class CountingBeforeAdvice : IMethodBeforeAdvice {
+ public class CountingBeforeAdvice : IMethodBeforeAdvice {
private int count;
@@ -761,7 +778,7 @@ public int GetAge(IPerson person)
Before advice can be used with any pointcut.
-
+ Throws adviceThrows advice is invoked after the return of the joinpoint if
@@ -771,7 +788,7 @@ public int GetAge(IPerson person)
advice object implements one or more typed throws advice methods.
These throws advice methods must be of the form:
- AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass)
+ AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass)Throws-advice methods must be named
'AfterThrowing'. The return value will be ignored
@@ -786,10 +803,10 @@ public int GetAge(IPerson person)
advice.This advice will be invoked if a
- RemotingException is thrown (including
+ RemotingException is thrown (including
subclasses):
- public class RemoteThrowsAdvice : IThrowsAdvice {
+ public class RemoteThrowsAdvice : IThrowsAdvice {
public void AfterThrowing(RemotingException ex) {
// Do something with remoting exception
@@ -797,11 +814,11 @@ public int GetAge(IPerson person)
}The following advice is invoked if a
- SqlException is thrown. Unlike the above
+ SqlException is thrown. Unlike the above
advice, it declares 4 arguments, so that it has access to the invoked
method, method arguments and target object:
- public class SqlExceptionThrowsAdviceWithArguments : IThrowsAdvice {
+ public class SqlExceptionThrowsAdviceWithArguments : IThrowsAdvice {
public void AfterThrowing(MethodInfo method, object[] args, object target, SqlException ex) {
// Do something will all arguments
@@ -810,12 +827,12 @@ public int GetAge(IPerson person)
The final example illustrates how these two methods could be
used in a single class, which handles both
- RemotingException and
- SqlException. Any number of throws advice
+ RemotingException and
+ SqlException. Any number of throws advice
methods can be combined in a single class, as can be seen in the
following example.
- public class CombinedThrowsAdvice : IThrowsAdvice {
+ public class CombinedThrowsAdvice : IThrowsAdvice {
public void AfterThrowing(RemotingException ex) {
// Do something with remoting exception
@@ -829,30 +846,30 @@ public int GetAge(IPerson person)
Finally, it is worth stating that throws advice is only applied
to the actual exception being thrown. What does this mean? Well, it
means that if you have defined some throws advice that handles
- RemotingExceptions, the applicable
+ RemotingExceptions, the applicable
AfterThrowing method will only be invoked if the type of the thrown
- exception is RemotingException... if a
- RemotingException has been thrown and
+ exception is RemotingException... if a
+ RemotingException has been thrown and
subsequently wrapped inside another exception before the exception
bubbles up to the throws advice interceptor, then the throws advice
- that handles RemotingExceptions will RemotingExceptions will never be called. Consider a business method
that is advised by throws advice that handles
- RemotingExceptions; if during the course of a
+ RemotingExceptions; if during the course of a
method invocation said business method throws a RemoteException... and
- subsequently wraps said RemotingException
+ subsequently wraps said RemotingException
inside a business-specific
- BadConnectionException (see the code snippet
+ BadConnectionException (see the code snippet
below) before throwing the exception, then the throws advice will
never be able to respond to the
- RemotingException... because all the throws
- advice sees is a BadConnectionException. The
- fact that the RemotingException is wrapped up
- inside the BadConnectionException is
+ RemotingException... because all the throws
+ advice sees is a BadConnectionException. The
+ fact that the RemotingException is wrapped up
+ inside the BadConnectionException is
immaterial.
- public void BusinessMethod()
+ public void BusinessMethod()
{
try
{
@@ -873,10 +890,10 @@ public int GetAge(IPerson person)
After Returning adviceAn after returning advice in Spring.NET must implement the
- Spring.Aop.IAfterReturningAdvice interface,
+ Spring.Aop.IAfterReturningAdvice interface,
shown below:
- public interface IAfterReturningAdvice : IAdvice
+ public interface IAfterReturningAdvice : IAdvice
{
void AfterReturning(object returnValue, MethodBase method, object[] args, object target);
}
@@ -888,7 +905,7 @@ public int GetAge(IPerson person)
The following after returning advice counts all successful
method invocations that have not thrown exceptions:
- public class CountingAfterReturningAdvice : IAfterReturningAdvice {
+ public class CountingAfterReturningAdvice : IAfterReturningAdvice {
private int count;
public void AfterReturning(object returnValue, MethodBase m, object[] args, object target) {
@@ -909,7 +926,7 @@ public int GetAge(IPerson person)
-
+ Advice OrderingWhen multiple pieces of advice want to run on the same joinpoint
@@ -937,14 +954,14 @@ public int GetAge(IPerson person)
Introduction advice is defined by using a normal interface
declaration that implements the tag interface
- IAdvice. The need for implementing this
+ IAdvice. The need for implementing this
marker interface will likely be removed in future versions. As
- an example, consider the interface IAuditable
+ an example, consider the interface IAuditable
that describes the last modified time of an object.
- public interface IAuditable : IAdvice
+ public interface IAuditable : IAdvice
{
DateTime LastModifiedDate
{
@@ -955,22 +972,22 @@ public int GetAge(IPerson person)
where
- public interface IAdvice
+ public interface IAdvice
{
}Access to the advised object can be obtained by implementing the
- interface ITargetAwarepublic interface ITargetAware
+ interface ITargetAwarepublic interface ITargetAware
{
IAopProxy TargetProxy
{
set;
}
-} with the IAopProxy reference
+} with the IAopProxy reference
providing a layer of indirection through which the advised object can
- be accessed. public interface IAopProxy
+ be accessed. public interface IAopProxy
{
object GetProxy();
}
@@ -978,7 +995,7 @@ public int GetAge(IPerson person)
A simple class that demonstrates this functionality is shown
- below. public interface IAuditable : IAdvice, ITargetAware
+ below. public interface IAuditable : IAdvice, ITargetAware
{
DateTime LastModifiedDate
{
@@ -993,7 +1010,7 @@ public int GetAge(IPerson person)
- public class AuditableMixin : IAuditable
+ public class AuditableMixin : IAuditable
{
private DateTime date;
private IAopProxy targetProxy;
@@ -1020,13 +1037,13 @@ public int GetAge(IPerson person)
Introduction advice is not associated with a pointcut, since it
applies at the class and not the method level. As such, introductions
use their own subclass of the interface
- IAdvisor, namely
- IIntroductionAdvisor, to specify the types that
+ IAdvisor, namely
+ IIntroductionAdvisor, to specify the types that
the introduction can be applied to.
- public interface IIntroductionAdvisor : IAdvisor
+ public interface IIntroductionAdvisor : IAdvisor
{
ITypeFilter TypeFilter { get; }
@@ -1055,7 +1072,7 @@ public int GetAge(IPerson person)
Spring.NET provides a default implementation of this interface
- (the DefaultIntroductionAdvisor class) that
+ (the DefaultIntroductionAdvisor class) that
should be sufficient for the majority of situations when you need to
use introductions. The most simple implementation of an introduction
advisor is a subclass that simply passes a new instance the base
@@ -1064,7 +1081,7 @@ public int GetAge(IPerson person)
- public class AuditableAdvisor : DefaultIntroductionAdvisor
+ public class AuditableAdvisor : DefaultIntroductionAdvisor
{
public AuditableAdvisor() : base(new AuditableMixin())
{
@@ -1083,7 +1100,7 @@ public int GetAge(IPerson person)
IAdvised.AddIntroduction(), method, or (the
recommended way) in XML configuration using the
IntroductionNames property on
- ProxyFactoryObject, which will be discussed
+ ProxyFactoryObject, which will be discussed
later.
@@ -1108,7 +1125,7 @@ public int GetAge(IPerson person)
-
+ Advisor API in Spring.NETIn Spring.NET, an advisor is a modularization of an aspect. Advisors
@@ -1116,17 +1133,17 @@ public int GetAge(IPerson person)
Apart from the special case of introductions, any advisor can be
used with any advice. The
- Spring.Aop.Support.DefaultPointcutAdvisor class is
+ Spring.Aop.Support.DefaultPointcutAdvisor class is
the most commonly used advisor implementation. For example, it can be used
- with a IMethodInterceptor,
- IBeforeAdvice or
- IThrowsAdvice and any pointcut definition.
+ with a IMethodInterceptor,
+ IBeforeAdvice or
+ IThrowsAdvice and any pointcut definition.Other convenience implementations provided are:
- AttributeMatchMethodPointcutAdvisor shown in usage
+ AttributeMatchMethodPointcutAdvisor shown in usage
previously in for use with
attribute based pointcuts.
- RegularExpressionMethodPointcutAdvisor that will
+ RegularExpressionMethodPointcutAdvisor that will
apply pointcuts based on the matching a regular expression to method
names.
@@ -1136,39 +1153,39 @@ public int GetAge(IPerson person)
will automatically create the necessary interceptor chain.
-
- Using the ProxyFactoryObject to create
+
+ Using the ProxyFactoryObject to create
AOP proxiesIf you're using the Spring.NET IoC container for your business
objects - generally a good idea - you will want to use one of Spring.NET's
- AOP-specific IFactoryObject implementations
+ AOP-specific IFactoryObject implementations
(remember that a factory object introduces a layer of indirection,
enabling it to create objects of a different type - ).The basic way to create an AOP proxy in Spring.NET is to use the
- Spring.Aop.Framework.ProxyFactoryObject class. This
+ Spring.Aop.Framework.ProxyFactoryObject class. This
gives complete control over ordering and application of the pointcuts and
advice that will apply to your business objects. However, there are
simpler options that are preferable if you don't need such control.
-
+ Basics
- The ProxyFactoryObject, like other
- Spring.NET IFactoryObject implementations,
+ The ProxyFactoryObject, like other
+ Spring.NET IFactoryObject implementations,
introduces a level of indirection. If you define a
- ProxyFactoryObject with name
+ ProxyFactoryObject with name
foo, what objects referencing foo
- see is not the ProxyFactoryObject instance
+ see is not the ProxyFactoryObject instance
itself, but an object created by the
- ProxyFactoryObject's implementation of the
+ ProxyFactoryObject's implementation of the
GetObject() method. This method will create an AOP
proxy wrapping a target object.One of the most important benefits of using a
- ProxyFactoryObject or other IoC-aware classes
+ ProxyFactoryObject or other IoC-aware classes
that create AOP proxies, is that it means that advice and pointcuts can
also be managed by IoC. This is a powerful feature, enabling certain
approaches that are hard to achieve with other AOP frameworks. For
@@ -1177,11 +1194,11 @@ public int GetAge(IPerson person)
all the pluggability provided by Dependency Injection.
-
+ ProxyFactoryObject Properties
- Like most IFactoryObject implementations
- provided with Spring.NET, the ProxyFactoryObject
+ Like most IFactoryObject implementations
+ provided with Spring.NET, the ProxyFactoryObject
is itself a Spring.NET configurable object. Its properties are used
to:
@@ -1196,7 +1213,7 @@ public int GetAge(IPerson person)
Some key properties are inherited from the
- Spring.Aop.Framework.ProxyConfig class: this
+ Spring.Aop.Framework.ProxyConfig class: this
class is the superclass for all AOP proxy factories in Spring.NET. Some
of the key properties include:
@@ -1247,7 +1264,7 @@ public int GetAge(IPerson person)
Other properties specific to the
- ProxyFactoryObject class include:
+ ProxyFactoryObject class include:
@@ -1266,7 +1283,7 @@ public int GetAge(IPerson person)
The names are object names in the current container, including
objectnames from container hierarchies. You can't mention object
references here since doing so would result in the
- ProxyFactoryObject ignoring the singleton
+ ProxyFactoryObject ignoring the singleton
setting of the advise.
@@ -1301,7 +1318,7 @@ public int GetAge(IPerson person)
-
+ Proxying InterfacesLet's look at a simple example of
@@ -1324,7 +1341,7 @@ public int GetAge(IPerson person)
- <object id="personTarget" type="MyCompany.MyApp.Person, MyCompany">
+ <object id="personTarget" type="MyCompany.MyApp.Person, MyCompany">
<property name="name" value="Tony"/>
<property name="age" value="51"/>
</object>
@@ -1369,13 +1386,13 @@ public int GetAge(IPerson person)
The "person" object definition above can be used in place of an
IPerson implementation, as follows:
- IPerson person = (IPerson) factory.GetObject("person");
+ IPerson person = (IPerson) factory.GetObject("person");Other objects in the same IoC context can express a strongly typed
dependency on it, as with an ordinary .NET object:
- <object id="personUser" type="MyCompany.MyApp.PersonUser, MyCompany">
+ <object id="personUser" type="MyCompany.MyApp.PersonUser, MyCompany">
<property name="person" ref="person"/>
</object>
@@ -1394,7 +1411,7 @@ public int GetAge(IPerson person)
ProxyFactoryObject definition is different; the
advice is included only for completeness:
- <object id="myCustomInterceptor" type="MyCompany.MyApp.MyCustomInterceptor, MyCompany">
+ <object id="myCustomInterceptor" type="MyCompany.MyApp.MyCustomInterceptor, MyCompany">
<property name="customProperty" value="configuration string"/>
</object>
@@ -1439,31 +1456,37 @@ public int GetAge(IPerson person)
Let's look at an example of configuring the proxy objects
retrieved from ProxyFactoryObject.
-
-<!-- create the object to reference -->
-<object id="RealObjectTarget" type="MyRealObject" singleton="false"/>
-<!-- create the proxied object for everyone to use-->
-<object id="MyObject" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
- <property name="proxyInterfaces" value="MyInterface" />
- <property name="isSingleton" value="false"/>
- <property name="targetName" value="RealObjectTarget" />
-</object>
- If you are using a prototype as the target you must set the
- TargetName property with the name/object id of your
- object and not use the property Target with a
- reference to that object. This will then allow a new proxy to be created
- around a new prototype target instance. Consider the above
- Spring.Net object configuration. Notice that the
- IsSingleton property of the
- ProxyFactoryObject instance is set to false. This
- means that each proxy object will be unique. Thus, you can configure
- each proxy object with its' own individual advice(s) using the following
- syntax MyInterface myProxyObject1 = (MyInterface)ctx.GetObject("MyObject"); // Will return un-advised instance of proxy object
+
+
+ <!-- create the object to reference -->
+ <object id="RealObjectTarget" type="MyRealObject" singleton="false"/>
+ <!-- create the proxied object for everyone to use-->
+ <object id="MyObject" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
+ <property name="proxyInterfaces" value="MyInterface" />
+ <property name="isSingleton" value="false"/>
+ <property name="targetName" value="RealObjectTarget" />
+ </object>
+ If you are using a prototype as the target you must set the
+ TargetName property with the name/object id of your
+ object and not use the property Target with a
+ reference to that object. This will then allow a new proxy to be created
+ around a new prototype target instance.
+
+
+ Consider the above Spring.Net object configuration. Notice that the
+ IsSingleton property of the ProxyFactoryObject
+ instance is set to false. This means that each proxy object will be unique.
+ Thus, you can configure each proxy object with its' own individual advice(s)
+ using the following syntax
+// Will return un-advised instance of proxy object
+MyInterface myProxyObject1 = (MyInterface)ctx.GetObject("MyObject");
+// myProxyObject1 instance now has an advice attached to it.
IAdvised advised = (IAdvised)myProxyObject1;
-advised.AddAdvice( new DebugAdvice() ); // myProxyObject1 instance now has an advice attached to it.
+advised.AddAdvice( new DebugAdvice() );
-MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will return a new, un-advised instance of proxy object
+// Will return a new, un-advised instance of proxy object
+MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject");
@@ -1510,7 +1533,7 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
First a parent, template, object definition is created for the
proxy:
- <object id="txProxyTemplate" abstract="true"
+ <object id="txProxyTemplate" abstract="true"
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
<property name="PlatformTransactionManager" ref="adoTransactionManager"/>
@@ -1527,7 +1550,7 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
object definition, since the target will never be used on its own
anyway.
- <object name="testObjectManager" parent="txProxyTemplate">
+ <object name="testObjectManager" parent="txProxyTemplate">
<property name="Target">
<object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
<property name="TestObjectDao" ref="testObjectDao"/>
@@ -1539,7 +1562,7 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
template, such as in this case, the transaction propagation
settings:
- <object name="testObjectManager" parent="txProxyTemplate">
+ <object name="testObjectManager" parent="txProxyTemplate">
<property name="Target">
<object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
<property name="TestObjectDao" ref="testObjectDao"/>
@@ -1567,7 +1590,7 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
-
+ Proxying mechanismsSpring creates AOP proxies built at runtime through the use of the
@@ -1590,9 +1613,9 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
if needed. Please note that in both cases a target method implementation
that calls other methods on the target object will not be advised. To
force inheritance based proxies you should either set the
- ProxyTargetType to true property of a ProxyFactory
- or set the XML namespace element proxy-target-type =
- true when using an AOP schema based configuration.
+ ProxyTargetType to true property of a ProxyFactory
+ or set the XML namespace element proxy-target-type =
+ true when using an AOP schema based configuration.
An important alternative approach to inheritance based proxies is
@@ -1607,7 +1630,7 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
InternalsVisibleTo("Spring.DynamicReflection")] to your to AssemblyInfo
file.
-
+ InheritanceBasedAopConfigurerThere is an important limitation in the inheritance based proxy as
@@ -1625,7 +1648,7 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
IObjectFactoryPostProcessor, in yoru configuraiton file. Here is an
example.
- <object type="Spring.Aop.Framework.AutoProxy.InheritanceBasedAopConfigurer, Spring.Aop">
+ <object type="Spring.Aop.Framework.AutoProxy.InheritanceBasedAopConfigurer, Spring.Aop">
<property name="ObjectNames">
<list>
<value>Form*</value>
@@ -1648,7 +1671,7 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
-
+ Creating AOP Proxies Programatically with the ProxyFactoryIt's easy to create AOP proxies Programatically using Spring.NET.
@@ -1659,7 +1682,7 @@ MyInterface myProxyObject2 = (MyInterface)ctx.GetObject("MyObject"); // Will ret
with one interceptor and one advisor. The interfaces implemented by the
target object will automatically be proxied:
- ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
+ ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
factory.AddAdvice(myMethodInterceptor);
factory.AddAdvisor(myAdvisor);
IBusinessInterface tb = (IBusinessInterface) factory.GetProxy();
@@ -1684,7 +1707,7 @@ IBusinessInterface tb = (IBusinessInterface) factory.GetProxy();
-
+ Manipulating Advised ObjectsHowever you create AOP proxies, you can manipulate them using the
@@ -1692,7 +1715,7 @@ IBusinessInterface tb = (IBusinessInterface) factory.GetProxy();
- public interface IAdvised
+ public interface IAdvised
{
IAdvisor[] Advisors { get; }
@@ -1773,7 +1796,7 @@ IBusinessInterface tb = (IBusinessInterface) factory.GetProxy();
-
+ Using the "autoproxy" facilitySo far we've considered explicit creation of AOP proxies using a
@@ -1815,7 +1838,7 @@ IBusinessInterface tb = (IBusinessInterface) factory.GetProxy(); also offers this
benefit.)
-
+ Autoproxy object definitionsThe namespace Spring.Aop.Framework.AutoProxy
@@ -1826,7 +1849,7 @@ IBusinessInterface tb = (IBusinessInterface) factory.GetProxy();DefaultAdvisorAutoProxyCreator. These are discussed
in the following sections.
-
+ ObjectNameAutoProxyCreatorThe ObjectNameAutoProxyCreator automatically
@@ -1836,7 +1859,7 @@ IBusinessInterface tb = (IBusinessInterface) factory.GetProxy();
- public enum Language
+ public enum Language
{
English = 1,
Portuguese = 2,
@@ -1894,7 +1917,7 @@ public class DebugInterceptor : IMethodInterceptor
and apply a Debug interceptor to object definitions whose names match
"English*" and "PortugueseSpeaker".
- <object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
+ <object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
<property name="ObjectNames">
<list>
<value>English*</value>
@@ -1939,7 +1962,7 @@ public class DebugInterceptor : IMethodInterceptor
Running the following simple program demonstrates the
application of the AOP interceptor.
-
+
IApplicationContext ctx = ContextRegistry.GetContext();
IDictionary speakerDictionary = ctx.GetObjectsOfType(typeof(IHelloWorldSpeaker));
foreach (DictionaryEntry entry in speakerDictionary)
@@ -1953,7 +1976,7 @@ foreach (DictionaryEntry entry in speakerDictionary)
The output is shown below
- ItalianSpeakerOne says; Ciao Mondo!
+ ItalianSpeakerOne says; Ciao Mondo!
EnglishSpeakerTwo says; Before: Void SayHello()
Hello World!
After: Void SayHello()
@@ -1965,7 +1988,7 @@ Hello World!
After: Void SayHello()
-
+ DefaultAdvisorAutoProxyCreator
@@ -2034,7 +2057,7 @@ After: Void SayHello()
ObjectNameAutoProxyCreator we will add a new class,
SpeakerDao, that acts as a Data Access Object to
find and store IHelloWorldSpeaker objects.
-
+
public interface ISpeakerDao
{
IList FindAll();
@@ -2073,11 +2096,11 @@ public class SpeakerDao : ISpeakerDao
is used as a convenience to specify the pointcut as a regular expression that matches methods names. Other pointcuts of your own creation could be used, in which case a
- DefaultPointcutAdvisor
+ DefaultPointcutAdvisor
would be used to define the Advisor. The object definitions for these advisors, advice, and SpeakerDao object are shown below
- <object id="SpeachAdvisor" type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
+ <object id="SpeachAdvisor" type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
<property name="advice" ref="debugInterceptor"/>
<property name="patterns">
@@ -2115,7 +2138,7 @@ public class SpeakerDao : ISpeakerDao
Adding an instance of
DefaultAdvisorAutoProxyCreator to the configuration
- file <object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop"/>
+ file <object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop"/>
will apply the debug interceptor on all objects in the context that
have a method that contains the text "Say" and apply the timing
interceptor on objects in the context that have a method that contains
@@ -2125,7 +2148,7 @@ public class SpeakerDao : ISpeakerDao
-
+
IApplicationContext ctx = ContextRegistry.GetContext();
IDictionary speakerDictionary = ctx.GetObjectsOfType(typeof(IHelloWorldSpeaker));
foreach (DictionaryEntry entry in speakerDictionary)
@@ -2146,7 +2169,7 @@ IHelloWorldSpeaker speaker = dao.Save(new HelloWorldSpeaker());
-
+
ItalianSpeakerOne says; Before: Void SayHello()
Ciao Mondo!
After: Void SayHello()
@@ -2188,7 +2211,7 @@ Saving speaker...
-
+ Using attribute-driven auto-proxyingA particularly important type of autoproxying is driven by
@@ -2206,18 +2229,18 @@ Saving speaker...
Several of the aspect provided with Spring use attribute driven
autoproxying. The most prominent example is Transaction support.
+ linkend="transaction">Transaction support.
-
+ Using AOP NamespaceThe AOP namespace allows you to define an advisor, i.e pointcut + 1
piece of advice, in a more declarative manner. Under the covers the
DefaultAdvisorAutoProxyCreator is being used. Here is an example,
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.net/aop">
@@ -2256,7 +2279,7 @@ Saving speaker...
context configuration
for more extensive information..
- <configuration>
+ <configuration>
<configSections>
<sectionGroup name="spring">
@@ -2264,16 +2287,16 @@ Saving speaker...
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
- <section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
+ <section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
</sectionGroup>
</configSections>
<spring>
- <parsers>
+ <parsers>
<parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" />
- </parsers>
+ </parsers>
<context>
@@ -2290,7 +2313,7 @@ Saving speaker...
-
+ Using TargetSourcesSpring.NET offers the concept of a
@@ -2317,7 +2340,7 @@ Saving speaker...
to be a prototype rather than a singleton object definition. This allows
Spring.NET to create a new target instance when required.
-
+ Hot swappable target sourcesThe
@@ -2331,13 +2354,13 @@ Saving speaker...
You can change the target via the swap() method
on HotSwappableTargetSource as follows:
- HotSwappableTargetSource swapper =
+ HotSwappableTargetSource swapper =
(HotSwappableTargetSource) objectFactory.GetObject("swapper");
object oldTarget = swapper.swap(newTarget);The XML definitions required look as follows:
- <object id="initialTarget" type="MyCompany.OldTarget, MyCompany">
+ <object id="initialTarget" type="MyCompany.OldTarget, MyCompany">
</object>
<object id="swapper"
@@ -2364,7 +2387,7 @@ object oldTarget = swapper.swap(newTarget);
with arbitrary advice.
-
+ Pooling target sourcesUsing a pooling target source provides a programming model in
@@ -2384,7 +2407,7 @@ object oldTarget = swapper.swap(newTarget);Sample configuration is shown below:
- <object id="businessObjectTarget" type="MyCompany.MyBusinessObject, MyCompany" singleton="false">
+ <object id="businessObjectTarget" type="MyCompany.MyBusinessObject, MyCompany" singleton="false">
... properties omitted
</object>
@@ -2418,22 +2441,22 @@ object oldTarget = swapper.swap(newTarget);
size of the pool through an introduction. You'll need to define an
advisor like this:
- <object id="poolConfigAdvisor"
+ <object id="poolConfigAdvisor"
type="Spring.Object.Factory.Config.MethodInvokingFactoryObject, Spring.Aop">
<property name="target" ref="poolTargetSource" />
<property name="targetMethod" value="getPoolingConfigMixin" />
</object>This advisor is obtained by calling a convenience method on the
- AbstractPoolingTargetSource class, hence the use
- of MethodInvokingFactoryObject. This advisor's
+ AbstractPoolingTargetSource class, hence the use
+ of MethodInvokingFactoryObject. This advisor's
name ('poolConfigAdvisor' here) must be in the list
- of interceptor names in the ProxyFactoryObject
+ of interceptor names in the ProxyFactoryObject
exposing the pooled object.The cast will look as follows:
- PoolingConfig conf = (PoolingConfig) objectFactory.GetObject("businessObject");
+ PoolingConfig conf = (PoolingConfig) objectFactory.GetObject("businessObject");
Console.WriteLine("Max pool size is " + conf.getMaxSize());Pooling stateless service objects is not usually necessary. We
@@ -2445,7 +2468,7 @@ Console.WriteLine("Max pool size is " + conf.getMaxSize());
set the TargetSources used by any autoproxy creator.
-
+ Prototype target sourcesSetting up a "prototype" target source is similar to a pooling
@@ -2459,7 +2482,7 @@ Console.WriteLine("Max pool size is " + conf.getMaxSize());poolTargetSource definition shown above as follows.
(the name of the definition has also been changed, for clarity.)
- <object id="prototypeTargetSource"
+ <object id="prototypeTargetSource"
type="Spring.Aop.Target.PrototypeTargetSource, Spring.Aop">
<property name="targetObjectName" value="businessObject" />
</object>
@@ -2480,14 +2503,14 @@ Console.WriteLine("Max pool size is " + conf.getMaxSize());
alongside a thread. Setting up a ThreadLocalTargetSource is pretty much
the same as was explained for the other types of target source:
- <object id="threadlocalTargetSource"
+ <object id="threadlocalTargetSource"
type="Spring.Aop.Target.ThreadLocalTargetSource, Spring.Aop">
<property name="targetObjectName" value="businessObject" />
</object>
-
+ Defining new Advice typesSpring.NET AOP is designed to be extensible. While the interception
@@ -2500,13 +2523,13 @@ Console.WriteLine("Max pool size is " + conf.getMaxSize());
SPI (Service Provider Interface) package allowing support for new custom
advice types to be added without changing the core framework. The only
constraint on a custom Advice type is that it must implement the
- AopAlliance.Aop.IAdvice tag interface.
+ AopAlliance.Aop.IAdvice tag interface.
Please refer to the Spring.Aop.Framework.Adapter
namespace documentation for further information.
-
+ Further reading and resourcesThe Spring.NET team recommends the excellent AspectJ in
diff --git a/doc/reference/src/background.xml b/doc/reference/src/background.xml
index c401cab5..028bf0ae 100644
--- a/doc/reference/src/background.xml
+++ b/doc/reference/src/background.xml
@@ -1,8 +1,25 @@
-
+
+Background information
-
+ Inversion of ControlIn early 2004, Martin Fowler asked the readers of his site: when
diff --git a/doc/reference/src/dao.xml b/doc/reference/src/dao.xml
index 30d7ad00..5a2c5a57 100644
--- a/doc/reference/src/dao.xml
+++ b/doc/reference/src/dao.xml
@@ -1,8 +1,25 @@
-
+
+DAO support
-
+ IntroductionSpring promotes the use of data access interfaces in your
@@ -35,17 +52,17 @@
catching exceptions that are specific to each technology.
-
+ Consistent exception hierarchyDatabase exceptions in the ADO.NET API are not consistent across
providers. The .NET 1.1 BCL did not provide a common base class for
ADO.NET exceptions. As such you were required to handle exceptions
specific to each provider such as
- System.Data.SqlClient.SqlException or
- System.Data.OracleClient.OracleException. The .NET
+ System.Data.SqlClient.SqlException or
+ System.Data.OracleClient.OracleException. The .NET
2.0 BCL improved in this regard by introducing a common base class for
- exceptions, System.Data.Common.DbException. However
+ exceptions, System.Data.Common.DbException. However
the common DbException is not very portable either as it provides a vendor
specific error code as the underlying piece of information as to what went
wrong. This error code is different across providers for the same
@@ -54,10 +71,10 @@
To promote writing portable and descriptive exception handling code
Spring provides a convenient translation from technology specific
- exceptions like System.Data.SqlClient.SqlException
- or System.Data.OracleClient.OracleException to its
+ exceptions like System.Data.SqlClient.SqlException
+ or System.Data.OracleClient.OracleException to its
own exception hierarchy with the
- Spring.Dao.DataAccessException as the root
+ Spring.Dao.DataAccessException as the root
exception. These exceptions wrap the original exception so there is never
any risk that one might lose any information as to what might have gone
wrong.
@@ -83,13 +100,13 @@
(Please note that the class hierarchy detailed in the above image
shows only a subset of the whole, rich,
- DataAccessException hierarchy.)
+ DataAccessException hierarchy.)The exception translation functionality is in the namespace
Spring.Data.Support and is based on the interface
IAdoExceptionTranslator shown below.
- public interface IAdoExceptionTranslator
+ public interface IAdoExceptionTranslator
{
DataAccessException Translate( string task, string sql, Exception exception );
}
@@ -131,7 +148,7 @@
codes that map to a
DataIntegrityViolationException.
- <objects xmlns='http://www.springframework.net'>
+ <objects xmlns='http://www.springframework.net'>
<alias name='SqlServer-2.0' alias='SqlServer2005'/>
@@ -153,7 +170,7 @@
periods in the name is a workaround.Another way to customize the mappings of error codes to exceptions
- is to subclass ErrorCodeExceptionTranslator and
+ is to subclass ErrorCodeExceptionTranslator and
override the method, DataAccessException
TranslateException(string task, string sql, string errorCode, Exception
exception). This will be called before referencing the metadata
@@ -297,26 +314,26 @@
- AdoDaoSupport - super class for ADO.NET
+ AdoDaoSupport - super class for ADO.NET
data access objects. Requires a
- DbProvider to be provided; in turn,
- this class provides a AdoTemplate instance
+ DbProvider to be provided; in turn,
+ this class provides a AdoTemplate instance
initialized from the supplied
- DbProvider to subclasses. See the
+ DbProvider to subclasses. See the
documentation for AdoTemplate for more
information.
- HibernateDaoSupport - super class for
+ HibernateDaoSupport - super class for
NHibernate data access objects. Requires a
- ISessionFactory to be provided; in
- turn, this class provides a HibernateTemplate
+ ISessionFactory to be provided; in
+ turn, this class provides a HibernateTemplate
instance initialized from the supplied
- SessionFactory to subclasses. Can
+ SessionFactory to subclasses. Can
alternatively be initialized directly via a
- HibernateTemplate, to reuse the latter's
- settings like SessionFactory, flush
+ HibernateTemplate, to reuse the latter's
+ settings like SessionFactory, flush
mode, exception translator, etc. This is contained in a download
separate from the main Spring.NET distribution.
diff --git a/doc/reference/src/data-quickstart.xml b/doc/reference/src/data-quickstart.xml
index 4395c959..be95892a 100644
--- a/doc/reference/src/data-quickstart.xml
+++ b/doc/reference/src/data-quickstart.xml
@@ -1,5 +1,22 @@
-
+
+Data Access QuickStart
@@ -14,40 +31,39 @@
The quick start contains pseudo DAO objects and a collection of
NUnit tests to exercise them rather than a full blown application. To run
the tests from within VS.NET install TestDriven.NET, TestDriven.NET, ReSharper, or an
equivalent . The listing of DAO classes and the parts of Spring.Data that
they demonstrate is shown below.
- CommandCallbackDao - Use of the
+ CommandCallbackDao - Use of the
ICommandCallback and CommandCallbackDelegate
- ResultSetExtractorDao - Use of
+ ResultSetExtractorDao - Use of
IResultSetExtractor and ResultSetExtractorDelegate
- RowCallbackDao - Use of IRowCallback and
+ RowCallbackDao - Use of IRowCallback and
RowCallbackDelegate
- RowMapperDao - Use of IRowMapper and
+ RowMapperDao - Use of IRowMapper and
RowMapperDelegate
- QueryForObject - Use of QueryForObject
+ QueryForObject - Use of QueryForObject
method.
- StoredProcDao - Use of
+ StoredProcDao - Use of
Spring.Data.Objects.StoredProcedure
@@ -63,7 +79,7 @@
database connection string. The listing in
DataQuickStart.GenericTemplate.ExampleTests.xml is shown below
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:db="http://www.springframework.net/database">
<db:provider id="dbProvider"
@@ -93,7 +109,7 @@
which is responsible for performing data access operations. This is
declared in ExampleTest.xml as shown below
- <object id="adoTemplate" type="Spring.Data.Generic.AdoTemplate, Spring.Data">
+ <object id="adoTemplate" type="Spring.Data.Generic.AdoTemplate, Spring.Data">
<property name="DbProvider" ref="dbProvider"/>
<property name="DataReaderWrapperType" value="Spring.Data.Support.NullMappingDataReader, Spring.Data"/>
</object>
@@ -103,7 +119,7 @@
previously defined. Also the property DataReaderWrapper is set to the
NullMappingDataReader that ships with Spring. This provides convenient
default values for null values returned from the database. To read
- more about AdoTemplate, refer to the chapter, Data
+ more about AdoTemplate, refer to the chapter, Data
access using ADO.NET.
@@ -114,7 +130,7 @@
The code that exercises the use of a CommandCallback is shown
below
- [Test]
+ [Test]
public void CallbackDaoTest()
{
CommandCallbackDao commandCallbackDao = ctx["commandCallbackDao"] as CommandCallbackDao;
@@ -124,7 +140,7 @@
The configuration of the CommandCallbackDao is shown below
- <object id="commandCallbackDao" type="Spring.DataQuickStart.Dao.GenericTemplate.CommandCallbackDao, Spring.DataQuickStart">
+ <object id="commandCallbackDao" type="Spring.DataQuickStart.Dao.GenericTemplate.CommandCallbackDao, Spring.DataQuickStart">
<property name="AdoTemplate" ref="adoTemplate"/>
</object>
@@ -134,7 +150,7 @@
size of the result set returned etc. The implementation of the
FindCountWithPostalCode is shown below
- public virtual int FindCountWithPostalCodeWithDelegate(string postalCode)
+ public virtual int FindCountWithPostalCodeWithDelegate(string postalCode)
{
// Using anonymous delegates allows you to easily reference the
// surrounding parameters for use with the DbCommand processing.
diff --git a/doc/reference/src/dbprovider.xml b/doc/reference/src/dbprovider.xml
index 4611fe7a..e03ddb47 100644
--- a/doc/reference/src/dbprovider.xml
+++ b/doc/reference/src/dbprovider.xml
@@ -1,13 +1,30 @@
-
+
+DbProvider
-
+ IntroductionSpring provides a generic factory for creating ADO.NET API artifacts
- such as IDbConnection and
- IDbCommand. The factory API is very
+ such as IDbConnection and
+ IDbCommand. The factory API is very
similar to the one introduced in .NET 2.0 but adds extra metadata needed
by Spring to support features provided by its DAO/ADO.NET framework such
as error code translation to a DAO exception hierarchy. The factory itself
@@ -39,15 +56,15 @@
calling context.
-
+ IDbProvider and DbProviderFactory
- The IDbProvider API is
+ The IDbProvider API is
shown below and should look familiar to anyone using .NET 2.0 data
providers. Note that Spring's DbProvider abstraction can be used on .NET
1.1 in addition to .NET 2.0
- public interface IDbProvider
+ public interface IDbProvider
{
IDbCommand CreateCommand();
@@ -89,7 +106,7 @@
create the string for a IDataParameter.ParameterName, typically contained
inside a IDataParameterCollection.
- The class DbProviderFactory creates
+ The class DbProviderFactory creates
IDbProvider instances given a provider name. The connection string
property will be used to set the IDbConnection returned by the factory if
present. The provider names, and corresponding database, currently
@@ -242,17 +259,17 @@
An example using DbProviderFactory is shown below
- IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");
+ IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");The default definitions of the providers are contained in the
assembly resource
assembly://Spring.Data/Spring.Data.Common/dbproviders.xml.
Future additions to round out the database coverage are forthcoming. The
current crude mechanism to add additional providers, or to apply any
- standard Spring IApplicationContext
+ standard Spring IApplicationContext
functionality, such as applying AOP advice, is to set the public static
property DBPROVIDER_ADDITIONAL_RESOURCE_NAME in
- DbProviderFactory to a Spring resource location.
+ DbProviderFactory to a Spring resource location.
The default value is file://dbProviders.xml. (That isn't a
typo, there is a difference in case with the name of the embedded
resource). This crude mechanism will eventually be replaced with one based
@@ -264,7 +281,7 @@
application, you should add an assembly redirect of the form shown
below.
- <dependentAssembly>
+ <dependentAssembly>
<assemblyIdentity name="MySql.Data"
publicKeyToken="c5687fc88969c44d"
culture="neutral"/>
@@ -283,7 +300,7 @@
below in the typical case of using it to specify the DbProvider property
on an AdoTemplate.
- <objects xmlns='http://www.springframework.net'
+ <objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database">
<db:provider id="DbProvider"
@@ -302,7 +319,7 @@
the rest of the Spring configuration locations as described in previous
chapters.
- <configuration>
+ <configuration>
<configSections>
<sectionGroup name="spring">
@@ -335,7 +352,7 @@
An example of such a setting is shown below
- <configuration>
+ <configuration>
<configSections>
<sectionGroup name="spring">
<section name='context' type='Spring.Context.Support.ContextHandler, Spring.Core'/>
@@ -367,7 +384,7 @@
Where Dao.xml has a connection string as shown
below
- <objects xmlns='http://www.springframework.net'
+ <objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database">
<db:provider id="DbProvider"
@@ -391,17 +408,17 @@
information.
-
+ Additional IDbProvider implementationsSpring provides some convenient implementations of the IDbProvider
interface that add addtional behavior on top of the standard
implementation.
-
+ UserCredentialsDbProvider
- This UserCredentialsDbProvider will allow
+ This UserCredentialsDbProvider will allow
you to change the username and password of a database connection at
runtime. The API contains the properties Username and
Password which are used as the default strings
@@ -416,7 +433,7 @@
You may retrieve the user information from an HTTP session for example.
Example configuration and usage is shown below
- <object id="DbProvider" type="Spring.Data.Common.UserCredentialsDbProvider, Spring.Data">
+ <object id="DbProvider" type="Spring.Data.Common.UserCredentialsDbProvider, Spring.Data">
<property name="TargetDbProvider" ref="targetDbProvider"/>
<property name="Username" value="User ID=defaultName"/>
<property name="Password" value="Password=defaultPass"/>
@@ -431,7 +448,7 @@
of the type UserCredentialsDbProvider instead of
IDbProvider.
- userCredentialsDbProvider.SetCredentialsForCurrentThread("User ID=springqa", "Password=springqa");
+ userCredentialsDbProvider.SetCredentialsForCurrentThread("User ID=springqa", "Password=springqa");UserCredentialsDbProvider's has a base class,
DelegatingDbProvider, and is intended for you to use
@@ -442,21 +459,21 @@
to the target IDbProvider.
-
+ MultiDelegatingDbProviderThere are use-cases in which there will need to be a runtime
selection of the database to connect to among many possible candidates.
This is often the case where the same schema is installed in separate
databases for different clients. The
- MultiDelegatingDbProvider implements the
- IDbProvider interface and provides an abstraction
+ MultiDelegatingDbProvider implements the
+ IDbProvider interface and provides an abstraction
to the multiple databases and can be used in DAO layer such that the DAO
layer is unaware of the switching between databases.
- MultiDelegatingDbProvider does its job by looking
+ MultiDelegatingDbProvider does its job by looking
into thread local storage under the key dbProviderName. This storage
location stores the name of the dbProvider that is to be used for
- processing the request. MultiDelegatingDbProvider
+ processing the request. MultiDelegatingDbProvider
is configured using the dictionary property
TargetDbProviders. The key of this dictionary
contains the name of a dbProvider and its value is a dbProvider object.
diff --git a/doc/reference/src/expressions.xml b/doc/reference/src/expressions.xml
index f29ce019..9d3f1a08 100644
--- a/doc/reference/src/expressions.xml
+++ b/doc/reference/src/expressions.xml
@@ -1,8 +1,25 @@
-
+
+Expression Evaluation
-
+ IntroductionThe Spring.Expressions namespace provides a powerful expression
@@ -33,12 +50,12 @@
additional example usage.
-
+ Evaluating ExpressionsThe simplest, but not the most efficient way to perform expression
evaluation is by using one of the static convenience methods of the
- ExpressionEvaluator class:public static object GetValue(object root, string expression);
+ ExpressionEvaluator class:public static object GetValue(object root, string expression);
public static object GetValue(object root, string expression, IDictionary variables)
@@ -49,8 +66,8 @@ public static void SetValue(object root, string expression, IDictionary variable
argument) will be evaluated against. The third argument is used to support
variables in the expression and will be discussed later. Simple usage to
get the value of an object property is shown below using the
- Inventor class. You can find the class listing in
- section . Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian");
+ Inventor class. You can find the class listing in
+ section . Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian");
tesla.PlaceOfBirth.City = "Smiljan";
@@ -61,39 +78,39 @@ string evaluatedCity = (string) ExpressionEvaluator.GetValue(tesla, "PlaceOfBirt
is 'Smiljan'. A period is used to navigate the nested properties of the
object. Similarly to set the property of an object, say we want to rewrite
history and change Tesla's city of birth, we would simply add the
- following line ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.City", "Novi Sad");
+ following line ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.City", "Novi Sad");A much better way to evaluate expressions is to parse them once and
then evaluate as many times as you want
- usingExpressionclass. Unlike
- ExpressionEvaluator, which parses expression every
- time you invoke one of its methods, Expression
+ usingExpressionclass. Unlike
+ ExpressionEvaluator, which parses expression every
+ time you invoke one of its methods, Expression
class will cache the parsed expression for increased performance. The
- methods of this class are listed below: public static IExpression Parse(string expression)
+ methods of this class are listed below: public static IExpression Parse(string expression)
public override object Get(object context, IDictionary variables)
public override void Set(object context, IDictionary variables, object newValue)
The retrieval of the Name property in the previous example using the
- Expression class is shown below IExpression exp = Expression.Parse("Name");
+ Expression class is shown below IExpression exp = Expression.Parse("Name");
string evaluatedName = (string) exp.GetValue(tesla, null);The difference in performance between the two approaches, when
evaluating the same expression many times, is several orders of magnitude,
so you should only use convenience methods of the
- ExpressionEvaluator class when you are doing
+ ExpressionEvaluator class when you are doing
one-off expression evaluations. In all other cases you should parse the
expression first and then evaluate it as many times as you need.There are a few exception classes to be aware of when using the
- ExpressionEvaluator. These are
- InvalidPropertyException, when you refer to a
+ ExpressionEvaluator. These are
+ InvalidPropertyException, when you refer to a
property that doesn't exist,
- NullValueInNestedPathException, when a null value
+ NullValueInNestedPathException, when a null value
is encountered when traversing through the nested property list, and
- ArgumentException and
- NotSupportedException when you pass in values that
+ ArgumentException and
+ NotSupportedException when you pass in values that
are in error in some other manner.The expression language is based on a grammar and uses
-
+ Language Reference
-
+ Literal expressionsThe types of literal expressions supported are strings, dates,
@@ -121,7 +138,7 @@ string evaluatedName = (string) exp.GetValue(tesla, null);string helloWorld = (string) ExpressionEvaluator.GetValue(null, "'Hello World'"); // evals to "Hello World"
+ side of a logical comparison operator. string helloWorld = (string) ExpressionEvaluator.GetValue(null, "'Hello World'"); // evals to "Hello World"
string tonyPizza = (string) ExpressionEvaluator.GetValue(null, "'Tony\\'s Pizza'"); // evals to "Tony's Pizza"
@@ -140,29 +157,29 @@ object nullValue = ExpressionEvaluator.GetValue(null, "null");
Note that the extra backslash character in Tony's Pizza is to satisfy C#
escape syntax. Numbers support the use of the negative sign, exponential
notation, and decimal points. By default real numbers are parsed using
- Double.Parse unless the format character "M" or
- "F" is supplied, in which case Decimal.Parse and
- Single.Parse would be used respectfully. As shown
+ Double.Parse unless the format character "M" or
+ "F" is supplied, in which case Decimal.Parse and
+ Single.Parse would be used respectfully. As shown
above, if two arguments are given to the date literal then
- DateTime.ParseExact will be used. Note that all
+ DateTime.ParseExact will be used. Note that all
parse methods of classes that are used internally reference the
- CultureInfo.InvariantCulture.
+ CultureInfo.InvariantCulture.
-
+ Properties, Arrays, Lists, Dictionaries, IndexersAs shown in the previous example in , navigating through properties is
easy, just use a period to indicate a nested property value. The
- instances of Inventor class,
+ instances of Inventor class,
pupin and tesla, were
populated with data listed in section . To navigate "down" and get Tesla's
year of birth and Pupin's city of birth the following expressions are
- used int year = (int) ExpressionEvaluator.GetValue(tesla, "DOB.Year")); // 1856
+ used int year = (int) ExpressionEvaluator.GetValue(tesla, "DOB.Year")); // 1856
string city = (string) ExpressionEvaluator.GetValue(pupin, "PlaCeOfBirTh.CiTy"); // "Idvor"
For the sharp-eyed, that isn't a typo in the property name for place of
@@ -170,7 +187,7 @@ string city = (string) ExpressionEvaluator.GetValue(pupin, "PlaCeOfBirTh.CiTy");
evaluation is case insensitive.The contents of arrays and lists are obtained using square bracket
- notation. // Inventions Array
+ notation. // Inventions Array
string invention = (string) ExpressionEvaluator.GetValue(tesla, "Inventions[3]"); // "Induction motor"
// Members List
@@ -182,7 +199,7 @@ string invention = (string) ExpressionEvaluator.GetValue(ieee, "Members[0].Inven
The contents of dictionaries are obtained by specifying the
literal key value within the brackets. In this case, because keys for
the Officers dictionary are strings, we can specify
- string literal.// Officer's Dictionary
+ string literal.// Officer's Dictionary
Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers['president']";
string city = (string) ExpressionEvaluator.GetValue(ieee, "Officers['president'].PlaceOfBirth.City"); // "Idvor"
@@ -196,7 +213,7 @@ ExpressionEvaluator.SetValue(ieee, "Officers['advisors'][0].PlaceOfBirth.Country
Indexers are similarly referenced using square brackets. The
following is a small example that shows the use of indexers.
- Multidimensional indexers are also supported. public class Bar
+ Multidimensional indexers are also supported. public class Bar
{
private int[] numbers = new int[] {1, 2, 3};
@@ -223,7 +240,7 @@ ExpressionEvaluator.SetValue(bar, "[1]", 3); // set value to 3
items with curly brackets:{1, 2, 3, 4, 5}
{'abc', 'xyz'} If you want to ensure that a strongly typed
array is initialized instead of a weakly typed list, you can use array
- initializer instead: new int[] {1, 2, 3, 4, 5}
+ initializer instead: new int[] {1, 2, 3, 4, 5}
new string[] {'abc', 'xyz'}Dictionary definition syntax is a bit different: you need to use
@@ -243,13 +260,13 @@ new string[] {'abc', 'xyz'}
-
+ MethodsMethods are invoked using typical C# programming syntax. You may
also invoke methods on literals.
- //string literal
+ //string literal
char[] chars = (char[]) ExpressionEvaluator.GetValue(null, "'test'.ToCharArray(1, 2)")) // 't','e'
//date literal
@@ -260,23 +277,23 @@ int year = (int) ExpressionEvaluator.GetValue(null, "date('1974/08/24').AddYears
ExpressionEvaluator.GetValue(ieee, "Members[0].GetAge(date('2005-01-01')") // 149 (eww..a big anniversary is coming up ;)
-
+ Operators
-
+ Relational operatorsThe relational operators; equal, not equal, less than, less than
or equal, greater than, and greater than or equal are supported using
standard operator notation. These operators take into account if the
- object implements the IComparable interface.
+ object implements the IComparable interface.
Enumerations are also supported but you will need to register the
enumeration type, as described in Section , in order to use an
enumeration value in an expression if it is not contained in the
mscorlib.
- ExpressionEvaluator.GetValue(null, "2 == 2") // true
+ ExpressionEvaluator.GetValue(null, "2 == 2") // true
ExpressionEvaluator.GetValue(null, "date('1974-08-24') != DateTime.Today") // true
@@ -286,12 +303,12 @@ ExpressionEvaluator.GetValue(null, "DateTime.Today <= date('1974-08-24')") //
ExpressionEvaluator.GetValue(null, "'Test' >= 'test'") // true
- Enumerations can be evaluated as shown below FooColor fColor = new FooColor();
+ Enumerations can be evaluated as shown below FooColor fColor = new FooColor();
ExpressionEvaluator.SetValue(fColor, "Color", KnownColor.Blue);
bool trueValue = (bool) ExpressionEvaluator.GetValue(fColor, "Color == KnownColor.Blue"); //true
- Where FooColor is the following class. public class FooColor
+ Where FooColor is the following class. public class FooColor
{
private KnownColor knownColor;
@@ -308,7 +325,7 @@ bool trueValue = (bool) ExpressionEvaluator.GetValue(fColor, "Color == KnownColo
like and between, as well as
is and matches operators,
which allow you to test if object is of a specific type or if the
- value matches a regular expression.ExpressionEvaluator.GetValue(null, "3 in {1, 2, 3, 4, 5}") // true
+ value matches a regular expression.ExpressionEvaluator.GetValue(null, "3 in {1, 2, 3, 4, 5}") // true
ExpressionEvaluator.GetValue(null, "'Abc' like '[A-Z]b*'") // true
@@ -329,13 +346,13 @@ ExpressionEvaluator.GetValue(null, @"'5.00' matches '^-?\d+(\.\d{2})?$'") // tr
like operator pattern string.
-
+ Logical operatorsThe logical operators that are supported are
and, or, and
not. Their use is demonstrated
- below// AND
+ below// AND
bool falseValue = (bool) ExpressionEvaluator.GetValue(null, "true and false"); //false
string expression = @"IsMember('Nikola Tesla') and IsMember('Mihajlo Pupin')";
@@ -355,7 +372,7 @@ string expression = @"IsMember('Nikola Tesla') and !IsMember('Mihajlo Pupin')";
bool falseValue = (bool) ExpressionEvaluator.GetValue(ieee, expression);
-
+ Mathematical operatorsThe addition operator can be used on numbers, strings and dates.
@@ -363,7 +380,7 @@ bool falseValue = (bool) ExpressionEvaluator.GetValue(ieee, expression);// Addition
+ // Addition
int two = (int)ExpressionEvaluator.GetValue(null, "1 + 1"); // 2
String testString = (String)ExpressionEvaluator.GetValue(null, "'test' + ' ' + 'string'"); //'test string'
@@ -407,7 +424,7 @@ int minusFortyFive = (int) ExpressionEvaluator.GetValue(null, "1+2-3*8^2/2/2");
-
+ AssignmentSetting of a property is done by using the assignment operator.
@@ -416,7 +433,7 @@ int minusFortyFive = (int) ExpressionEvaluator.GetValue(null, "1+2-3*8^2/2/2");
SetValue offers the same functionality. Assignment in
this manner is useful when combining multiple operators in an expression
list, discussed in the next section. Some examples of assignment are
- shown below Inventor inventor = new Inventor();
+ shown below Inventor inventor = new Inventor();
String aleks = (String) ExpressionEvaluator.GetValue(inventor, "Name = 'Aleksandar Seovic'");
DateTime dt = (DateTime) ExpressionEvaluator.GetValue(inventor, "DOB = date('1974-08-24')");
@@ -424,14 +441,14 @@ DateTime dt = (DateTime) ExpressionEvaluator.GetValue(inventor, "DOB = date('197
Inventor tesla = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers['vp'] = Members[0]");
-
+ Expression listsMultiple expressions can be evaluated against the same context
object by separating them with a semicolon and enclosing the entire
expression within parentheses. The value returned is the value of the
last expression in the list. Examples of this are shown below
- //Perform property assignments and then return Name property.
+ //Perform property assignments and then return Name property.
String pupin = (String) ExpressionEvaluator.GetValue(ieee.Members,
"( [1].PlaceOfBirth.City = 'Beograd'; [1].PlaceOfBirth.Country = 'Serbia'; [1].Name )"));
@@ -439,11 +456,11 @@ String pupin = (String) ExpressionEvaluator.GetValue(ieee.Members,
// pupin = "Mihajlo Pupin"
-
+ TypesIn many cases, you can reference types by simply specifying type
- name:ExpressionEvaluator.GetValue(null, "1 is int")
+ name:ExpressionEvaluator.GetValue(null, "1 is int")
ExpressionEvaluator.GetValue(null, "DateTime.Today")
@@ -455,7 +472,7 @@ ExpressionEvaluator.GetValue(null, "new string[] {'abc', 'efg'}")
For all other types, you need to use special
- T(typeName) expression:Type dateType = (Type) ExpressionEvaluator.GetValue(null, "T(System.DateTime)")
+ T(typeName) expression:Type dateType = (Type) ExpressionEvaluator.GetValue(null, "T(System.DateTime)")
Type evalType = (Type) ExpressionEvaluator.GetValue(null, "T(Spring.Expressions.ExpressionEvaluator, Spring.Core)")
@@ -463,14 +480,14 @@ bool trueValue = (bool) ExpressionEvaluator.GetValue(tesla, "T(System.DateTime)
The implementation delegates to Spring's
- ObjectUtils.ResolveType method for the actual
+ ObjectUtils.ResolveType method for the actual
type resolution, which means that the types used within expressions
are resolved in the exactly the same way as the types specified in
Spring configuration files.
-
+ Type RegistrationTo refer to a type within an expression that is not in the
@@ -480,7 +497,7 @@ bool trueValue = (bool) ExpressionEvaluator.GetValue(tesla, "T(System.DateTime)
used in expression that use the new operator or refer to a static
properties of an object. Example usage is shown below.
- TypeRegistry.RegisterType("Society", typeof(Society));
+ TypeRegistry.RegisterType("Society", typeof(Society));
Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers[Society.President]");
@@ -488,13 +505,13 @@ Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers[Society
typeAliases configuration section.
-
+ ConstructorsConstructors can be invoked using the new operator. For classes
outside mscorlib you will need to register your types so they can be
resolved. Examples of using constructors are shown below:
- // simple ctor
+ // simple ctor
DateTime dt = (DateTime) ExpressionEvaluator.GetValue(null, "new DateTime(1974, 8, 24)");
// Register Inventor type then create new inventor instance within Add method inside an expression list.
@@ -510,7 +527,7 @@ int three = (int) ExpressionEvaluator.GetValue(ieee.Members, "{ Add(new Inventor
instantiation, similar to the way standard .NET attributes work. For
example, you could create an instance of the Inventor
class and set its Inventions property in a single
- statement:
+ statement:
Inventor aleks = (Inventor) ExpressionEvaluator.GetValue(null, "new Inventor('Aleksandar Seovic', date('1974-08-24'), 'Serbian', Inventions = {'SPELL'})");
The only rule you have to follow is that named arguments
should be specified after standard constructor
@@ -520,7 +537,7 @@ Inventor aleks = (Inventor) ExpressionEvaluator.GetValue(null, "new Inventor('Al
provides a convenient syntax for .NET attribute instance creation.
Instead of using standard constructor syntax, you can use a somewhat
shorter and more familiar syntax to create an instance of a .NET
- attribute class:
+ attribute class:
WebMethodAttribute webMethod = (WebMethodAttribute) ExpressionEvaluator.GetValue(null, "@[WebMethod(true, CacheDuration = 60, Description = 'My Web Method')]");
As you can see, with the exception of the
@ prefix, syntax is exactly the same as in C#.
@@ -533,29 +550,29 @@ WebMethodAttribute webMethod = (WebMethodAttribute) ExpressionEvaluator.GetValue
Attribute suffix, just like the C# compiler.
-
+ VariablesVariables can referenced in the expression using the syntax
#variableName. The variables are
passed in and out of the expression using the dictionary parameter in
- ExpressionEvaluator's GetValue
- or SetValue methods. public static object GetValue(object root, string expression, IDictionary variables)
+ ExpressionEvaluator's GetValue
+ or SetValue methods. public static object GetValue(object root, string expression, IDictionary variables)
public static void SetValue(object root, string expression, IDictionary variables, object newValue)
The variable name is the key value of the dictionary. Example usage is
- shown below; IDictionary vars = new Hashtable();
+ shown below; IDictionary vars = new Hashtable();
vars["newName"] = "Mike Tesla";
ExpressionEvaluator.GetValue(tesla, "Name = #newName", vars));
You can also use the dictionary as a place to store values of the object
as they are evaluated inside the expression. For example to change
- Tesla's first name back again and keep the old value; ExpressionEvaluator.GetValue(tesla, "{ #oldName = Name; Name = 'Nikola Tesla' }", vars);
+ Tesla's first name back again and keep the old value; ExpressionEvaluator.GetValue(tesla, "{ #oldName = Name; Name = 'Nikola Tesla' }", vars);
String oldName = (String)vars["oldName"]; // Mike Tesla
Variable names can also be used inside indexers or maps instead of
- literal values. For example; vars["prez"] = "president";
+ literal values. For example; vars["prez"] = "president";
Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers[#prez]", vars);
-
+ The '#this' and '#root' variablesThere are two special variables that are always defined and can
@@ -564,24 +581,24 @@ Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers[#prez]"
The #this variable can be used to explicitly
refer to the context for the node that is currently being
- evaluated:// sets the name of the president and returns its instance
+ evaluated:// sets the name of the president and returns its instance
ExpressionEvaluator.GetValue(ieee, "Officers['president'].( #this.Name = 'Nikola Tesla'; #this )")Similarly, the #root variable allows you to
- refer to the root context for the expression:// removes president from the Officers dictionary and returns removed instance
+ refer to the root context for the expression:// removes president from the Officers dictionary and returns removed instance
ExpressionEvaluator.GetValue(ieee, "Officers['president'].( #root.Officers.Remove('president'); #this )")
-
+ Ternary Operator (If-Then-Else)You can use the ternary operator for performing if-then-else
conditional logic inside the expression. A minimal example is;
- String aTrueString = (String) ExpressionEvaluator.GetValue(null, "false ? 'trueExp' : 'falseExp'") // trueExp
+ String aTrueString = (String) ExpressionEvaluator.GetValue(null, "false ? 'trueExp' : 'falseExp'") // trueExp
In this case, the boolean false results in returning the
string value 'trueExp'. A less artificial example is shown below
- ExpressionEvaluator.SetValue(ieee, "Name", "IEEE");
+ ExpressionEvaluator.SetValue(ieee, "Name", "IEEE");
IDictionary vars = new Hashtable();
vars["queryName"] = "Nikola Tesla";
@@ -607,8 +624,8 @@ String queryResultString = (String) ExpressionEvaluator.GetValue(ieee, expressio
For example, let's say that we need a list of the cities where our
inventors were born. This could be easily obtained by projecting on the
- PlaceOfBirth.City property: IList placesOfBirth = (IList) ExpressionEvaluator.GetValue(ieee, "Members.!{PlaceOfBirth.City}") // { 'Smiljan', 'Idvor' }
-Or we can get the list of officers' names:IList officersNames = (IList) ExpressionEvaluator.GetValue(ieee, "Officers.Values.!{Name}") // { 'Nikola Tesla', 'Mihajlo Pupin' }
+ PlaceOfBirth.City property: IList placesOfBirth = (IList) ExpressionEvaluator.GetValue(ieee, "Members.!{PlaceOfBirth.City}") // { 'Smiljan', 'Idvor' }
+Or we can get the list of officers' names:IList officersNames = (IList) ExpressionEvaluator.GetValue(ieee, "Officers.Values.!{Name}") // { 'Nikola Tesla', 'Mihajlo Pupin' }
As you can see from the examples, projection uses
@@ -620,11 +637,11 @@ String queryResultString = (String) ExpressionEvaluator.GetValue(ieee, expressio
?{projectionExpression}
syntax, will filter the list and return a new list containing a subset
of the original element list. For example, selection would allow us to
- easily get a list of Serbian inventors:IList serbianInventors = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{Nationality == 'Serbian'}") // { tesla, pupin }
+ easily get a list of Serbian inventors:IList serbianInventors = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{Nationality == 'Serbian'}") // { tesla, pupin }
Or to get a list of inventors that invented
- sonar:IList sonarInventors = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{'Sonar' in Inventions}") // { pupin }
+ sonar:IList sonarInventors = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{'Sonar' in Inventions}") // { pupin }
Or we can combine selection and projection to get a list of
- sonar inventors' names:IList sonarInventorsNames = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{'Sonar' in Inventions}.!{Name}") // { 'Mihajlo Pupin' }
+ sonar inventors' names:IList sonarInventorsNames = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{'Sonar' in Inventions}.!{Name}") // { 'Mihajlo Pupin' }
As a convenience, Spring.NET Expression Language also supports a
@@ -635,7 +652,7 @@ String queryResultString = (String) ExpressionEvaluator.GetValue(ieee, expressio
elements were found. In order to return a first match you should prefix
your selection expression with ^{ instead of
?{, and to return last match you should use
- ${ prefix:ExpressionEvaluator.GetValue(ieee, "Members.^{Nationality == 'Serbian'}.Name") // 'Nikola Tesla'
+ ${ prefix:ExpressionEvaluator.GetValue(ieee, "Members.^{Nationality == 'Serbian'}.Name") // 'Nikola Tesla'
ExpressionEvaluator.GetValue(ieee, "Members.${Nationality == 'Serbian'}.Name") // 'Mihajlo Pupin'
Notice that we access the Name property
directly on the selection result, because an actual matched instance is
@@ -643,7 +660,7 @@ ExpressionEvaluator.GetValue(ieee, "Members.${Nationality == 'Serbian'}.Name")
list.
-
+ Collection Processors and AggregatorsIn addition to list projection and selection, Spring.NET
@@ -670,9 +687,9 @@ ExpressionEvaluator.GetValue(ieee, "Members.${Nationality == 'Serbian'}.Name")
Count or Length property
depending on the context. Unlike its standard .NET counterparts, count
aggregator can also be invoked on the null context
- without throwing a NullReferenceException. It
+ without throwing a NullReferenceException. It
will simply return zero in this case, which makes it much safer than
- standard .NET properties within larger expression.ExpressionEvaluator.GetValue(null, "{1, 5, -3}.count()") // 3
+ standard .NET properties within larger expression.ExpressionEvaluator.GetValue(null, "{1, 5, -3}.count()") // 3
ExpressionEvaluator.GetValue(null, "count()") // 0
@@ -685,7 +702,7 @@ ExpressionEvaluator.GetValue(null, "count()") // 0
or precision, it will automatically perform necessary conversion and
the result will be the highest precision type. If any of the
collection elements is not a number, this aggregator will throw an
- InvalidArgumentException.ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.sum()") // 13 (int)
+ InvalidArgumentException.ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.sum()") // 13 (int)
ExpressionEvaluator.GetValue(null, "{5, 5.8, 12.2, 1}.sum()") // 24.0 (double)
@@ -698,7 +715,7 @@ ExpressionEvaluator.GetValue(null, "{5, 5.8, 12.2, 1}.sum()") // 24.0 (double)
the sum aggregator in order to be as precise as possible. Just like
the sum aggregator, if any of the collection elements is not a number,
it will throw an
- InvalidArgumentException.ExpressionEvaluator.GetValue(null, "{1, 5, -4, 10}.average()") // 3
+ InvalidArgumentException.ExpressionEvaluator.GetValue(null, "{1, 5, -4, 10}.average()") // 3
ExpressionEvaluator.GetValue(null, "{1, 5, -2, 10}.average()") // 3.5
@@ -710,9 +727,9 @@ ExpressionEvaluator.GetValue(null, "{1, 5, -2, 10}.average()") // 3.5
list. In order to determine what "the smallest" actually means, this
aggregator relies on the assumption that the collection items are of
the uniform type and that they implement the
- IComparable interface. If that is not the case,
+ IComparable interface. If that is not the case,
this aggregator will throw an
- InvalidArgumentException.ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.min()") // -3
+ InvalidArgumentException.ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.min()") // -3
ExpressionEvaluator.GetValue(null, "{'abc', 'efg', 'xyz'}.min()") // 'abc'
@@ -724,9 +741,9 @@ ExpressionEvaluator.GetValue(null, "{'abc', 'efg', 'xyz'}.min()") // 'abc'
In order to determine what "the largest" actually means, this
aggregator relies on the assumption that the collection items are of
the uniform type and that they implement
- IComparable interface. If that is not the case,
+ IComparable interface. If that is not the case,
this aggregator will throw an
- InvalidArgumentException.ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.max()") // 10
+ InvalidArgumentException.ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.max()") // 10
ExpressionEvaluator.GetValue(null, "{'abc', 'efg', 'xyz'}.max()") // 'xyz'
@@ -736,7 +753,7 @@ ExpressionEvaluator.GetValue(null, "{'abc', 'efg', 'xyz'}.max()") // 'xyz'
A non-null processor is a very simple collection processor that
eliminates all null values from the
- collection.ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', null, 'abc', 'def', null}.nonNull()") // { 'abc', 'xyz', 'abc', 'def' }
+ collection.ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', null, 'abc', 'def', null}.nonNull()") // { 'abc', 'xyz', 'abc', 'def' }
ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', null, 'abc', 'def', null}.nonNull().distinct().sort()") // { 'abc', 'def', 'xyz' }
@@ -749,7 +766,7 @@ ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', null, 'abc', 'def', null}.no
an optional Boolean argument that will determine
whether null values should be included in the
results. The default is false, which means that
- they will not be included. ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.distinct(true).sort()") // { null, 'abc', 'def', 'xyz' }
+ they will not be included. ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.distinct(true).sort()") // { null, 'abc', 'def', 'xyz' }
ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.distinct(false).sort()") // { 'abc', 'def', 'xyz' }
@@ -758,9 +775,9 @@ ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.
Sort ProcessorThe sort processor can be used to sort uniform collections of
- elements that implement IComparable.
+ elements that implement IComparable.
- ExpressionEvaluator.GetValue(null, "{1.2, 5.5, -3.3}.sort()") // { -3.3, 1.2, 5.5 }
+ ExpressionEvaluator.GetValue(null, "{1.2, 5.5, -3.3}.sort()") // { -3.3, 1.2, 5.5 }
ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.sort()") // { null, 'abc', 'abc', 'def', 'def', 'xyz' }
@@ -775,7 +792,7 @@ ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.
The convert processor can be used to convert a collection of
elements to a given Type.
- object[] arr = new object[] { "0", 1, 1.1m, "1.1", 1.1f };
+ object[] arr = new object[] { "0", 1, 1.1m, "1.1", 1.1f };
decimal[] result = (decimal[]) ExpressionEvaluator.GetValue(arr, "convert(decimal)");
@@ -786,7 +803,7 @@ decimal[] result = (decimal[]) ExpressionEvaluator.GetValue(arr, "convert(decima
The reverse processor returns the reverse order of elements in
the list
- object[] arr = new object[] { "0", 1, 2.1m, "3", 4.1f };
+ object[] arr = new object[] { "0", 1, 2.1m, "3", 4.1f };
object[] result = new ArrayList( (ICollection) ExpressionEvaluator.GetValue(arr, "reverse()") ).ToArray(); // { 4.1f, "3", 2.1m, 1, "0" }
@@ -796,13 +813,13 @@ object[] result = new ArrayList( (ICollection) ExpressionEvaluator.GetValue(arr,
Collections can be ordered in three ways, an expression, a SpEL
lamda expreression, or a delegate.
- // orderBy expression
+ // orderBy expression
IExpression exp = Expression.Parse("orderBy('ToString()')");
object[] input = new object[] { 'b', 1, 2.0, "a" };
object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
-// SpEL lambda expressions
+// SpEL lambda expressions
IExpression exp = Expression.Parse("orderBy({|a,b| $a.ToString().CompareTo($b.ToString())})");
object[] input = new object[] { 'b', 1, 2.0, "a" };
object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
@@ -812,7 +829,7 @@ Expression.RegisterFunction( "compare", "{|a,b| $a.ToString().CompareTo($b.ToStr
exp = Expression.Parse("orderBy(#compare)");
ordered = exp.GetValue(input, vars); // { 1, 2.0, "a", 'b' }
-// .NET delegate
+// .NET delegate
private delegate int CompareCallback(object x, object y);
private int CompareObjects(object x, object y)
{
@@ -837,7 +854,7 @@ object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
implementation that sums only the even numbers of an integer
list
- public class IntEvenSumCollectionProcessor : ICollectionProcessor
+ public class IntEvenSumCollectionProcessor : ICollectionProcessor
{
public object Process(ICollection source, object[] args)
{
@@ -874,7 +891,7 @@ object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
-
+ Spring Object ReferencesExpressions can refer to objects that are declared in Spring's
@@ -884,7 +901,7 @@ object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
(Spring.RootContext) is used. Using the application
context defined in the MovieFinder example from , the following expression returns the number of
- movies directed by Roberto Benigni. public static void Main()
+ movies directed by Roberto Benigni. public static void Main()
{
. . .
@@ -900,7 +917,7 @@ int numMovies = (int) ExpressionEvaluator.GetValue(null,
example.
-
+ Lambda ExpressionsA somewhat advanced, but a very powerful feature of Spring.NET
@@ -916,7 +933,7 @@ int numMovies = (int) ExpressionEvaluator.GetValue(null,
functionBody }For example, you could define a max function
- and call it like this:ExpressionEvaluator.GetValue(null, "(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))", new Hashtable()) // 25
+ and call it like this:ExpressionEvaluator.GetValue(null, "(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))", new Hashtable()) // 25As you can see, any arguments defined for the expression can be
referenced within the function body using a local
@@ -927,7 +944,7 @@ int numMovies = (int) ExpressionEvaluator.GetValue(null,
function name.Lambda expressions can be recursive, which means that you can
- invoke the function within its own body:ExpressionEvaluator.GetValue(null, "(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))", new Hashtable()) // 120
+ invoke the function within its own body:ExpressionEvaluator.GetValue(null, "(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))", new Hashtable()) // 120Notice that in both examples above we had to specify a
variables parameter for the
@@ -945,13 +962,13 @@ int numMovies = (int) ExpressionEvaluator.GetValue(null,
easy way to pre-register your lambda expressions by exposing a static
Expression.RegisterFunction method, which takes
function name, lambda expression and variables dictionary to register
- function in as parameters:IDictionary vars = new Hashtable();
+ function in as parameters:IDictionary vars = new Hashtable();
Expression.RegisterFunction("sqrt", "{|n| Math.Sqrt($n)}", vars);
Expression.RegisterFunction("fact", "{|n| $n <= 1 ? 1 : $n * #fact($n-1)}", vars);Once
the function registration is done, you can simply evaluate an expression
that uses these functions, making sure that the vars
dictionary is passed as a parameter to expression evaluation
- engine:ExpressionEvaluator.GetValue(null, "#fact(5)", vars) // 120
+ engine:ExpressionEvaluator.GetValue(null, "#fact(5)", vars) // 120
ExpressionEvaluator.GetValue(null, "#sqrt(9)", vars) // 3Finally, because lambda expressions are treated as variables, they
@@ -961,7 +978,7 @@ ExpressionEvaluator.GetValue(null, "#sqrt(9)", vars) // 3n that will be passed to
function f as the second. Then we invoke the
functions registered in the previous example, as well as the lambda
- expression defined inline, through our delegate:Expression.RegisterFunction("delegate", "{|f, n| $f($n) }", vars);
+ expression defined inline, through our delegate:Expression.RegisterFunction("delegate", "{|f, n| $f($n) }", vars);
ExpressionEvaluator.GetValue(null, "#delegate(#sqrt, 4)", vars) // 2
ExpressionEvaluator.GetValue(null, "#delegate(#fact, 5)", vars) // 120
ExpressionEvaluator.GetValue(null, "#delegate({|n| $n ^ 2 }, 5)", vars) // 25While
@@ -980,7 +997,7 @@ ExpressionEvaluator.GetValue(null, "#delegate({|n| $n ^ 2 }, 5)", vars) // 25
For example, you can define a max delegate and call it like
this
- private delegate double DoubleFunctionTwoArgs(double arg1, double arg2);
+ private delegate double DoubleFunctionTwoArgs(double arg1, double arg2);
private double Max(double arg1, double arg2)
{
@@ -1013,13 +1030,13 @@ public void DoWork()
-
+ Classes used in the examplesThe following simple classes are used to demonstrate the
functionality of the expression language.
- public class Inventor
+ public class Inventor
{
public string Name;
public string Nationality;
@@ -1099,7 +1116,7 @@ public class Society
The code listings in this chapter use instances of the data
populated with the following information.
- Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian");
+ Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian");
tesla.Inventions = new string[]
{
"Telephone repeater", "Rotating magnetic field principle",
diff --git a/doc/reference/src/images/Copy of S2-banner-rhs.png b/doc/reference/src/images/Copy of S2-banner-rhs.png
deleted file mode 100644
index a9f6d959..00000000
Binary files a/doc/reference/src/images/Copy of S2-banner-rhs.png and /dev/null differ
diff --git a/doc/reference/src/images/i21-banner-rhs.jpg b/doc/reference/src/images/i21-banner-rhs.jpg
deleted file mode 100644
index 8b24a773..00000000
Binary files a/doc/reference/src/images/i21-banner-rhs.jpg and /dev/null differ
diff --git a/doc/reference/src/index.xml b/doc/reference/src/index.xml
index aaceb3de..8c7df74c 100644
--- a/doc/reference/src/index.xml
+++ b/doc/reference/src/index.xml
@@ -1,63 +1,63 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
]>
-
-
+
+ The Spring.NET FrameworkReference DocumentationVersion 1.2.0 M1
@@ -81,7 +81,7 @@
Federico
- Spinazzi
+ SpinazziRob
@@ -110,328 +110,318 @@
distribution to others, provided that you do not charge any fee for such
copies and further provided that each copy contains this Copyright
Notice, whether distributed in print or electronically.
-
+
-
+
- &preface;
- &overview;
- &background;
- &migration;
-
- Core Technologies
-
-
- This initial part of the reference documentation covers
- all of those technologies that are absolutely integral
- to the Spring Framework.
-
-
- Foremost amongst these is the Spring Framework's
- Inversion of Control (IoC) container. A thorough treatment
- of the Spring Framework's IoC container is closely followed
- by comprehensive coverage of Spring's Aspect-Oriented
- Programming (AOP) technologies. The Spring Framework has
- its own AOP framework, which is conceptually easy to understand,
- and which successfully addresses the 80% sweet spot of AOP
- requirements in enterprise programming.
-
-
- The core functionality also includes an expression language
- for lightweight scripting and a ui-agnostic validation framework.
-
-
- Finally, the adoption of the test-driven-development (TDD)
- approach to software development is certainly advocated by
- the Spring team, and so coverage of Spring's support for
- integration testing is covered (alongside best practices for
- unit testing). The Spring team have found that the correct
- use of IoC certainly does make both unit and integration
- testing easier (in that the presence of properties and
- appropriate constructors on classes makes them
- easier to wire together on a test without having to set up
- service locator registries and suchlike)... the chapter
- dedicated solely to testing will hopefully convince you of
- this as well.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &objects;
- &objects-misc;
- &resources;
- &threading;
- &pool;
- &misc;
- &expressions;
- &validation;
-
- &aop;
- &aop-aspect-library;
- &logging;
- &testing;
-
-
- Middle Tier Data Access
-
-
- This part of the reference documentation is concerned
- with othe middle tier, and specifically the data access
- responsibilities of said tier.
-
-
- Spring's comprehensive transaction management support is
- covered in some detail, followed by thorough coverage of
- the various middle tier data access frameworks and
- technologies that the Spring Framework integrates with.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &transaction;
- &dao;
- &dbprovider;
- &ado;
- &orm;
-
-
- The Web
-
-
- This part of the reference documentation covers the
- Spring Framework's support for the presentation tier,
- specifically web-based presentation tiers.
-
-
-
-
-
-
-
-
-
-
- &web;
- &ajax;
-
-
- Services
-
-
- This part of the reference documentation covers
- the Spring Framework's integration with .NET distributed
- technologies such as .NET Remoting, Enterprise Services,
- Web Services. Integration with WCF Services is forthcoming.
- Please refer to the introduction chapter for more details.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &psa-intro;
- &remoting;
- &services;
- &webservices;
- &wcf;
-
+ &preface;
+ &overview;
+ &background;
+ &migration;
+
+ Core Technologies
+
+
+ This initial part of the reference documentation covers
+ all of those technologies that are absolutely integral
+ to the Spring Framework.
+
+
+ Foremost amongst these is the Spring Framework's
+ Inversion of Control (IoC) container. A thorough treatment
+ of the Spring Framework's IoC container is closely followed
+ by comprehensive coverage of Spring's Aspect-Oriented
+ Programming (AOP) technologies. The Spring Framework has
+ its own AOP framework, which is conceptually easy to understand,
+ and which successfully addresses the 80% sweet spot of AOP
+ requirements in enterprise programming.
+
+
+ The core functionality also includes an expression language
+ for lightweight scripting and a ui-agnostic validation framework.
+
+
+ Finally, the adoption of the test-driven-development (TDD)
+ approach to software development is certainly advocated by
+ the Spring team, and so coverage of Spring's support for
+ integration testing is covered (alongside best practices for
+ unit testing). The Spring team have found that the correct
+ use of IoC certainly does make both unit and integration
+ testing easier (in that the presence of properties and
+ appropriate constructors on classes makes them
+ easier to wire together on a test without having to set up
+ service locator registries and suchlike)... the chapter
+ dedicated solely to testing will hopefully convince you of
+ this as well.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &objects;
+ &objects-misc;
+ &resources;
+ &threading;
+ &pool;
+ &misc;
+ &expressions;
+ &validation;
+
+ &aop;
+ &aop-aspect-library;
+ &logging;
+ &testing;
+
+
+ Middle Tier Data Access
+
+
+ This part of the reference documentation is concerned
+ with othe middle tier, and specifically the data access
+ responsibilities of said tier.
+
+
+ Spring's comprehensive transaction management support is
+ covered in some detail, followed by thorough coverage of
+ the various middle tier data access frameworks and
+ technologies that the Spring Framework integrates with.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &transaction;
+ &dao;
+ &dbprovider;
+ &ado;
+ &orm;
+
+
+ The Web
+
+
+ This part of the reference documentation covers the
+ Spring Framework's support for the presentation tier,
+ specifically web-based presentation tiers.
+
+
+
+
+
+
+
+
+
+
+ &web;
+ &ajax;
+
+
+ Services
+
+
+ This part of the reference documentation covers
+ the Spring Framework's integration with .NET distributed
+ technologies such as .NET Remoting, Enterprise Services,
+ Web Services. Integration with WCF Services is forthcoming.
+ Please refer to the introduction chapter for more details.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &psa-intro;
+ &remoting;
+ &services;
+ &webservices;
+ &wcf;
+
+
+ Integration
+
+
+ This part of the reference documentation covers
+ the Spring Framework's integration with a number of
+ related enterprise .NET technologies.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &messaging;
+ &msmq;
+ &scheduling;
+
+
+ VS.NET Integration
+
+
+ This part of the reference documentation covers
+ the Spring Framework's integration with VS.NET
+
+
+
+
+
+
+
+ &vsnet;
+
+
+ Quickstart applications
+
+
+ This part of the reference documentation covers
+ the quickstart applications included with
+ Spring that demonstrate features in a code centric
+ manner.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &quickstarts;
+ &aop-quickstart;
+ &remoting-quickstart;
+ &web-quickstart;
+ &springair;
+ &data-quickstart;
+ &tx-quickstart;
+ &quartz-quickstart;
+ &nms-quickstart;
+
+ &wcf-quickstart;
+
+
+ Spring.NET for Java developers
+
+
+ This part of the reference documentation
+ is for Java developers who would like a quick
+ orientation to what is different between
+ the Java and .NET versions of the framework.
+
+
+
+
+
+
+
+ &javadevelopers;
+
-
- Integration
-
-
- This part of the reference documentation covers
- the Spring Framework's integration with a number of
- related enterprise .NET technologies.
-
-
-
-
-
-
-
-
-
-
-
-
-
- &messaging;
- &msmq;
- &scheduling;
-
-
-
- VS.NET Integration
-
-
- This part of the reference documentation covers
- the Spring Framework's integration with VS.NET
-
-
-
-
-
-
-
- &vsnet;
-
-
- Quickstart applications
-
-
- This part of the reference documentation covers
- the quickstart applications included with
- Spring that demonstrate features in a code centric
- manner.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &quickstarts;
- &aop-quickstart;
- &remoting-quickstart;
- &web-quickstart;
- &springair;
- &data-quickstart;
- &tx-quickstart;
- &quartz-quickstart;
- &nms-quickstart;
- &msmq-quickstart;
- &wcf-quickstart;
-
-
- Spring.NET for Java developers
-
-
- This part of the reference documentation
- is for Java developers who would like a quick
- orientation to what is different between
- the Java and .NET versions of the framework.
-
-
-
-
-
-
-
- &javadevelopers;
-
-
-
- &xsd-configuration;
- &xml-custom;
- &xsd;
+
+ &xsd-configuration;
+ &xml-custom;
+ &xsd;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/reference/src/javadevelopers.xml b/doc/reference/src/javadevelopers.xml
index dd570464..2d5cf2ba 100644
--- a/doc/reference/src/javadevelopers.xml
+++ b/doc/reference/src/javadevelopers.xml
@@ -1,8 +1,25 @@
-
+
+Spring.NET for Java Developers
-
+ IntroductionThis chapter is to help Java developers get their sea legs using
@@ -11,21 +28,21 @@
experience when you start to use Spring.NET.
-
+ Beans to ObjectsThere are some simple name changes, basically everywhere you saw the
word 'bean' you will now see the word 'object'. A comparison of a simple
Spring configuration file highlights these small name changes. Here is the
application.xml file for the sample MovieFinder application in Spring.Java
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+ <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="MyMovieLister" class="MovieFinder.MovieLister">
<property name="finder" ref="MyMovieFinder"/>
</bean>
<bean id="MyMovieFinder" class="MovieFinder.SimpleMovieFinder"/>
</beans> Here is the corresponding file in Spring.NET
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects-1.1.xsd">
<object name="MyMovieLister"
@@ -46,9 +63,8 @@
The other XML Schema elements in Spring.NET are the same as in
Spring.Java's DTD except for specifying string based key value pairs. In
Java this is represented by the java.util.Properties class and the xml
- element is name <props> as shown below
-<property name="people">
+ element is name <props> as shown below
+ <property name="people">
<props>
<prop key="PennAndTeller">The magic property</prop>
<prop key="GeorgeCarlin">The funny property</prop>
@@ -58,8 +74,7 @@
the xml element <name-values>. The listing of the elements also
follows the .NET convention of application configuration files using the
<add> element with 'key' and 'value' attributes. This is show below
-
-<property name="people">
+ <property name="people">
<name-values>
<add key="PennAndTeller" value="The magic property"/>
<add key="GeorgeCarlin" value="The funny property"/>
@@ -67,7 +82,7 @@
</property>
-
+ PropertyEditors to TypeConvertersPropertyEditors from the java.beans package provide the ability to
@@ -90,11 +105,11 @@
approach.
-
+ ResourceBundle-ResourceManager
-
+ ExceptionsExceptions in Java can either be checked or unchecked. .NET supports
@@ -104,7 +119,7 @@
of .NET
-
+ Application ConfigurationIn Spring.Java it is very common to create an ObjectFactory or
@@ -135,7 +150,7 @@
without coding or using more verbose XML as would be required in the
current version of Spring.Java
- <?xml version="1.0" encoding="utf-8" ?>
+ <?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
@@ -177,35 +192,35 @@
The following code segment is used to retrieve the
IApplicationContext from the .NET application configuration file.
- IApplicationContext ctx
+ IApplicationContext ctx
= ConfigurationUtils.GetSection("spring/context") as IApplicationContext;In order to enforce the usage of the named configuration section
spring/context the preferred instantiation mechanism is
via the use of the registry class ContextRegistry as shown below
- IApplicationContext ctx = ContextRegistry.GetContext();
+ IApplicationContext ctx = ContextRegistry.GetContext();
-
+ AOP Framework
-
+ Cannot specify target name at the end of interceptorNames for
ProxyFactoryObjectWhen configuring the list of interceptor names on a
- ProxyFactoryObject instance (or object
+ ProxyFactoryObject instance (or object
definition), one cannot specify the name of the
target (i.e. the object being proxied) at the end of the list of
interceptor names. This shortcut is valid in Spring
- Java, where the ProxyFactoryBean will
+ Java, where the ProxyFactoryBean will
automatically detect this, and use the last name in the interceptor
- names list as the target of the ProxyFactoryBean.
+ names list as the target of the ProxyFactoryBean.
The following configuration, which would be valid in Spring Java
(barring the obvious element name changes), is not valid in Spring.NET (so don't do it).
- <?xml version="1.0" encoding="utf-8" ?>
+ <?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object id="target" type="Spring.Objects.TestObject">
<property name="name" value="Bingo"/>
@@ -219,7 +234,7 @@
</objects>In Spring.NET, the InterceptorNames property of
- the ProxyFactoryObject can
+ the ProxyFactoryObject can
only be used to specify the names of interceptors.
Use the TargetName property to specify the name of
the target object that is to be proxied.
diff --git a/doc/reference/src/logging.xml b/doc/reference/src/logging.xml
index 8c67db25..0d1047f4 100644
--- a/doc/reference/src/logging.xml
+++ b/doc/reference/src/logging.xml
@@ -1,8 +1,25 @@
-
+
+Common Logging
-
+ IntroductionSpring uses a simple logging abstraction in order to provide a layer
diff --git a/doc/reference/src/messaging.xml b/doc/reference/src/messaging.xml
index 8b0a1c13..23a8558b 100644
--- a/doc/reference/src/messaging.xml
+++ b/doc/reference/src/messaging.xml
@@ -1,5 +1,22 @@
-
+
+Message Oriented Middleware
@@ -61,7 +78,7 @@
NmsTemplate, EmsTemplate (etc.) is
used. Asynchronous message consumption is performed though a
multi-threaded message listener container,
- SimpleMessageListenerContainer. This message
+ SimpleMessageListenerContainer. This message
listener container is used to create Message-Driven PONOs (MDPs) which
refer to a messaging callback class that consists of just 'plain .NET
object's and is devoid of any specific messaging types or other artifacts.
@@ -73,7 +90,7 @@
Spring.Messaging.<Vendor>.Core contains the
messing template class (e.g. NmsTemplate). The template
class simplifies the use of the messaging APIs by handling the creation
- and release of resources, much like the AdoTemplate
+ and release of resources, much like the AdoTemplate
does for ADO.NET. The JMS inspired APIs are low-level API, much like
ADO.NET. As such, even the simplest of operations requires 10s of lines of
code with the bulk of that code related to resource management of
@@ -205,35 +222,35 @@
Messaging Template overviewCode that uses the messaging template classes
- (NmsTemplate, EmsTemplate,
+ (NmsTemplate, EmsTemplate,
etc) only needs to implement callback interfaces giving them a clearly
- defined contract. The IMessageCreator callback
+ defined contract. The IMessageCreator callback
interface creates a message given a Session provided by the calling code
in NmsTemplate. In order to allow for more complex
usage of the provider messaging API, the callback
- ISessionCallback provides the user with the
+ ISessionCallback provides the user with the
provider specific messaging Session and the callback
- IProducerCallback exposes a provider specific
+ IProducerCallback exposes a provider specific
Session and MessageProducer pair.Provider messaging APIs typically expose two types of send
methods, one that takes delivery mode, priority, and time-to-live as
quality of service (QOS) parameters and one that takes no QOS parameters
which uses default values. Since there are many higher level send
- methods in NmsTemplate, the setting of the QOS
+ methods in NmsTemplate, the setting of the QOS
parameters have been exposed as properties on the template class to
avoid duplication in the number of send methods. Similarly, the timeout
value for synchronous receive calls is set using the property
- ReceiveTimeout.
+ ReceiveTimeout.Instances of the NmsTemplate class are
thread-safe once configured. This is important because it means that
you can configure a single instance of a
- NmsTemplate and then safely inject this shared
+ NmsTemplate and then safely inject this shared
reference into multiple collaborators. To be clear, the
- NmsTemplate is stateful, in that it maintains a
- reference to a ConnectionFactory, but this
+ NmsTemplate is stateful, in that it maintains a
+ reference to a ConnectionFactory, but this
state is not conversational state.
@@ -241,7 +258,7 @@
Connections
- The NmsTemplate requires a reference to a
+ The NmsTemplate requires a reference to a
ConnectionFactory. The ConnectionFactory serves as the entry point for
working with the provider's messaging API. It is used by the client
application as a factory to create connections to the messaging server
@@ -268,7 +285,7 @@
creating many intermediate objects. To send a message the following
'API' walk is performed
- IConnectionFactory->IConnection->ISession->IMessageProducer->Send
+ IConnectionFactory->IConnection->ISession->IMessageProducer->SendBetween the ConnectionFactory and the Send operation there are
three intermediate objects that are created and destroyed. To optimise
@@ -280,15 +297,15 @@
SingleConnectionFactory
- Spring.Messaging.Nms.Connections.SingleConnectionFactory
- will return the same connection on all calls to
+ Spring.Messaging.Nms.Connections.SingleConnectionFactory
+ will return the same connection on all calls to
CreateConnection and ignore calls to Close.CachingConnectionFactory
- Spring.Messaging.Nms.Connections.CachingConnectionFactory
+ Spring.Messaging.Nms.Connections.CachingConnectionFactory
extends the functionality of SingleConnectionFactory and adds the
caching of Sessions, MessageProducers, and MessageConsumers.
@@ -298,14 +315,14 @@
than that number as sessions are cached based on their acknowledgment
mode, so there can be up to 4 cached session instances when
SessionCacheSize is set to one, one for each
- AcknowledgementMode.
- MessageProducers and
- MessageConsumers are cached within their owning
+ AcknowledgementMode.
+ MessageProducers and
+ MessageConsumers are cached within their owning
session and also take into account the unique properties of the
producers and consumers when caching.
- MessageProducers are cached based on
- their destination. MessageConsumers are cached
+ MessageProducers are cached based on
+ their destination. MessageConsumers are cached
based on a key composed of the destination, selector, noLocal delivery
flag, and the durable subscription name (if creating durable
consumers).
@@ -323,7 +340,7 @@
administratively. You can use these vendor specific APIs to perform
dependency injection on references to JMS Destination objects in
Spring's XML configuration file by creating am implementation of
- IObjectFactory or alternatively configuring the
+ IObjectFactory or alternatively configuring the
specific concrete class implementation for a messaging provider.However, this approach of administered objects can be quite
@@ -332,12 +349,12 @@
unique to the messaging provider. Examples of such advanced destination
management would be the creation of dynamic destinations or support for
a hierarchical namespace of destinations. The
- NmsTemplate delegates the resolution of a
+ NmsTemplate delegates the resolution of a
destination name to a destination object by delegating to an
implementation of the interface
- IDestinationResolver.
- DynamicDestinationResolver is the default
- implementation used by NmsTemplate and
+ IDestinationResolver.
+ DynamicDestinationResolver is the default
+ implementation used by NmsTemplate and
accommodates resolving dynamic destinations.Quite often the destinations used in a messaging application are
@@ -353,16 +370,16 @@
dynamic destinations varies from provider to provider since the
properties associated with the destination are vendor specific. However,
a simple implementation choice that is sometimes made by vendors is to
- use the TopicSession method
+ use the TopicSession method
CreateTopic(string topicName) or the
- QueueSession method CreateQueue(string
- queueName) to create a new destination with default
+ QueueSession method CreateQueue(string
+ queueName) to create a new destination with default
destination properties. Depending on the vendor implementation,
- DynamicDestinationResolver may then also create a
+ DynamicDestinationResolver may then also create a
physical destination instead of only resolving one.The boolean property PubSubDomain is used to
- configure the NmsTemplate with knowledge of what
+ configure the NmsTemplate with knowledge of what
messaging 'domain' is being used. By default the value of this property
is false, indicating that the point-to-point domain, Queues, will be
used. This property is infrequently used as the provider messaging APIs
@@ -370,10 +387,10 @@
referring to 'Destinations' rather than 'Queues' or 'Topics'. However,
this property does influence the behavior of dynamic destination
resolution via implementations of the
- IDestinationResolver interface.
+ IDestinationResolver interface.You can also configure the NmsTemplate with a default destination
- via the property DefaultDestination. The default
+ via the property DefaultDestination. The default
destination will be used with send and receive operations that do not
refer to a specific destination.
@@ -384,7 +401,7 @@
One of the most common uses of JMS is to concurrently process
messages delivered asynchronously. A message listener container is used
to receive messages from a message queue and drive the
- IMessageListener that is injected into it. The
+ IMessageListener that is injected into it. The
listener container is responsible for all threading of message reception
and dispatches into the listener for processing. A message listener
container is the intermediary between an Message-Driven PONO (MDP) and a
@@ -396,11 +413,11 @@
infrastructure concerns to the framework.A subclass of
- AbstractMessageListenerContainer is used to
+ AbstractMessageListenerContainer is used to
receive messages from JMS and drive the Message-Driven PONOs (MDPs) that
are injected into it. There are one subclasses of
- AbstractMessageListenerContainer packaged with
- Spring - SimpleMessageListenerContainer.
+ AbstractMessageListenerContainer packaged with
+ Spring - SimpleMessageListenerContainer.
Additional subclasses, in particular to participate in distributed
transactions (if the provider supports it), will be provided in future
releases. SimpleMessageListenerContainer creates a fixed number of JMS
@@ -415,13 +432,13 @@
manages transactions for a single ConnectionFactory. This allows
messaging applications to leverage the managed transaction features of
Spring as described in . The
- NmsTransactionManager performs local resource
+ NmsTransactionManager performs local resource
transactions, binding a Connection/Session pair from the specified
- ConnectionFactory to the thread. NmsTemplate
+ ConnectionFactory to the thread. NmsTemplate
automatically detects such transactional resources and operates on them
accordingly.
- Using Spring's SingleConnectionFactory will
+ Using Spring's SingleConnectionFactory will
result in a shared Connection, with each transaction having its own
independent Session.
@@ -430,7 +447,7 @@
Sending a Message
- The NmsTemplate contains three convenience
+ The NmsTemplate contains three convenience
methods to send a message. The methods are listed below.
@@ -453,20 +470,20 @@
The method differ in how the destination is specified. In first case
the JMS Destination object is specified directly. The second case
specifies the destination using a string that is then resolved to a
- messaging Destination object using the
- IDestinationResolver associated with the template.
+ messaging Destination object using the
+ IDestinationResolver associated with the template.
The last method sends the message to the destination specified by
- NmsTemplate''s
- DefaultDestination property.
+ NmsTemplate''s
+ DefaultDestination property.All methods take as an argument an instance of
- IMessageCreator which defines the API contract for
+ IMessageCreator which defines the API contract for
you to create the JMS message. The interface is show below
- public interface IMessageCreator {
+ public interface IMessageCreator {
IMessage CreateMessage(ISession session);
}Intermediate Sessions and MessageProducers needed to send
- the message are managed by NmsTemplate. The session
+ the message are managed by NmsTemplate. The session
passed in to the method is never null. There is a similar set methods that
use a delegate instead of the interface, which can be convenient when
writing small implementation in .NET 2.0 using anonymous delegates.
@@ -492,7 +509,7 @@
The declaration of the delegate is
- public delegate IMessage MessageCreatorDelegate(ISession session);
+ public delegate IMessage MessageCreatorDelegate(ISession session);The following class shows how to use the SendWithDelegate method
with an anonymous delegate to create a MapMessage from the supplied
@@ -501,7 +518,7 @@
NmsTemplate is constructed by passing a reference to a
ConnectionFactory.
- public class SimplePublisher
+ public class SimplePublisher
{
private NmsTemplate template;
@@ -537,15 +554,15 @@
Using MessageConvertersIn order to facilitate the sending of domain model objects, the
- NmsTemplate has various send methods that take a
+ NmsTemplate has various send methods that take a
.NET object as an argument for a message's data content. The overloaded
- methods ConvertAndSend and
- ReceiveAndConvert in
- NmsTemplate delegate the conversion process to an
- instance of the IMessageConverter
+ methods ConvertAndSend and
+ ReceiveAndConvert in
+ NmsTemplate delegate the conversion process to an
+ instance of the IMessageConverter
interface. This interface defines a simple contract to convert between
.NET objects and JMS messages. The default implementation
- SimpleMessageConverter supports conversion
+ SimpleMessageConverter supports conversion
between String and TextMessage, byte[] and BytesMesssage, and
System.Collections.IDictionary and MapMessage. By using the converter,
you and your application code can focus on the business object that is
@@ -556,7 +573,7 @@
converts objects to an XML string and vice-versa for sending via a
TextMessage.
- The family of ConvertAndSend messages are
+ The family of ConvertAndSend messages are
similar to that of the Send method with the additional argument of type
IMessagePostProcessor. These methods are listed below.
@@ -594,7 +611,7 @@
The example below uses the default message converter to send a
Hashtable as a message to the destination "APP.STOCK".
- public void PublishUsingDict(string ticker, double price)
+ public void PublishUsingDict(string ticker, double price)
{
IDictionary marketData = new Hashtable();
marketData.Add("TICKER", ticker);
@@ -602,12 +619,12 @@
template.ConvertAndSend("APP.STOCK.MARKETDATA", marketData);
}To accommodate the setting of message's properties, headers,
and body that can not be generally encapsulated inside a converter
- class, the IMessageConverterPostProcessor
+ class, the IMessageConverterPostProcessor
interface gives you access to the message after it has been converted
but before it is sent. The example below demonstrates how to modify a
message header and a property after a Hashtable is converted to a
message using the IMessagePostProcessor. The methods
- ConvertAndSendUsingDelegate allow for the use of
+ ConvertAndSendUsingDelegate allow for the use of
a delegate to perform message post processing. This family of methods is
listed below
@@ -632,11 +649,11 @@
The declaration of the delegate is
- public delegate IMessage MessagePostProcessorDelegate(IMessage message);
+ public delegate IMessage MessagePostProcessorDelegate(IMessage message);The following code shows this in action.
- public void PublishUsingDict(string ticker, double price)
+ public void PublishUsingDict(string ticker, double price)
{
IDictionary marketData = new Hashtable();
marketData.Add("TICKER", ticker);
@@ -685,12 +702,12 @@
Where ISessionCallback and IProducerCallback are
- public interface IProducerCallback
+ public interface IProducerCallback
{
object DoInJms(Session session, MessageProducer producer);
}and
- public interface ISessionCallback
+ public interface ISessionCallback
{
object DoInJms(Session session);
}
@@ -698,7 +715,7 @@
The delegate signatures are listed below and mirror the interface
method signature
- public delegate object SessionDelegate(ISession session);
+ public delegate object SessionDelegate(ISession session);
public delegate object ProducerDelegate(ISession session, IMessageProducer producer);
@@ -712,12 +729,12 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
While messaging middleware is typically associated with
asynchronous processing, it is possible to consume messages
synchronously. The overloaded Receive(..) methods on
- NmsTemplate provide this functionality. During a
+ NmsTemplate provide this functionality. During a
synchronous receive, the calling thread blocks until a message becomes
available. This can be a dangerous operation since the calling thread
can potentially be blocked indefinitely. The property
ReceiveTimeout on
- NmsTemplate specifies how long the receiver
+ NmsTemplate specifies how long the receiver
should wait before giving up waiting for a message.The Receive methods are listed
@@ -757,14 +774,14 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
The Receive method without arguments will
use the DefaultDestination. The
ReceiveSelected methods apply the provided
- message selector string to the MessageConsumer
+ message selector string to the MessageConsumer
that is created.The ReceiveAndConvert methods apply the
template's message converter when receiving a message. The message
converter to use is set using the property
- MessageConverter and is the
- SimpleMessageConverter implementation by default.
+ MessageConverter and is the
+ SimpleMessageConverter implementation by default.
These methods are listed below.
@@ -807,7 +824,7 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
such as the IMessageListener interface shown below, taken from the TIBCO
EMS provider.
- public interface IMessageListener
+ public interface IMessageListener
{
void OnMessage(Message message);
}
@@ -816,14 +833,14 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
callback or even both a delegate and interface options. Apache ActiveMQ
supports only the use of delegates for message reception callbacks. As a
programming convenience in
- Spring.Messaging.Nms.Core is an interface
- IMessageListener that can be used with
+ Spring.Messaging.Nms.Core is an interface
+ IMessageListener that can be used with
NMS.
Below is a simple implementation of the IMessageListener interface
that processing a message.
- using Spring.Messaging.Nms.Core;
+ using Spring.Messaging.Nms.Core;
using Apache.NMS;
using Common.Logging;
@@ -862,15 +879,15 @@ namespace MyApp
specifies various messaging configuration parameters, such as the
ConnectionFactory, and the number of concurrent consumers to create.
There is an abstract base class for message listener containers,
- AbstractMessageListenerContainer, and one
+ AbstractMessageListenerContainer, and one
concrete implementation,
- SimpleMessageListenerContainer.
- SimpleMessageListenerContainer creates a fixed
+ SimpleMessageListenerContainer.
+ SimpleMessageListenerContainer creates a fixed
number of JMS Sessions/MessageConsumer pairs as set by the property
ConcurrentConsumers. Here is a sample
configuration
-
+
<object id="ConnectionFactory" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ">
<constructor-arg index="0" value="tcp://localhost:61616"/>
</object>
@@ -895,14 +912,14 @@ namespace MyApp
via the properties SubscriptionDurable and
DurableSubscriptionName. You may also register an
exception listener using the property
- ExceptionListener.
+ ExceptionListener.
A custom schema to create the
- SimpleMessageListener container is also provided.
+ SimpleMessageListener container is also provided.
Using this schema the configuration above looks like the
following
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:nms="http://www.springframework.net/nms">
<!-- other object definitions -->
@@ -913,35 +930,35 @@ namespace MyApp
</objects>Exceptions that are thrown during message processing can be passed
- to an implementation of IExceptionHandler and
+ to an implementation of IExceptionHandler and
registered with the container via the property
- ExceptionListener. The registered
- IExceptionHandler will be invoked if the
- exception is of the type NMSException (or the
+ ExceptionListener. The registered
+ IExceptionHandler will be invoked if the
+ exception is of the type NMSException (or the
equivalent root exception type for other providers). The
SimpleMessageListenerContainer will logs the exception at error level
and not propagate the exception to the provider. All handling of
acknowledgement and/or transactions is done by the listener container.
You can override the method
- HandleListenerException to change this
+ HandleListenerException to change this
behavior.Please refer to the Spring SDK documentation for additional
description of the features and properties of
- SimpleMessageListenerContainer.
+ SimpleMessageListenerContainer.
The ISessionAwareMessageListener interface
- The ISessionAwareMessageListener interface
+ The ISessionAwareMessageListener interface
is a Spring-specific interface that provides a similar contract to the
- messaging provider's IMessageListener interface
+ messaging provider's IMessageListener interface
or Listener delegate/event, but also provides the message handling
method with access to the Session from which the Message was
received.
- public interface ISessionAwareMessageListener
+ public interface ISessionAwareMessageListener
{
void OnMessage(IMessage message, ISession session);
}
@@ -950,7 +967,7 @@ namespace MyApp
with the message listener container
-
+ MessageListenerAdapaterThe MessageListenerAdapter class is the final component in
@@ -960,15 +977,15 @@ namespace MyApp
Consider the following interface definition. Notice that although
the interface extends neither the
- IMessageListener nor
- ISessionAwareMessageListener interfaces, it can
+ IMessageListener nor
+ ISessionAwareMessageListener interfaces, it can
still be used as a Message-Driven PONOs (MDP) via the use of the
- MessageListenerAdapter class. Notice also how the
+ MessageListenerAdapter class. Notice also how the
various message handling methods are strongly typed according to the
contents of the various Message types that they can receive and
handle.
- public interface MessageHandler {
+ public interface MessageHandler {
void HandleMessage(string message);
@@ -980,7 +997,7 @@ namespace MyApp
and a class that implements this interface...
- public class DefaultMessageHandler : IMessageHandler {
+ public class DefaultMessageHandler : IMessageHandler {
// stub implementations elided for bevity...
}
@@ -989,16 +1006,16 @@ namespace MyApp
messaging provider API dependencies at all. It truly is a PONO that we
will make into an MDP via the following configuration.
- <object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/>
+ <object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/>
<object id="MessageListenerAdapter" type="Spring.Messaging.Nms.Listener.Adapter.MessageListenerAdapter, Spring.Messaging.Nms">
- <property name="HandlerObject" ref="MessagleHandler"/>
+ <property name="HandlerObject" ref="MessagleHandler"/>
</object>
<object id="MessageListenerContainer" type="Spring.Messaging.Nms.Listener.SimpleMessageListenerContainer, Spring.Messaging.Nms">
<property name="ConnectionFactory" ref="ConnectionFactory"/>
<property name="DestinationName" value="APP.REQUEST"/>
- <property name="MessageListener" ref="MessageListenerAdapter"/>
+ <property name="MessageListener" ref="MessageListenerAdapter"/>
</object>The previous examples relies on the fact that the default
@@ -1015,23 +1032,23 @@ namespace MyApp
'Receive(..)' method is strongly typed to receive and respond only to
NMS ITextMessage messages.
- public interface TextMessageHandler {
+ public interface TextMessageHandler {
void Receive(ITextMessage message);
}
- public class TextMessageHandler implements ITextMessageHandler {
+ public class TextMessageHandler implements ITextMessageHandler {
// implementation elided for clarity...
}The configuration of the attendant
- MessageListenerAdapter would look like
+ MessageListenerAdapter would look like
this
- <object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/>
+ <object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/>
<object id="MessageListenerAdapter" type="Spring.Messaging.Nms.Listener.Adapter.MessageListenerAdapter, Spring.Messaging.Nms">
- <property name="HandlerObject" ref="TextMessagleHandler"/>
+ <property name="HandlerObject" ref="TextMessagleHandler"/>
<property name="DefaultHandlerMethod" value="Receive"/>
<!-- we don't want automatic message context extraction -->
<property name="MessageConverter">
@@ -1041,18 +1058,18 @@ namespace MyApp
Please note that if the above 'MessageListener' receives a Message
of a type other than ITextMessage, a
- ListenerExecutionFailedException will be thrown
+ ListenerExecutionFailedException will be thrown
(and subsequently handled by the container by logging the
exception).
- If your IMessageConverter implementation
+ If your IMessageConverter implementation
will return multiple object types, overloading the handler method is
perfectly acceptable, the most specific matching method will be used. A
method with an object signature would be consider a 'catch-all' method
of last resort. For example, you can have an handler interface as shown
below.
- public interface IMyHandler
+ public interface IMyHandler
{
void DoWork(string text);
void DoWork(OrderRequest orderRequest);
@@ -1068,7 +1085,7 @@ namespace MyApp
property of the original Message (if one exists) , or the default
Destination set on the MessageListenerAdapter (if one has been
configured). If no Destination is found then an
- InvalidDestinationException will be thrown (and
+ InvalidDestinationException will be thrown (and
please note that this exception will not be swallowed and will propagate
up the call stack).
@@ -1076,7 +1093,7 @@ namespace MyApp
that supports multiple object types and has return values is shown
below.
- public interface IMyHandler
+ public interface IMyHandler
{
string DoWork(string text);
OrderResponse DoWork(OrderRequest orderRequest);
@@ -1120,7 +1137,7 @@ namespace MyApp
more <listener/> child elements. Here is an example of a basic
configuration for two listeners.
- <nms:listener-container>
+ <nms:listener-container>
<nms:listener destination="queue.orders" ref="OrderService" method="PlaceOrder"/>
@@ -1166,7 +1183,7 @@ namespace MyApp
role="bold">(required)
The destination name for this listener, resolved
- through the IDestinationResolver
+ through the IDestinationResolver
strategy.
@@ -1182,8 +1199,8 @@ namespace MyApp
The name of the handler method to invoke. If the
ref points to a
- IMessageListener or Spring
- ISessionAwareMessageListener,
+ IMessageListener or Spring
+ ISessionAwareMessageListener,
this attribute may be omitted.
@@ -1234,7 +1251,7 @@ namespace MyApp
to define highly-customized listener containers while still benefiting
from the convenience of the namespace.
- <jms:listener-container connection-factory="MyConnectionFactory"
+ <jms:listener-container connection-factory="MyConnectionFactory"
destination-resolver="MyDestinationResolver"
concurrency="10">
@@ -1246,8 +1263,8 @@ namespace MyApp
The following table describes all available attributes. Consult
the class-level SDK documentation of the
- AbstractMessageListenerContainer and its subclass
- SimpleMessageListenerContainer for more detail on
+ AbstractMessageListenerContainer and its subclass
+ SimpleMessageListenerContainer for more detail on
the individual properties.
@@ -1272,7 +1289,7 @@ namespace MyApp
connection-factoryA reference to the NMS
- ConnectionFactory object (the
+ ConnectionFactory object (the
default object name is
'ConnectionFactory').
@@ -1281,18 +1298,18 @@ namespace MyApp
destination-resolverA reference to the
- IDestinationResolver strategy for
+ IDestinationResolver strategy for
resolving JMS
- Destinations.
+ Destinations.
message-converterA reference to the
- IMessageConverter strategy for
+ IMessageConverter strategy for
converting NMS Messages to listener method arguments. Default is
- a SimpleMessageConverter.
+ a SimpleMessageConverter.
@@ -1319,7 +1336,7 @@ namespace MyApp
auto, client,
dups-ok or transacted. A
value of transacted activates a locally
- transacted Session. As an
+ transacted Session. As an
alternative, specify the transaction-manager
attribute described below. Default is
auto.
diff --git a/doc/reference/src/migration.xml b/doc/reference/src/migration.xml
index 15e714bf..383d4736 100644
--- a/doc/reference/src/migration.xml
+++ b/doc/reference/src/migration.xml
@@ -1,8 +1,25 @@
-
+
+Migrating from 1.1 M2
-
+ IntroductionSeveral API changes were made after 1.1 M2 (before 1.1 RC1)due
@@ -19,7 +36,7 @@
and higher
-
+ Important ChangesThis section covers the common areas were you will need to make
@@ -35,39 +52,39 @@
The names of the section handlers to register custom schemas has
changed, from ConfigParsersSectionHandler to
- NamespaceParsersSectionHandler.
+ NamespaceParsersSectionHandler.The target namespaces have changed, the 'directory' named /schema/
has been removed. For example, the target schema changed from
http://www.springframework.net/schema/tx to
- http://www.springframework.net/tx.
+ http://www.springframework.net/tx.A typical declaration to use custom schemas within your
configuration file looks like this
- <objects xmlns='http://www.springframework.net'
+ <objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database"
xmlns:tx="http://www.springframework.net/tx"
xmlns:aop="http://www.springframework.net/aop">
- The class XmlParserRegistry was renamed to
- NamespaceParserRegistry.
+ The class XmlParserRegistry was renamed to
+ NamespaceParserRegistry.Renamed
- Spring.Validation.ValidationConfigParser to
- Spring.Validation.Config.ValidationNamespaceParser
+ Spring.Validation.ValidationConfigParser to
+ Spring.Validation.Config.ValidationNamespaceParser
- Renamed from DatabaseConfigParser to
- DatabaseNamespaceParser
+ Renamed from DatabaseConfigParser to
+ DatabaseNamespaceParser
- Renamed/Moved Remoting.RemotingConfigParser
+ Renamed/Moved Remoting.RemotingConfigParser
to
- Remoting.Config.RemotingNamespaceParser
+ Remoting.Config.RemotingNamespaceParserA typical registration of custom parsers within your configuration
file looks like this
- <configuration>
+ <configuration>
<configSections>
<sectionGroup name="spring">
@@ -85,7 +102,7 @@
A manual registration would look like this
- NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
+ NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));
diff --git a/doc/reference/src/misc.xml b/doc/reference/src/misc.xml
index 2dd0779a..77546dca 100644
--- a/doc/reference/src/misc.xml
+++ b/doc/reference/src/misc.xml
@@ -1,4 +1,22 @@
-
+
+
+Spring.NET miscellaneaIntroduction
@@ -23,12 +41,10 @@
features.
To do the match, you use the method:
-
-tatic bool Match(string pattern, string path)
+ static bool Match(string pattern, string path)If you want to decide if case is important or not use the method:
-
-tatic bool Match(string pattern, string path, bool ignoreCase)
+ static bool Match(string pattern, string path, bool ignoreCase)General rules
@@ -60,35 +76,29 @@ tatic bool Match(string pattern, string path, bool ignoreCase)
A file name can be matched using the following
notation:
-
-foo?bar.*
+ foo?bar.*
matches:
-
-fooAbar.txt
+ fooAbar.txt
foo1bar.txt
foo_bar.txt
foo-bar.txt
does not match:
-
-foo.bar.txt
+ foo.bar.txt
foo/bar.txt
foo\bar.txt
The classical all files pattern:
-
-*.*
+ *.*
matches:
-
-foo.db
+ foo.db
.db
foo
foo.bar.db
foo.db.db
db.db.db
does not match:
-
-c:/
+ c:/
c:/foo.db
c:/foo
c:/.db
@@ -102,48 +112,39 @@ c:/foo.foo.db
A directory name can be matched at any depth level using the following
notation:
-
-**/db/**
+ **/db/**
That pattern matches the following paths:
-
-/db
+ /db
//server/db
c:/db
c:/spring/app/db/foo.db
//Program Files/App/spaced dir/db/foo.db
/home/spring/spaced dir/db/v1/foo.db
but does not match these:
-
-c:/spring/app/db-v1/foo.db
+ c:/spring/app/db-v1/foo.db
/home/spring/spaced dir/db-v1/foo.db
You can compose subdirectories to match like this:
-
-**/bin/**/tmp/**
+ **/bin/**/tmp/**
That pattern matches the following paths:
-
-c:/spring/foo/bin/bar/tmp/a
+ c:/spring/foo/bin/bar/tmp/a
c:/spring/foo/bin/tmp/a/b.c
but does not match these:
-
-c:/spring/foo/bin/bar/temp/a
+ c:/spring/foo/bin/bar/temp/a
c:/tmp/foo/bin/bar/a/b.c
You can use more advanced patterns:
-
-**/.spring-assemblies*/**
+ **/.spring-assemblies*/**
matches:
-
-c:/.spring-assemblies
+ c:/.spring-assemblies
c:/.spring-assembliesabcd73xs
c:/app/.spring-assembliesabcd73xs
c:/app/.spring-assembliesabcd73xs/foo.dll
//server/app/.spring-assembliesabcd73xs
does not match:
-
-c:/app/.spring-assemblie
+ c:/app/.spring-assemblie
@@ -153,14 +154,11 @@ c:/app/.spring-assemblie
.NET is expected to be a cross-platform development ... platform. So,
PathMatcher will match taking care of the case of the pattern
and the case of the path. For example:
-
-**/db/**/*.DB
+ **/db/**/*.DB
matches:
-
-c:/spring/service/deploy/app/db/foo.DB
+ c:/spring/service/deploy/app/db/foo.DB
but does not match:
-
-c:/spring/service/deploy/app/DB/foo.DB
+ c:/spring/service/deploy/app/DB/foo.DB
c:spring/service/deploy/app/spaced dir/DB/foo.DB
//server/share/service/deploy/app/DB/backup/foo.db
@@ -169,11 +167,9 @@ c:spring/service/deploy/app/spaced dir/DB/foo.DB
Back and forward slashes, in the very same cross-platform spirit, are
not important:
-
-spring/foo.bar
+ spring/foo.bar
matches all the following paths:
-
-c:\spring\foo.bar
+ c:\spring\foo.bar
c:/spring\foo.bar
c:/spring/foo.bar
/spring/foo.bar
diff --git a/doc/reference/src/msmq.xml b/doc/reference/src/msmq.xml
index 842a1696..2d7dc409 100644
--- a/doc/reference/src/msmq.xml
+++ b/doc/reference/src/msmq.xml
@@ -1,5 +1,22 @@
-
+
+Message Oriented Middleware - MSMQ
@@ -29,29 +46,29 @@
reference to a particular middleware technology. Spring provides the
'adapter' classes that converts between the middleware world, in this case
MSMQ, and the oo-world of your business processing. This is done through
- the use of Spring's MessageListenerAdapter class
- and IMessageConverters.
+ the use of Spring's MessageListenerAdapter class
+ and IMessageConverters.
The namespace Spring.Messaging provides the core
functionality for messaging. It contains the class
- MessageQueueTemplate that simplifies the use of
- System.Messaging.MessageQueue by handling the lack
+ MessageQueueTemplate that simplifies the use of
+ System.Messaging.MessageQueue by handling the lack
of thread-safety in most of
System.Messaging.MessageQueue's methods (for example
Send). A single instance of
- MessageQueueTemplate can be used throughout your
+ MessageQueueTemplate can be used throughout your
application and Spring will ensure that a different instance of a
- MessageQueue class is used per thread when using
- MessageQueueTemplate's methods. This per-thread
- instance of a System.Messaging.MessageQueue is also
- available via its property MessageQueue. The
- MessageQueueTemplate class is also aware of the
+ MessageQueue class is used per thread when using
+ MessageQueueTemplate's methods. This per-thread
+ instance of a System.Messaging.MessageQueue is also
+ available via its property MessageQueue. The
+ MessageQueueTemplate class is also aware of the
presence of either an 'ambient' System.Transaction's
transaction or a local
- System.Messaging.MessageQueueTransaction. As such
- if you use MessageQueueTemplate's send and receive
+ System.Messaging.MessageQueueTransaction. As such
+ if you use MessageQueueTemplate's send and receive
methods, unlike with plain use of
- System.Messaging.MessageQueue, you do not need to
+ System.Messaging.MessageQueue, you do not need to
keep track of this information yourself and call the correct overloaded
System.Messaging.MessageQueue method for a specific
transaction environment. When using a
@@ -79,9 +96,9 @@
configuring message listener containers and
writing a callback function for message processing.
On the sending side, it involves you learning how to use
- MessageQueueTemplate. In both cases you will quite
+ MessageQueueTemplate. In both cases you will quite
likely want to take advantage of using
- MessageListenerConverters so you can better
+ MessageListenerConverters so you can better
structure the translation from the System.Messaging.Message data structure
to your business objects. After the initial learning hurdle, you should
find that you will be much more productive leveraging Spring's helper
@@ -103,12 +120,12 @@
demonstrated).On the client side you create an instance of the
- MessageQueueTemplate class and configure it to use
- a MessageQueue. This can be done programmatically
+ MessageQueueTemplate class and configure it to use
+ a MessageQueue. This can be done programmatically
but it is common to use dependency injection and Spring's XML
configuration file to configure your client class as shown below.
- <object id='questionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
+ <object id='questionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
<property name='Path' value='.\Private$\questionTxQueue'/>
<property name='MessageReadPropertyFilterSetAll' value='true'/>
</object>
@@ -117,20 +134,20 @@
<property name="MessageQueueObjectName" value="questionTxQueue"/>
</object>
- <!-- Class you write -->
+ <!-- Class you write -->
<object id="questionService" type="MyNamespace.QuestionService, MyAssembly">
<property name="MessageQueueTemplate" ref="messageQueueTemplate"/>
<object>
- The MessageQueue object is created via an
- instance of MessageQueueFactoryObject and the
- MessageQueueTemplate refers to this factory object
- by name and not by reference. The SimpleSender
+ The MessageQueue object is created via an
+ instance of MessageQueueFactoryObject and the
+ MessageQueueTemplate refers to this factory object
+ by name and not by reference. The SimpleSender
class looks like this
- public class QuestionService : IQuestionService
+ public class QuestionService : IQuestionService
{
private MessageQueueTemplate messageQueueTemplate;
@@ -146,52 +163,52 @@
}This class can be shared across multiple threads and the
- MessageQueueTemplate will take care of managing
+ MessageQueueTemplate will take care of managing
thread local access to a
- System.Messaging.MessageQueue as well as any
- System.Messaging.IMessageFormatter
+ System.Messaging.MessageQueue as well as any
+ System.Messaging.IMessageFormatter
instances.Furthermore, since this is a transactional queue (only the name
gives it away), the message will be sent using a single local messaging
transaction. The conversion from the string to the underling message is
- managed by an instance of the IMessageConverter
+ managed by an instance of the IMessageConverter
class. By default an implementation that uses an
- XmlMessageFormatter with a
- TargetType of System.String is
+ XmlMessageFormatter with a
+ TargetType of System.String is
used. You can configure the MessageQueueTemplate to use
- other IMessageConveter implementations that do
+ other IMessageConveter implementations that do
conversions above and beyond what the 'stock'
- IMessageFormatters do. See the section on
+ IMessageFormatters do. See the section on
MessageConverters for more details.On the receiving side we would like to consume the messages
transactionally from the queue. Since no other database operations are
being performed in our server side processing, we select the
- TransactionMessageListenerContainer and configure
- it to use the MessageQueueTransactionManager. The
- MessageQueueTransactionManager an implementation of
- Spring's IPlatformTransactionManager abstraction
+ TransactionMessageListenerContainer and configure
+ it to use the MessageQueueTransactionManager. The
+ MessageQueueTransactionManager an implementation of
+ Spring's IPlatformTransactionManager abstraction
that provides a uniform API on top of various transaction manager
(ADO.NET,NHibernate, MSMQ, etc). Spring's
- MessageQueueTransactionManager is responsible for
+ MessageQueueTransactionManager is responsible for
createing, committing, and rolling back a MSMQ
- MessageQueueTransaction.
+ MessageQueueTransaction.While you can create the message listener container
programmatically, we will show the declarative configuration approach
below
- <!-- Queue to receive from -->
+ <!-- Queue to receive from -->
<object id='questionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
<property name='Path' value='.\Private$\questionTxQueue'/>
<property name='MessageReadPropertyFilterSetAll' value='true'/>
</object>
- <!-- MSMQ Transaction Manager -->
+ <!-- MSMQ Transaction Manager -->
<object id="messageQueueTransactionManager" type="Spring.Messaging.Core.MessageQueueTransactionManager, Spring.Messaging"/>
- <!-- Message Listener Container that uses MSMQ transactional for receives -->
+ <!-- Message Listener Container that uses MSMQ transactional for receives -->
<object id="transactionalMessageListenerContainer" type="Spring.Messaging.Listener.TransactionalMessageListenerContainer, Spring.Messaging">
<property name="MessageQueueObjectName" value="questionTxQueue"/>
<property name="PlatformTransactionManager" ref="messageQueueTransactionManager"/>
@@ -199,23 +216,23 @@
<property name="MessageListener" ref="messageListenerAdapter"/>
</object>
- <!-- Adapter to call a PONO as a messaging callback -->
+ <!-- Adapter to call a PONO as a messaging callback -->
<object id="messageListenerAdapter" type="Spring.Messaging.Listener.MessageListenerAdapter, Spring.Messaging">
<property name="HandlerObject" ref="questionHandler"/>
</object>
- <!-- The PONO class that you write -->
+ <!-- The PONO class that you write -->
<object id="questionHandler" type="MyNamespace.QuestionHandler, MyAssembly"/>
We have specified the queue to listen, that we want to consume the
messages transactionally, process messages from the queue using 10
threads, and that our plain object that will handle the business
- processing is of the type QuestionHandler. The only
- class you need to write, QuestionHandler, looks
+ processing is of the type QuestionHandler. The only
+ class you need to write, QuestionHandler, looks
like
- public class QuestionHandler : IQuestionHandler
+ public class QuestionHandler : IQuestionHandler
{
public void HandleObject(string question)
{
@@ -230,7 +247,7 @@
}That is general idea. You write the sender class using
- MessageQueueTemplate and the consumer class which
+ MessageQueueTemplate and the consumer class which
does not refer to any messaging specific class. The rest is configuration
of Spring provided helper classes.
@@ -254,7 +271,7 @@
In the last part this 'quick tour' we will configure the message
listener container to handle poison messages. This is done by creating an
- instance of SendToQueueExceptionHandler and setting
+ instance of SendToQueueExceptionHandler and setting
the property MaxRetry to be the number of exceptions or
retry attempts we are willing to tolerate before taking corrective
actions. In this case, the corrective action is to send the message to
@@ -263,22 +280,21 @@
you will avoid automated processing of these messages and take manual
corrective actions.
-
- <!-- The 'error' queue to send poison messages -->
+
+ <!-- The 'error' queue to send poison messages -->
<object id='errorQuestionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
<property name='Path' value='.\Private$\errorQuestionTxQueue'/>
<property name='MessageReadPropertyFilterSetAll' value='true'/>
</object>
- <!-- Message Listener Container that uses MSMQ transactional for receives -->
+ <!-- Message Listener Container that uses MSMQ transactional for receives -->
<object id="transactionalMessageListenerContainer" type="Spring.Messaging.Listener.TransactionalMessageListenerContainer, Spring.Messaging">
- <!-- as before but adding -->
-
+ <!-- as before but adding -->
<property name="MessageTransactionExceptionHandler" ref="messageTransactionExceptionHandler"/>
</object>
- <!-- Poison message handling policy -->
+ <!-- Poison message handling policy -->
<object id="messageTransactionExceptionHandler" type="Spring.Messaging.Listener.SendToQueueExceptionHandler, Spring.Messaging">
<property name="MaxRetry" value="5"/>
<property name="MessageQueueObjectName" value="errorQuestionTxQueue"/>
@@ -292,8 +308,8 @@
it from the queue questionTxQueue). You can also specify that certain
exceptions should commit the transaction (remove from the queue) but this
is not shown here ,see below for more informatio non this functionality
- The SendToQueueExceptionHandler implements the
- interface IMessageTransactionExceptionHandler
+ The SendToQueueExceptionHandler implements the
+ interface IMessageTransactionExceptionHandler
(discussed below) so you can write your own implementations should the
provided ones not meet your needs.
@@ -318,12 +334,12 @@
the MessageQueue class is available via
MessageQueueTemplate's property
MessageQueue. A
- MessageQueueTemplate is created by passing a
+ MessageQueueTemplate is created by passing a
reference to the name of a
- MessageQueueFactoryObject, you can think of it as
- a friendly name for your MessagingQueue and the
+ MessageQueueFactoryObject, you can think of it as
+ a friendly name for your MessagingQueue and the
recipe of how to create an instance of it. See the following section on
- MessageQueueFactoryObject for more
+ MessageQueueFactoryObject for more
information.
The MessageQueueTemplate also provides several
@@ -337,25 +353,25 @@
given to the template's associated IMessageConverter
implementation. This can be set using the property
MessageConverter. The default implementation,
- XmlMessageConverter, uses an
- XmlMessageFormatter with its
+ XmlMessageConverter, uses an
+ XmlMessageFormatter with its
TargetType set to
- System.String. Note that
- System.Messaging.IMessageFormatter classes are
- also not thread safe, so MessageQueueTemplate
+ System.String. Note that
+ System.Messaging.IMessageFormatter classes are
+ also not thread safe, so MessageQueueTemplate
ensures that thread-local instances of
- IMessageConverter are used (as they generally
- wrap IMessageFormatter's that are not
+ IMessageConverter are used (as they generally
+ wrap IMessageFormatter's that are not
thread-safe).You can use the MessageQueueTemplate to send
messages to other MessageQueues by specifying their queue 'object name',
- the name of the MessageQueueFactoryObject.
+ the name of the MessageQueueFactoryObject.
The family of overloaded ConvertAndSend and
ReceiveAndConvert methods are shown below
- void ConvertAndSend(object obj);
+ void ConvertAndSend(object obj);
void ConvertAndSend(object obj, MessagePostProcessorDelegate messagePostProcessorDelegate);
@@ -368,20 +384,20 @@ object ReceiveAndConvert();
object ReceiveAndConvert(string messageQueueObjectName);The transactional settings of the underlying overloaded
- System.Messaging.MessageQueue Send method that
+ System.Messaging.MessageQueue Send method that
are used are based on the following algorithm. If the message queue is
transactional and there is an ambient
- MessageQueueTransaction in thread local storage
+ MessageQueueTransaction in thread local storage
(put there via the use of Spring's
- MessageQueueTransactionManager or
- TransactionalMessageListenerContainer), the
+ MessageQueueTransactionManager or
+ TransactionalMessageListenerContainer), the
message will be sent transactionally using the
- MessageQueueTransaction object in thread local
+ MessageQueueTransaction object in thread local
storage. This lets you group together multiple messaging operations
within the same transaction without having to explicitly pass around the
- MessageQueueTransaction object. If the message
+ MessageQueueTransaction object. If the message
queue is transactional but there is no ambient
- MessageQueueTransaction, then a single message
+ MessageQueueTransaction, then a single message
transaction is created on each messaging operation.
(MessageQueueTransactionType = Single). If there is an ambient
System.Transactions transaction then that transaction will be used
@@ -389,26 +405,26 @@ object ReceiveAndConvert(string messageQueueObjectName);
transactional, then a non-transactional send
(MessageQueueTransactionType = None) is used.
- The delegate MessagePostProcessorDelegate
+ The delegate MessagePostProcessorDelegate
has the following signature
- public delegate Message MessagePostProcessorDelegate(Message message);
+ public delegate Message MessagePostProcessorDelegate(Message message);This lets you modify the message after it has been converted from
and object to a message using the
- IMessageConverter but before it is sent. This is
- useful for setting Message properties (e.g.
+ IMessageConverter but before it is sent. This is
+ useful for setting Message properties (e.g.
CorrelationId, AppSpecific,
TimeToReachQueue). Using anonymous delegates in .NET
2.0 makes this a very succinct coding task. If you have elaborate
properties that need to be set, perhaps creating a custom
- IMessageConverter would be appropriate.
+ IMessageConverter would be appropriate.Overloaded Send and Receive
operations that use the algorithm listed above to set transactional
delivery options are also available. These are listed below
- Message Receive();
+ Message Receive();
Message Receive(string messageQueueObjectName);
@@ -419,16 +435,16 @@ void Send(string messageQueueObjectName, Message message);
void Send(MessageQueue messageQueue, Message message);Note that in the last Send method that takes a
- MessageQueue instance, it is the callers
+ MessageQueue instance, it is the callers
responsibility to ensure that this instance is not accessed from
multiple threads. This Send method is commonly used
- when getting the MessageQueue from the
+ when getting the MessageQueue from the
ResponseQueue property of a
- Message during an asynchronous receive process.
+ Message during an asynchronous receive process.
The receive timeout of the Receive operations is set
using the ReceiveTimeout property of
- MessageQueueTemplate. The default value is
- MessageQueue.InfiniteTimeout (which is actually
+ MessageQueueTemplate. The default value is
+ MessageQueue.InfiniteTimeout (which is actually
~3 months).The XML configuration snippit for defining a MessageQueueTemplate
@@ -439,53 +455,53 @@ void Send(MessageQueue messageQueue, Message message);MessageQueueFactoryObject
- The MessageQueueFactoryObject is
- responsible for creating MessageQueue instances.
+ The MessageQueueFactoryObject is
+ responsible for creating MessageQueue instances.
You configure the factory with some basic information, namely the
constructor parameters you are familiar with already when creating a
- standard MessageQueue instance, and then setting
- MessageQueue properties, such a Label etc. Some
- configuration tasks of a MessageQueue involve
+ standard MessageQueue instance, and then setting
+ MessageQueue properties, such a Label etc. Some
+ configuration tasks of a MessageQueue involve
calling methods, for example to set which properties of the message to
read. These available as properties to set on the
- MessageQueueFactoryObject. An example declarative
+ MessageQueueFactoryObject. An example declarative
configuration is shown below
- <object id='testqueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
- <!-- propeties passed to the MessageQueue constructor -->
+ <object id='testqueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
+ <!-- propeties passed to the MessageQueue constructor -->
<property name='Path' value='.\Private$\testqueue'/>
<property name='DenySharedReceive' value='true'/>
<property name='AccessMode' value='Receive'/>
<property name='EnableCache' value='true'/>
- <!-- properties that call configuration methods on the MessageQueue -->
+ <!-- properties that call configuration methods on the MessageQueue -->
<property name='MessageReadPropertyFilterSetAll' value='true'/>
<property name='ProductTemplate'>
<object>
<property name='Label' value='MyLabel'/>
- <!-- other MessageQueue properties can be set here -->
+ <!-- other MessageQueue properties can be set here -->
</object>
</property>
</object>Whenever an object reference is made to 'testqueue' an new
- instance of the MessageQueue class is created.
+ instance of the MessageQueue class is created.
This Spring's so-called 'prototype' model, which differs from
'singleton' mode. In the singleton creation mode whenever an object
reference is made to a 'testqueue' the same
- MessageQueue instance would be used. So that a
+ MessageQueue instance would be used. So that a
new instance can be retrieved based on need, the message listener
containers take as an argument the name of the
- MessageQueueFactoryObject and not a reference.
+ MessageQueueFactoryObject and not a reference.
(i.e. use of 'value' instead of 'ref' in the XML).
- The MessageQueueFactoryObject class is an
+ The MessageQueueFactoryObject class is an
ideal candidate for use of a custom namespace. This will be provided
in the future. This will allow you to use VS.NET IntelliSense to
configure this commonly used object. An example of the potential
syntax is shown below
- <mq:messageQueue id="testqueue" path=".\Private$\testqueue" MessageReadPropertyFilterSetAll="true">
+ <mq:messageQueue id="testqueue" path=".\Private$\testqueue" MessageReadPropertyFilterSetAll="true">
<mq:properties label="MyLabel"/>
</mq:messageQueue>
@@ -494,21 +510,21 @@ void Send(MessageQueue messageQueue, Message message);MessageQueue and IMessageConverter resource management
- MessageQueues and
- IMessageFormatters (commonly used in
- IMessageConverter implementations) are not
+ MessageQueues and
+ IMessageFormatters (commonly used in
+ IMessageConverter implementations) are not
thread-safe. For example, only the following methods on
- MessageQueue are thread-safe,
+ MessageQueue are thread-safe,
BeginPeek, BeginReceive,
EndPeek, EndReceive,
GetAllMessages, Peek, and
Receive.To isolate the creation logic of these classes, the factory
- interface IMessageQueueFactory is used. The
+ interface IMessageQueueFactory is used. The
interface is shown below
- public interface IMessageQueueFactory
+ public interface IMessageQueueFactory
{
MessageQueue CreateMessageQueue(string messageQueueObjectName);
@@ -516,26 +532,26 @@ void Send(MessageQueue messageQueue, Message message);
}A provided implementation,
- DefaultMessageQueueFactory will create an
+ DefaultMessageQueueFactory will create an
instance of each class per-thread. It delegates the creation of the
- MessageQueue instance to the Spring container.
+ MessageQueue instance to the Spring container.
The argument, messageConverterObjectName, must be the id/name of a
- MessageQueueFactoryObject defined in the Spring
+ MessageQueueFactoryObject defined in the Spring
container.
- DefaultMessageQueueFactory leverages
+ DefaultMessageQueueFactory leverages
Spring's local thread storage support so it will work correctly in stand
alone and web applications.
- You can use the DefaultMessageQueueFactory
+ You can use the DefaultMessageQueueFactory
independent of the rest of Spring's MSMQ support should you need only
- the functionality it offers. MessageQueueTemplate
+ the functionality it offers. MessageQueueTemplate
and the listener containers create an instance of
- DefaultMessageQueueFactory by default. Should you
+ DefaultMessageQueueFactory by default. Should you
want to share the same instance across these two classes, or provide
your own custom implementation, use the property
- MessageQueueFactory on either
- MessageQueueTemplate or the message listener
+ MessageQueueFactory on either
+ MessageQueueTemplate or the message listener
classe.s
@@ -545,8 +561,8 @@ void Send(MessageQueue messageQueue, Message message);One of the most common uses of MSMQ is to concurrently process
messages delivered asynchronously. This support is provided in Spring by
message listener containers. A message listener container is the
- intermediary between an IMessageListener and a
- MessageQueue. (Note, message listener containers
+ intermediary between an IMessageListener and a
+ MessageQueue. (Note, message listener containers
are conceptually different than Spring's Inversion of Control container,
though it integrates and leverages the IoC container.) The message
listener container takes care of registering to receive messages,
@@ -557,26 +573,26 @@ void Send(MessageQueue messageQueue, Message message);
boilerplate MSMQ infrastructure concerns to the framework.
A subclass of
- AbstractMessageListenerContainer is used to
- receive messages from a MessageQueue. Which
+ AbstractMessageListenerContainer is used to
+ receive messages from a MessageQueue. Which
subclass you pick depends on your transaction processing requirements.
The following subclasses are available in the namespace
Spring.Messaging.Listener
- NonTransactionalMessageListenerContainer
+ NonTransactionalMessageListenerContainer
- does not surround the receive operation with a transaction
- TransactionalMessageListenerContainer -
+ TransactionalMessageListenerContainer -
surrounds the receive operation with local (non-DTC) based
transaction(s).
- DistributedTxMessageListenerContainer -
+ DistributedTxMessageListenerContainer -
surrounds the receive operation with a distributed (DTC)
transaction
@@ -604,25 +620,25 @@ void Send(MessageQueue messageQueue, Message message);NonTransactionalMessageListenerContainerThis container performs a Receive operation on the
- MessageQueue without any transactional
+ MessageQueue without any transactional
settings. As such messages will not be redelivered if an exception is
thrown during message processing. Exceptions during message processing
can be handled via an implementation of the interface
- IExceptionHandler. This can be set via the
+ IExceptionHandler. This can be set via the
property ExceptionHandler on the listener. The
IExceptionHandler interface is shown below
- public interface IExceptionHandler
+ public interface IExceptionHandler
{
void OnException(Exception exception, Message message);
}An example of configuring a
- NonTransactionalMessageListenerContainer with
- an IExceptionHandler is shown below
+ NonTransactionalMessageListenerContainer with
+ an IExceptionHandler is shown below
-
- <!-- Queue to receive from -->
+
+ <!-- Queue to receive from -->
<object id='msmqTestQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
<property name='Path' value='.\Private$\testqueue'/>
<property name='MessageReadPropertyFilterSetAll' value='true'/>
@@ -633,7 +649,7 @@ void Send(MessageQueue messageQueue, Message message);
</property>
</object>
- <!-- Queue to respond to -->
+ <!-- Queue to respond to -->
<object id='msmqTestResponseQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
<property name='Path' value='.\Private$\testresponsequeue'/>
<property name='MessageReadPropertyFilterSetAll' value='true'/>
@@ -644,7 +660,7 @@ void Send(MessageQueue messageQueue, Message message);
</property>
</object>
- <!-- Listener container -->
+ <!-- Listener container -->
<object id="nonTransactionalMessageListenerContainer" type="Spring.Messaging.Listener.NonTransactionalMessageListenerContainer, Spring.Messaging">
<property name="MessageQueueObjectName" value="msmqTestQueue"/>
<property name="MaxConcurrentListeners" value="2"/>
@@ -653,13 +669,13 @@ void Send(MessageQueue messageQueue, Message message);
<property name="ExceptionHandler" ref="exceptionHandler"/>
</object>
- <!-- Delegate to plain .NET object for message handling -->
+ <!-- Delegate to plain .NET object for message handling -->
<object id="messageListenerAdapter" type="Spring.Messaging.Listener.MessageListenerAdapter, Spring.Messaging">
<property name="DefaultResponseQueueName" value="msmqTestResponseQueue"/>
<property name="HandlerObject" ref="simpleHandler"/>
</object>
- <!-- Classes you need to write -->
+ <!-- Classes you need to write -->
<object id="simpleHandler" type="MyNamespace.SimpleHandler, MyAssembly"/>
<object id="exceptionHandler" type="MyNamespace.SimpleExceptionHandler, MyAssembly"/>
@@ -667,7 +683,7 @@ void Send(MessageQueue messageQueue, Message message);The SimpleHandler class would look something like this
- public class SimpleHandler : ISimpleHandler
+ public class SimpleHandler : ISimpleHandler
{
public void HandleObject(string txt)
{
@@ -683,38 +699,38 @@ void Send(MessageQueue messageQueue, Message message);This message listener container performs receive operations
within the context of local transaction. This class requires an
instance of Spring's
- IPlatformTransactionManager, either
- AdoPlatformTransactionManager,
- HibernateTransactionManager, or
- MessageQueueTransactionManager.
+ IPlatformTransactionManager, either
+ AdoPlatformTransactionManager,
+ HibernateTransactionManager, or
+ MessageQueueTransactionManager.
If you specify a
- MessageQueueTransactionManager then a
- MessageQueueTransaction will be started before
+ MessageQueueTransactionManager then a
+ MessageQueueTransaction will be started before
receiving the message and used as part of the container's receive
operation. As with other
- IPlatformTransactionManager implementation's,
+ IPlatformTransactionManager implementation's,
the transactional resources (in this case an instance of the
- MessageQueueTransaction class) is bound to
- thread local storage. MessageQueueTemplate will
+ MessageQueueTransaction class) is bound to
+ thread local storage. MessageQueueTemplate will
look in thread-local storage and use this 'ambient' transaction if
found for its send and receive operations. The message listener is
invoked and if no exception occurs, then the
- MessageQueueTransactionManager will commit the
- MessageQueueTransaction.
+ MessageQueueTransactionManager will commit the
+ MessageQueueTransaction.
The message listener implementation can call into service layer
classes that are made transactional using standard Spring declarative
transactional techniques. In case of exceptions in the service layer,
the database operation will be rolled back (nothing new here), and the
- TransactionalMessageListenerContainer will call
- it's IMessageTransactionExceptionHandler
+ TransactionalMessageListenerContainer will call
+ it's IMessageTransactionExceptionHandler
implementation to determine if the
- MessageQueueTransaction should commit (removing
+ MessageQueueTransaction should commit (removing
the message from the queue) or rollback (leaving the message on the
queue for redelivery).The use of a transactional service layer in combination with
- a MessageQueueTransactionManager is a
+ a MessageQueueTransactionManager is a
powerful combination that can be used to achieve "exactly one"
transaction message processing with database operations. This
requires a little extra programming effort and is a more efficient
@@ -738,16 +754,16 @@ void Send(MessageQueue messageQueue, Message message);
exception type and vote to commit (remove from the queue) the
'outer' messaging transaction. Spring provides an exception
handler with this functionality, see
- SendToQueueExceptionHandler described
+ SendToQueueExceptionHandler described
below.
An example of configuring the
- TransactionalMessageListenerContainer using a
+ TransactionalMessageListenerContainer using a
MessageQueueTransactionManager is shown
below
- <!-- Queue to receive from -->
+ <!-- Queue to receive from -->
<object id='msmqTestQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
<property name='Path' value='.\Private$\testqueue'/>
<property name='MessageReadPropertyFilterSetAll' value='true'/>
@@ -758,7 +774,7 @@ void Send(MessageQueue messageQueue, Message message);
</property>
</object>
- <!-- Queue to respond to -->
+ <!-- Queue to respond to -->
<object id='msmqTestResponseQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
<property name='Path' value='.\Private$\testresponsequeue'/>
<property name='MessageReadPropertyFilterSetAll' value='true'/>
@@ -769,7 +785,7 @@ void Send(MessageQueue messageQueue, Message message);
</property>
</object>
- <!-- Transaction Manager for MSMQ Messaging -->
+ <!-- Transaction Manager for MSMQ Messaging -->
<object id="messageQueueTransactionManager" type="Spring.Messaging.Core.MessageQueueTransactionManager, Spring.Messaging"/>
<!-- The transaction message listener container -->
@@ -782,47 +798,47 @@ void Send(MessageQueue messageQueue, Message message);
<property name="MessageTransactionExceptionHandler" ref="messageTransactionExceptionHandler"/>
</object>
- <!-- Delegate to plain .NET object for message handling -->
+ <!-- Delegate to plain .NET object for message handling -->
<object id="messageListenerAdapter" type="Spring.Messaging.Listener.MessageListenerAdapter, Spring.Messaging">
<property name="DefaultResponseQueueName" value="msmqTestResponseQueue"/>
<property name="HandlerObject" ref="simpleHandler"/>
</object>
- <!-- Poison message handling -->
+ <!-- Poison message handling -->
<object id="messageTransactionExceptionHandler" type="Spring.Messaging.Listener.SendToQueueExceptionHandler, Spring.Messaging">
<property name="MaxRetry" value="5"/>
<property name="MessageQueueObjectName" value="testTxErrorQueue"/>
</object>
- <!-- Classes you need to write -->
+ <!-- Classes you need to write -->
<object id="simpleHandler" type="MyNamespace.SimpleHandler, MyAssembly"/>
If you specify either
- AdoPlatformTransactionManager or
- HibernateTransactionManager then a local
+ AdoPlatformTransactionManager or
+ HibernateTransactionManager then a local
database transaction will be started before the receiving the message.
By default, the container will also start a local
- MessageQueueTransaction after the local
+ MessageQueueTransaction after the local
database transaction has started, but before the receiving the
- message. This MessageQueueTransaction will be
+ message. This MessageQueueTransaction will be
used to receive the message. By default the
- MessageQueueTransaction will be bound to thread
- local storage so that any MessageQueueTemplate
+ MessageQueueTransaction will be bound to thread
+ local storage so that any MessageQueueTemplate
send or receive operations will participate transparently in the same
- MessageQueueTransaction. If you do not want
+ MessageQueueTransaction. If you do not want
this behavior set the property
ExposeContainerManagedMessageQueueTransaction to
false.In case of exceptions during IMessageListener
processing when using either either
- AdoPlatformTransactionManager or
- HibernateTransactionManager the container's
- IMessageTransactionExceptionHandler will
- determine if the MessageQueueTransaction should
+ AdoPlatformTransactionManager or
+ HibernateTransactionManager the container's
+ IMessageTransactionExceptionHandler will
+ determine if the MessageQueueTransaction should
commit (removing it from the queue) or rollback (placing it back on
the queue for redelivery). The listener exception will always trigger
a rollback in the 'outer' database transaction.
@@ -830,10 +846,10 @@ void Send(MessageQueue messageQueue, Message message);Poison message handing, that is, the endless redelivery of a
message due to exceptions during processing, can be detected using
implementations of the
- IMessageTransactionExceptionHandler. This
+ IMessageTransactionExceptionHandler. This
interface is shown below
- public interface IMessageTransactionExceptionHandler
+ public interface IMessageTransactionExceptionHandler
{
TransactionAction OnException(Exception exception, Message message, MessageQueueTransaction messageQueueTransaction);
}
@@ -842,21 +858,21 @@ void Send(MessageQueue messageQueue, Message message);Commit and Rollback. A specific
implementation is provided that will move the poison message to
another queue after a maximum number of redelivery attempts. See
- SendToQueueExceptionHandler described below.
+ SendToQueueExceptionHandler described below.
You can set a specific implementation to by setting
- TransactionalMessageListenerContainer's
+ TransactionalMessageListenerContainer's
property
- MessageTransactionExceptionHandler
+ MessageTransactionExceptionHandlerThe IMessageTransactionExceptionHandler
- implementation SendToQueueExceptionHandler
+ implementation SendToQueueExceptionHandler
keeps track of the Message's Id property in memory
with a count of how many times an exception has occurred. If that
count is greater than the handler's MaxRetry count
it will be sent to another queue using the provided
- MessageQueueTransaction. The queue to send the
+ MessageQueueTransaction. The queue to send the
message to is specified via the property
- MessageQueueObjectName.
+ MessageQueueObjectName.
@@ -878,10 +894,10 @@ void Send(MessageQueue messageQueue, Message message);Exceptions in message listener processing are handled by
implementations of the
- IDistributedTransactionExceptionHandler
+ IDistributedTransactionExceptionHandler
interface. This interface is shown below
- public interface IDistributedTransactionExceptionHandler
+ public interface IDistributedTransactionExceptionHandler
{
bool IsPoisonMessage(Message message);
@@ -899,13 +915,13 @@ void Send(MessageQueue messageQueue, Message message);
Typical implementations of HandlePoisonMessage will
move the poison message to another queue (under the same distributed
transaction used to receive the message). The class
- SendToQueueDistributedTransactionExceptionHandler
+ SendToQueueDistributedTransactionExceptionHandler
detects poison messages by tracking the Message Id
property in memory with a count of how many times an exception has
occurred. If that count is greater than the handler's
MaxRetry count it will be sent to another queue.
The queue to send the message to is specified via the property
- MessageQueueObjectName.
+ MessageQueueObjectName.
@@ -917,15 +933,15 @@ void Send(MessageQueue messageQueue, Message message);Using MessageConvertersIn order to facilitate the sending of business model objects, the
- MessageQueueTemplate has various send methods
+ MessageQueueTemplate has various send methods
that take a .NET object as an argument for a message's data content. The
overloaded methods ConvertAndSend and ReceiveAndConvert in
- MessageQueue delegate the conversion process to
- an instance of the IMessageConverter
+ MessageQueue delegate the conversion process to
+ an instance of the IMessageConverter
interface. This interface defines a simple contract to convert between
.NET objects and JMS messages. The interface is shown below
- public interface IMessageConverter : ICloneable
+ public interface IMessageConverter : ICloneable
{
Message ToMessage(object obj);
@@ -933,36 +949,36 @@ void Send(MessageQueue messageQueue, Message message);
}There are a standard implementations provided the simply wrap
- existing IMessageFormatter
+ existing IMessageFormatter
implementations.
- XmlMessageConverter - uses a
+ XmlMessageConverter - uses a
XmlMessageFormatter.
- BinaryMessageConverter - uses a
+ BinaryMessageConverter - uses a
BinaryMessageFormatter
- ActiveXMessageConverter - uses a
+ ActiveXMessageConverter - uses a
ActiveXMessageFormatterThe default implementation used in
- MessageQueueTemplate and the message listener
+ MessageQueueTemplate and the message listener
containers is an instance of XmlMessageConverter configured with a
TargetType to be System.String. You specify the types that the
XmlMessageConverter can convert though either the array property
- TargetTypes or
- TargetTypeNames. Here is an example taken from
+ TargetTypes or
+ TargetTypeNames. Here is an example taken from
the QuickStart application
- <object id="xmlMessageConverter" type="Spring.Messaging.Support.Converters.XmlMessageConverter, Spring.Messaging">
+ <object id="xmlMessageConverter" type="Spring.Messaging.Support.Converters.XmlMessageConverter, Spring.Messaging">
<property name="TargetTypes">
<list>
<value>Spring.MsmqQuickStart.Common.Data.TradeRequest, Spring.MsmqQuickStart.Common</value>
@@ -972,17 +988,17 @@ void Send(MessageQueue messageQueue, Message message);
</property>
</object>
- You can specify other IMessageConverter
+ You can specify other IMessageConverter
implementations using the
- MessageConverterObjectName property on the
- MessageQueueTemplate and
- MessageListenerAdapter.
+ MessageConverterObjectName property on the
+ MessageQueueTemplate and
+ MessageListenerAdapter. Other implementations provided are
- XmlDocumentConverter - loads and saves
+ XmlDocumentConverter - loads and saves
an XmlDocument to the message BodyStream. This lets you manipulate
directly the XML data independent of type serialization issues. This
is quite useful if you use XPath expressions to pick out the
@@ -1022,20 +1038,20 @@ void Send(MessageQueue messageQueue, Message message);
MessageListenerAdapater
- The MessageListenerAdapter allows methods
+ The MessageListenerAdapter allows methods
of a class that does not implement the
- IMessageListener interface to be invoked upon
+ IMessageListener interface to be invoked upon
message delivery. Lets call this class the 'message handler' class. To
- achieve this goal the MessageListenerAdapter
- implements the standard IMessageListener
+ achieve this goal the MessageListenerAdapter
+ implements the standard IMessageListener
interface to receive a message and then delegates the processing to
the message handler class. Since the message handler class does not
contain methods that refer to MSMQ artifacts such as Message, the
- MessageListenerAdapter uses a
- IMessageConverter to bridge the MSMQ and 'plain
+ MessageListenerAdapter uses a
+ IMessageConverter to bridge the MSMQ and 'plain
object' worlds. As a reminder, the default
- XmlMessageConverter used in
- MessageQueueTemplate and the message listener
+ XmlMessageConverter used in
+ MessageQueueTemplate and the message listener
containers converts from Message to string. Once the incoming message
is converted to an object (string for example) a method with the name
'HandleMessage' is invoked via reflection passing in the string as an
@@ -1045,7 +1061,7 @@ void Send(MessageQueue messageQueue, Message message);
message listeners, a simple string based message handler would look
like this.
- public class MyHandler
+ public class MyHandler
{
public void HandleMessage(string text)
@@ -1059,7 +1075,7 @@ void Send(MessageQueue messageQueue, Message message);
the handler method name has been changed to "DoWork", by setting the
adapter's property DefaultHandlerMethod.
- public interface IMyHandler
+ public interface IMyHandler
{
void DoWork(string text);
}
@@ -1070,7 +1086,7 @@ void Send(MessageQueue messageQueue, Message message);
object signature would be consider a 'catch-all' method of last
resort.
- public interface IMyHandler
+ public interface IMyHandler
{
void DoWork(string text);
void DoWork(OrderRequest orderRequest);
@@ -1079,24 +1095,24 @@ void Send(MessageQueue messageQueue, Message message);
}Another of the capabilities of the
- MessageListenerAdapter class is the ability to
- automatically send back a response Message if a
+ MessageListenerAdapter class is the ability to
+ automatically send back a response Message if a
handler method returns a non-void value. Any non-null value that is
returned from the execution of the handler method will (in the default
configuration) be converted to a string. The resulting string will
then be sent to the ResponseQueue defined in the
Message's ResponseQueue property of the original
Message, or the DefaultResponseQueueName on the
- MessageListenerAdapter (if one has been
+ MessageListenerAdapter (if one has been
configured) will be used. If not ResponseQueue is
- found then an Spring MessagingException will be
+ found then an Spring MessagingException will be
thrown. Please note that this exception will not be swallowed and will
propagate up the call stack.Here is an example of Handler signatures that have various
return types.
- public interface IMyHandler
+ public interface IMyHandler
{
string DoWork(string text);
OrderResponse DoWork(OrderRequest orderRequest);
@@ -1108,7 +1124,7 @@ void Send(MessageQueue messageQueue, Message message);
process incoming MSMQ messages using the default message converter.
- <!-- Delegate to plain .NET object for message handling -->
+ <!-- Delegate to plain .NET object for message handling -->
<object id="messageListenerAdapter" type="Spring.Messaging.Listener.MessageListenerAdapter, Spring.Messaging">
<property name="DefaultResponseQueueName" value="msmqTestResponseQueue"/>
<property name="HandlerObject" ref="myHandler"/>
diff --git a/doc/reference/src/navigation.xml b/doc/reference/src/navigation.xml
index 391d9f9c..85b12478 100644
--- a/doc/reference/src/navigation.xml
+++ b/doc/reference/src/navigation.xml
@@ -1,6 +1,24 @@
-
+
+
+Object Navigation
-
+ Introduction(Available in 1.0)Spring provides an expression language that allows for the easy setting
@@ -19,11 +37,11 @@
contained in the Spring.Web library uses this expression language.
-
+ Simple Expressions
Consider the simple class shown below with the
- public field Name
+ public field Name
public class Inventor
{
public string Name;
@@ -37,21 +55,21 @@ public class Inventor
}
which may have been instantiated in code somewhere and had its Name
- and DOB set to particular valuesInventor inventor = new Inventor();
+ and DOB set to particular valuesInventor inventor = new Inventor();
inventor.Name = "Nikola Tesla";
inventor.DOB = new DateTime(1854, 10, 9);
- The ObjectNavigator is the central
+ The ObjectNavigator is the central
class used to set or retrieve the value of an object, and contains
the following static methods
-
+
object GetValue(object root, string expression)
object GetValue(object root, NavigationExpression expression)
void SetValue(object root, string expression, object newValue)
void SetValue(object root, NavigationExpression expression, object newValue)
- To retrieve the name and year of birth we can use the following code
+ To retrieve the name and year of birth we can use the following code
string name = (string) ObjectNavigator.GetValue(inventor, "Name");
int year = (int) ObjectNavigator.GetValue(inventor, "DOB.Year");
@@ -61,13 +79,13 @@ int year = (int) ObjectNavigator.GetValue(inventor, "DOB.Year");
evaluate a complex expression frequently, creating a
NavigationExpression
and reusing it will increase performance. To set the property values of this
- object instance to that of another famous inventor we would write
+ object instance to that of another famous inventor we would write
ObjectNavigator.SetValue(inventor, "Name", "Michael Pupin");
ObjectNavigator.SetValue(inventor, "DOB", new DateTime(1854, 10, 9));
-
+ Navigating CollectionsTODO. TestCase shows some example usage. Please check the Spring.NET website for the latest updates to this document.
diff --git a/doc/reference/src/nms-quickstart.xml b/doc/reference/src/nms-quickstart.xml
index 17fcfe0f..c8db8f1a 100644
--- a/doc/reference/src/nms-quickstart.xml
+++ b/doc/reference/src/nms-quickstart.xml
@@ -1,5 +1,22 @@
-
+
+NMS QuickStart
@@ -58,51 +75,51 @@
Queues are shown in red and topics in green.
-
+ GatewaysGateways represent the service operation to send a message. The
client will send a stock request to the server based on the contract
- defined by the IStockService interface .
+ defined by the IStockService interface .
- public interface IStockService
+ public interface IStockService
{
void Send(TradeRequest tradeRequest);
}The server will send market data to the clients based on the
- contract defined by the IMarketDataService
+ contract defined by the IMarketDataService
interface.
- public interface IMarketDataService
+ public interface IMarketDataService
{
void SendMarketData();
}The market data gateway has no method parameters as it is assumed
that implementations will manage the data to send internally. The
- TradeRequest object is one of the data objects that
+ TradeRequest object is one of the data objects that
will be exchanged in the application and is discussed in the next
section.The use of interfaces allows for multiple implementations to be
created. Implementations that use messaging to communicate will be based
- on the Spring's NmsGateway class and will be
+ on the Spring's NmsGateway class and will be
discussed later. stub or mock implementations can be used for testing
purposes.
-
+ Message Data
- The TradeRequest object shown above contains
+ The TradeRequest object shown above contains
all the information required to process a stock order. To promote the
interoperability of this data across different platforms the
- TradeRequest class is generated from an XML Schema
+ TradeRequest class is generated from an XML Schema
using Microsoft's Schema Definition Tool (xsd.exe). The schema for trade
request is shown below
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://www.springframework.net/nms/common/2008-08-05">
<xs:element name="TradeRequest">
@@ -127,7 +144,7 @@
properties for each of the element names. A partial code listing of the
TradeRequest class is shown below
- // This code was generated by a tool.
+ // This code was generated by a tool.
public partial class TradeRequest {
public string Ticker {
@@ -152,16 +169,16 @@
}
- The schema and the TradeRequest class are
- located in the project Spring.NmsQuickStart.Common.
+ The schema and the TradeRequest class are
+ located in the project Spring.NmsQuickStart.Common.
This common project will be shared between the server and client for
convenience.When sending a response back to the client the type
- TradeResponse will be used. The schema for the
- TradeResponse is shown below
+ TradeResponse will be used. The schema for the
+ TradeResponse is shown below
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://www.springframework.net/nms/common/2008-08-05">
<xs:element name="TradeResponse">
@@ -179,10 +196,10 @@
</xs:schema>
- The TradeResponse type also generated from a
+ The TradeResponse type also generated from a
schema using xsd.exe. A partial code listing is shown below
- // This code was generated by a tool.
+ // This code was generated by a tool.
public partial class TradeResponse {
@@ -212,15 +229,15 @@
structure.
-
+ Message Handlers
- When the TradeRequest message is received by
+ When the TradeRequest message is received by
the server, it will be handled by the class
- Spring.NmsQuickStart.Server.Handlers.StockAppHandler
- shown below
+ Spring.NmsQuickStart.Server.Handlers.StockAppHandler
+ shown below
- public class StockAppHandler
+ public class StockAppHandler
{
private IExecutionVenueService executionVenueService;
@@ -260,7 +277,7 @@
client is the class Spring.NmsQuickStart.Client.Handlers.StockAppHandler
and is shown below.
- public class StockAppHandler
+ public class StockAppHandler
{
// definition of stockController omitted for brevity.
@@ -292,10 +309,10 @@
Message ConvertersThe implementation of IMessageConverter used is
- Spring.NmsQuickStart.Common.Converters.XmlMessageConverter.
+ Spring.NmsQuickStart.Common.Converters.XmlMessageConverter.
This converter adds the ability to marshal and unmarshal objects to and
from XML strings. It also uses Spring's
- SimpleMessageConverter to convert Hashtables,
+ SimpleMessageConverter to convert Hashtables,
strings, and byte arrays. In order to pass information about the
serialized type, type information is put in the message properties. The
type information can be either the class name or an integer value
@@ -305,7 +322,7 @@
The XML configuration used to configure these objects is shown
below
- <object name="XmlMessageConverter" type="Spring.NmsQuickStart.Common.Converters.XmlMessageConverter, Spring.NmsQuickStart.Common">
+ <object name="XmlMessageConverter" type="Spring.NmsQuickStart.Common.Converters.XmlMessageConverter, Spring.NmsQuickStart.Common">
<property name="TypeMapper" ref="TypeMapper"/>
</object>
@@ -323,11 +340,11 @@
Messaging InfrastructureThe implementations of the gateway interfaces inherit from Spring's
- helper class NmsGatewaySupport in order to get easy
+ helper class NmsGatewaySupport in order to get easy
access to a NmsTemplate for sending. The implementation of the
- IStockService interface is shown below
+ IStockService interface is shown below
- public class NmsStockServiceGateway : NmsGatewaySupport, IStockService
+ public class NmsStockServiceGateway : NmsGatewaySupport, IStockService
{
private IDestination defaultReplyToQueue;
@@ -347,7 +364,7 @@
}
}
- The Send method is using NmsTemplate's
+ The Send method is using NmsTemplate's
ConvertAndSendWithDelegate(object obj,
MessagePostProcessorDelegate messagePostProcessorDelegate)
method. The anonymous delegate allows you to modify the message
@@ -357,12 +374,13 @@
logic to the converted message.The object definition for the
- NmsStockServiceGateway is shown below along with
+ NmsStockServiceGateway is shown below along with
its dependent object definitions of NmsTemplate and the
ConnectionFactory.
- <object name="StockServiceGateway" type="Spring.NmsQuickStart.Client.Gateways.NmsStockServiceGateway, Spring.NmsQuickStart.Client">
- <property name="NmsTemplate" ref="NmsTemplate"/>
+
+ <object name="StockServiceGateway" type="Spring.NmsQuickStart.Client.Gateways.NmsStockServiceGateway, Spring.NmsQuickStart.Client">
+ <property name="NmsTemplate" ref="NmsTemplate"/>
<property name="DefaultReplyToQueue">
<object type="Apache.NMS.ActiveMQ.Commands.ActiveMQQueue, Apache.NMS.ActiveMQ">
<constructor-arg value="APP.STOCK.JOE"/>
@@ -370,32 +388,32 @@
</property>
</object>
- <object name="NmsTemplate" type="Spring.Messaging.Nms.Core.NmsTemplate, Spring.Messaging.Nms">
- <property name="ConnectionFactory" ref="ConnectionFactory"/>
+ <object name="NmsTemplate" type="Spring.Messaging.Nms.Core.NmsTemplate, Spring.Messaging.Nms">
+ <property name="ConnectionFactory" ref="ConnectionFactory"/>
<property name="DefaultDestinationName" value="APP.STOCK.REQUEST"/>
<property name="MessageConverter" ref="XmlMessageConverter"/>
</object>
- <object id="ConnectionFactory" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ">
+ <object id="ConnectionFactory" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ">
<constructor-arg index="0" value="tcp://localhost:61616"/>
</object>In this example the 'raw'
- Apache.NMS.ActiveMQ.ConnectionFactory connection
+ Apache.NMS.ActiveMQ.ConnectionFactory connection
factory was used. It would be more efficient resource wise to use Spring's
- CachingConnectionFactory wrapper class so that
+ CachingConnectionFactory wrapper class so that
connections will not be open and closed for each message send as well as
allowing for the caching of other intermediate NMS API objects such as
sessions and message producers.A similar configuration is used on the server to configure the class
- Spring.NmsQuickStart.Server.Gateways.MarketDataServiceGateway
- that implements the IMarketDataService
+ Spring.NmsQuickStart.Server.Gateways.MarketDataServiceGateway
+ that implements the IMarketDataService
interface.Since the client is also a consumer of messages, on the topic
APP.STOCK.MARKETDATA and the queue APP.STOCK.JOE (for Trader Joe!), two
message listener containers are defined as shown below.
- <nms:listener-container connection-factory="ConnectionFactory">
+ <nms:listener-container connection-factory="ConnectionFactory">
<nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.JOE" />
<nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.MARKETDATA" pubsub-domain="true"/>
</nms:listener-container>
@@ -410,7 +428,7 @@
APP.STOCK.REQUEST but set the concurrency property to 10 so that 10
threads will be consuming messages from the queue.
- <nms:listener-container connection-factory="ConnectionFactory" concurrency=" <nms:listener-container connection-factory="ConnectionFactory" concurrency="10">
<nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.REQUEST" />
</nms:listener-container>
diff --git a/doc/reference/src/objects-misc.xml b/doc/reference/src/objects-misc.xml
index 00a357ee..32fea0e2 100644
--- a/doc/reference/src/objects-misc.xml
+++ b/doc/reference/src/objects-misc.xml
@@ -1,50 +1,67 @@
-
+
+The IObjectWrapper and Type conversion
-
+ IntroductionThe concepts encapsulated by the
- IObjectWrapper interface are fundamental to the
+ IObjectWrapper interface are fundamental to the
workings of the core Spring.NET libraries The typical application
developer most probably will not ever have the need to use the
- IObjectWrapper directly... because this is
+ IObjectWrapper directly... because this is
reference documentation however, we felt that some explanation of this
- core interface might be right. The IObjectWrapper
+ core interface might be right. The IObjectWrapper
is explained in this chapter since if you were going to use it at all, you
would probably do that when trying to bind data to objects, which, nicely
enough, is precisely the area that the
- IObjectWrapper addresses.
+ IObjectWrapper addresses.
-
+ Manipulating objects using the IObjectWrapperOne quite important concept of the Spring.Objects
namespace is encapsulated in the definition
- IObjectWrapper interface and its corresponding
- implementation, the ObjectWrapper class. The
- functionality offered by the IObjectWrapper
+ IObjectWrapper interface and its corresponding
+ implementation, the ObjectWrapper class. The
+ functionality offered by the IObjectWrapper
includes methods to set and get property values (either individually or in
bulk), get property descriptors (instances of the
- System.Reflection.PropertyInfo class), and to query
+ System.Reflection.PropertyInfo class), and to query
the readability and writability of properties. The
- IObjectWrapper also offers support for nested
+ IObjectWrapper also offers support for nested
properties, enabling the setting of properties on subproperties to an
- unlimited depth. The IObjectWrapper usually isn't
+ unlimited depth. The IObjectWrapper usually isn't
used by application code directly, but by framework classes such as the
- various IObjectFactory implementations.
+ various IObjectFactory implementations.
- The way the IObjectWrapper works is partly
+ The way the IObjectWrapper works is partly
indicated by its name: it wraps an object to perform
actions on a wrapped object instance... such actions would include the
setting and getting of properties exposed on the wrapped object.Note: the concepts explained in this section are not
important to you if you're not planning to work with the
- IObjectWrapper directly.
+ IObjectWrapper directly.
-
+ Setting and getting basic and nested propertiesSetting and getting properties is done using the
@@ -59,7 +76,7 @@
GetPropertyValue() methods have a number of
conventions for indicating the path of a property. A property path is an
expression that implementations of the
- IObjectWrapper interface can use to look up the
+ IObjectWrapper interface can use to look up the
properties of the wrapped object; some examples of property paths
include...
@@ -109,8 +126,8 @@
Below you'll find some examples of working with the
- IObjectWrapper to get and set properties.
- Consider the following two classes: [C#]
+ IObjectWrapper to get and set properties.
+ Consider the following two classes: [C#]
public class Company
{
private string name;
@@ -127,7 +144,7 @@ public class Company
get { return this.managingDirector; }
set { this.managingDirector = value; }
}
-}[C#]
+}[C#]
public class Employee
{
private string name;
@@ -148,8 +165,8 @@ public class Employee
The following code snippets show some examples of how to retrieve
and manipulate some of the properties of
- IObjectWrapper-wrapped Company
- and Employee instances. [C#]
+ IObjectWrapper-wrapped Company
+ and Employee instances. [C#]
Company c = new Company();
IObjectWrapper owComp = new ObjectWrapper(c);
// setting the company name...
@@ -177,7 +194,7 @@ float salary = (float)owComp.GetPropertyValue("managingDirector.salary");
- [C#]
+ [C#]
// ok, let's create the director and bind it to the company...
Employee don = new Employee();
IObjectWrapper owDon = new ObjectWrapper(don);
@@ -197,7 +214,7 @@ Console.WriteLine(don.Salary); // puts 80000
practice.
-
+ Other features worth mentioningIn addition to the features described in the preceding sections
@@ -214,7 +231,7 @@ Console.WriteLine(don.Salary); // puts 80000
retrieving PropertyInfo instances:
using GetPropertyInfo(string) and
GetPropertyInfos() you can retrieve instances
- of the System.Reflection.PropertyInfo
+ of the System.Reflection.PropertyInfo
class, that might come in handy sometimes when you need access to
the property metadata specific to the object being wrapped.
@@ -222,19 +239,19 @@ Console.WriteLine(don.Salary); // puts 80000
-
+ Type conversion
- If you associate a TypeConverter with the
- definition of a custom Type using the standard .NET
+ If you associate a TypeConverter with the
+ definition of a custom Type using the standard .NET
mechanism (see the example code below), Spring.NET will use the associated
- TypeConverter to do the conversion.[C#]
+ TypeConverter to do the conversion.[C#]
[TypeConverter (typeof (FooTypeConverter))]
public class Foo
{
}
- The TypeConverter class from the
+ The TypeConverter class from the
System.ComponentModel namespace of the .NET BCL is used
extensively by the various classes in the Spring.Core
library, as said class ... provides a unified way of converting
@@ -249,36 +266,36 @@ public class Foo
For example, a date can be represented in a human readable format
(such as 30th August 1984), while we're still able to
convert the human readable form to the original date format or (even
- better) to an instance of the System.DateTime
+ better) to an instance of the System.DateTime
class. This behavior can be achieved by using the standard .NET idiom of
- decorating a class with the TypeConverterAttribute.
+ decorating a class with the TypeConverterAttribute.
Spring.NET also offers another means of associating a
- TypeConverters with a class. You might want to do
+ TypeConverters with a class. You might want to do
this to achieve a conversion that is not possible using standard idiom...
for example, the Spring.Core library contains a custom
- TypeConverter that converts comma-delimited strings
+ TypeConverter that converts comma-delimited strings
to String array instances. Registering custom converters on an
- IObjectWrapper instance gives the wrapper the
+ IObjectWrapper instance gives the wrapper the
knowledge of how to convert properties to the desired
- Type.
+ Type.An example of where property conversion is used in Spring.NET is the
setting of properties on objects, accomplished using the aforementioned
TypeConverters. When mentioning
- System.String as the value of a property of some
+ System.String as the value of a property of some
object (declared in an XML file for instance), Spring.NET will (if the
- type of the associated property is System.Type) use
- the RuntimeTypeConverter class to try to resolve
- the property value to a Type object. The example
+ type of the associated property is System.Type) use
+ the RuntimeTypeConverter class to try to resolve
+ the property value to a Type object. The example
below demonstrates this automatic conversion of the
Example.Xml.SAXParser (a string) into the corresponding
- Type instance for use in this factory-style class.
- <objects xmlns="http://www.springframework.net">
+ Type instance for use in this factory-style class.
+ <objects xmlns="http://www.springframework.net">
<object id="parserFactory" type="Example.XmlParserFactory, ExamplesLibrary"
destroy-method="Close">
<property name="ParserClass" value="Example.Xml.SAXParser, ExamplesLibrary"/>
</object>
-</objects>[C#]
+</objects>[C#]
public class XmlParserFactory
{
private Type parserClass;
@@ -295,35 +312,35 @@ public class XmlParserFactory
}
}
-
+ Type Conversion for EnumerationsThe default type converter for enumerations is the
- System.ComponentModel.EnumConverter class. To
+ System.ComponentModel.EnumConverter class. To
specify the value for an enumerated property, simply use the name of the
- property. For example the TestObject class has a
- property of the enumerated type FileMode. One of
+ property. For example the TestObject class has a
+ property of the enumerated type FileMode. One of
the values for this enumeration is named Create. The
following XML fragment shows how to configure this property
- <object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests">
+ <object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="name" value="Rod"/>
<property name="FileMode" value="Create"/>
</object>
-
+ Built-in TypeConvertersSpring.NET has a number of built-in
- TypeConverters to make life easy. Each of those is
+ TypeConverters to make life easy. Each of those is
listed below and they are all located in the
Spring.Objects.TypeConverters namespace of the
Spring.Core library.
- Built-in TypeConverters
+ Built-in TypeConverters
@@ -343,8 +360,8 @@ public class XmlParserFactory
RuntimeTypeConverterParses strings representing
- System.Types to actual
- System.Types and the other way
+ System.Types to actual
+ System.Types and the other way
around.
@@ -352,7 +369,7 @@ public class XmlParserFactory
FileInfoConverterCapable of resolving strings to a
- System.IO.FileInfo object.
+ System.IO.FileInfo object.
@@ -396,7 +413,7 @@ public class XmlParserFactory
Capable of resolving a two part string (resource name,
assembly name) to a
- System.Resources.ResourceManager
+ System.Resources.ResourceManager
object.
@@ -405,7 +422,7 @@ public class XmlParserFactory
Capable of resolving a comma separated list of Red,
Green, Blue integer values to a
- System.Drawing.Color structure.
+ System.Drawing.Color structure.
@@ -419,7 +436,7 @@ public class XmlParserFactory
Spring.NET uses the standard .NET mechanisms for the resolution of
- System.Types, including, but not limited to
+ System.Types, including, but not limited to
checking any configuration files associated with your application,
checking the Global Assembly Cache (GAC), and assembly probing.
diff --git a/doc/reference/src/objects.xml b/doc/reference/src/objects.xml
index 6f4f866c..a7f02cc1 100644
--- a/doc/reference/src/objects.xml
+++ b/doc/reference/src/objects.xml
@@ -1,8 +1,25 @@
-
+
+The IoC container
-
+ IntroductionThis chapter covers the Spring Framework's implementation of the
@@ -12,34 +29,34 @@
principleThe Spring.Core assembly provides the basis for
- the Spring.NET Inversion of Control container. The IObjectFactory
+ the Spring.NET Inversion of Control container. The IObjectFactory
interface provides an advanced configuration mechanism capable of managing
- objects of any nature. The IApplicationContext
- interface builds on top of the IObjectFactory (it
+ objects of any nature. The IApplicationContext
+ interface builds on top of the IObjectFactory (it
is a sub-interface) and adds other functionality such as easier
integration with Spring.NET's Aspect Oriented Programming (AOP) features,
message resource handling (for use in internationalization), event
propagation and application layer-specific context such as
- WebApplicationContext for use in web
+ WebApplicationContext for use in web
applications.
- In short, the IObjectFactory provides the
+ In short, the IObjectFactory provides the
configuration framework and basic functionality, while the
- IApplicationContext adds more enterprise-centric
- functionality to it. The IApplicationContext is a
- complete superset of the IObjectFactory, and any
- description of IObjectFactory capabilities and
+ IApplicationContext adds more enterprise-centric
+ functionality to it. The IApplicationContext is a
+ complete superset of the IObjectFactory, and any
+ description of IObjectFactory capabilities and
behavior should be considered to apply to
IApplicationContexts as well.This chapter is divided into two parts, with the first part covering the basic principles
- that apply to both the IObjectFactory and
- IApplicationContext, with the IObjectFactory and
+ IApplicationContext, with the second part covering those features
- that apply only to the IApplicationContext
+ that apply only to the IApplicationContext
interface.If you are new to Spring.NET or IoC containers in general, you may
@@ -52,13 +69,13 @@
will fill in all the fine detail.
-
+ Basics - containers and objects
-
+ The container
- The IObjectFactory is the actual
+ The IObjectFactory is the actual
representation of the Spring IoC container that is responsible for
instantiating, configuring, and managing a number of objects.
@@ -68,19 +85,19 @@
and assembling the dependencies between these objects.There are a number of implementations of the
- IObjectFactory interface that come supplied
+ IObjectFactory interface that come supplied
straight out-of-the-box with Spring. The most commonly used
- IObjectFactory implementation is the
- XmlObjectFactory class. This implementation
+ IObjectFactory implementation is the
+ XmlObjectFactory class. This implementation
allows you to express the objects that compose your application, and the
doubtless rich interdependencies between such objects, in terms of XML.
- The XmlObjectFactory takes this XML configuration
+ The XmlObjectFactory takes this XML configuration
metadata and uses it to create a fully configured system or application.
- Interaction with the IObjectFactory interface is
+ Interaction with the IObjectFactory interface is
discussed in . Additional
features offered by another implementation of
- IObjectFactory, the
- IApplicationContext, are discussed in section
+ IObjectFactory, the
+ IApplicationContext, are discussed in section
.
@@ -89,7 +106,7 @@
-
+ Configuration metadataAs can be seen in the above image, the Spring IoC container
@@ -146,12 +163,12 @@
-
+ Instantiating a containerInstantiating a Spring IoC container is straightforward.
- IApplicationContext context = new XmlApplicationContext(
+ IApplicationContext context = new XmlApplicationContext(
"file://services.xml",
"assembly://MyAssembly/MyDataAccess/data-access.xml");
@@ -165,14 +182,14 @@ IObjectFactory factory = context;
ASP.NET pages.
You may be wondering what the assembly URL is all about. The above
- example uses Spring.NET's IResource
- abstraction. The IResource interface
+ abstraction. The IResource interface
provides a simple and uniform interface to a wide array of IO resources
that can represent themselves as
- System.IO.Stream. An example for a file based
+ System.IO.Stream. An example for a file based
resource, not using the URL syntax but an implementation of the
- IResource interface for file is shown below.[C#]
+ IResource interface for file is shown below.[C#]
IResource input = new FileSystemResource ("objects.xml");
IObjectFactory factory = new XmlObjectFactory(input);
@@ -188,17 +205,17 @@ IObjectFactory factory = new XmlObjectFactory(input);assembly://<AssemblyName>/<NameSpace>/<ResourceName>
To create an embedded resource using Visual Studio you must set the Build Action of the .xml configuration file to Embedded Resource in the file property editor. Also, you will need to explicitly rebuild the project containing the configuration file if it is the only change you make between successive builds. If using NAnt to build, add a <resources> section to the csc task. For example usage, look at the Spring.Core.Tests.build file included the distribution.
- The IResource abstraction is explained
+ The IResource abstraction is explained
further in .
The preferred way to create an
- IApplicationContext or
- IObjectFactory is to use a custom configuration
+ IApplicationContext or
+ IObjectFactory is to use a custom configuration
section in the standard .NET application configuration file (one of
App.config or Web.config). A
custom configuration section that creates the same
- IApplicationContext as the previous example is
- <spring>
+ IApplicationContext as the previous example is
+ <spring>
<context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
<resource uri="file://services.xml"/>
<resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/>
@@ -206,9 +223,9 @@ IObjectFactory factory = new XmlObjectFactory(input);
</spring> The context type (specified as the value of
the type attribute of the context
element) is wholly optional, and defaults to the
- Spring.Context.Support.XmlApplicationContext
+ Spring.Context.Support.XmlApplicationContext
class, so the following XML snippet is functionally equivalent to the
- first. <spring>
+ first. <spring>
<context>
<resource uri="file://services.xml"/>
<resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/>
@@ -216,18 +233,18 @@ IObjectFactory factory = new XmlObjectFactory(input);
</spring> To acquire a reference to an
- IApplicationContext using a custom configuration
- section, one simply uses the following code; IApplicationContext ctx = ContextRegistry.GetContext();
- The ContextRegistry is used to both instantiate
+ IApplicationContext using a custom configuration
+ section, one simply uses the following code; IApplicationContext ctx = ContextRegistry.GetContext();
+ The ContextRegistry is used to both instantiate
the application context and to perform service locator style access to
other objects. (See for more
information). The glue that makes this possible is an implementation of
the Base Class Library (BCL) provided
- IConfigurationSectionHandler interface, namely
- the Spring.Context.Support.ContextHandler class.
+ IConfigurationSectionHandler interface, namely
+ the Spring.Context.Support.ContextHandler class.
The handler class needs to be registered in the
configSections section of the .NET configuration file
- as shown below. <configSections>
+ as shown below. <configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
</sectionGroup>
@@ -237,9 +254,9 @@ IObjectFactory factory = new XmlObjectFactory(input);In some usage scenarios, user code will not have to explicitly
instantiate an appropriate implementation of the
- IObjectFactory interface, since Spring.NET code
+ IObjectFactory interface, since Spring.NET code
will do it. For example, the ASP.NET web layer provides support code to
- load a Spring.NET IApplicationContext
+ load a Spring.NET IApplicationContext
automatically as part of the normal startup process of an ASP.NET web
application. Similar support for WinForms applications is being
investigated.
@@ -262,12 +279,12 @@ IObjectFactory factory = new XmlObjectFactory(input);
Your XML object definitions can also be defined within the
standard .NET application configuration file by registering the
- Spring.Context.Support.DefaultSectionHandler
+ Spring.Context.Support.DefaultSectionHandler
class as the configuration section handler for inline object
definitions. This allows you to completely configure one or more
- IApplicationContext instances within a single
+ IApplicationContext instances within a single
standard .NET application configuration file as shown in the following
- example. <configuration>
+ example. <configuration>
<configSections>
<sectionGroup name="spring">
@@ -292,15 +309,15 @@ IObjectFactory factory = new XmlObjectFactory(input);Other options available to structure the configuration files are
described in and
- .
+ .
- The IApplicationContext can be configured
+ The IApplicationContext can be configured
to register other resource handlers, custom parsers to integrate
user-contributed XML schema into the object definitions section, type
converters, and define type aliases. These features are discussed in
section
-
+ Composing XML-based configuration metadataIt is often useful to split up container definitions into
@@ -320,7 +337,7 @@ IObjectFactory factory = new XmlObjectFactory(input);object elements in the file doing the importing.
Let's look at a sample:
- <objects xmlns="http://www.springframework.net">
+ <objects xmlns="http://www.springframework.net">
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
@@ -350,7 +367,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
-
+ The ObjectsA Spring IoC container manages one or more objects. these objects
@@ -422,7 +439,7 @@ IObjectFactory factory = new XmlObjectFactory(input);singleton or prototype
-
+
@@ -467,15 +484,15 @@ IObjectFactory factory = new XmlObjectFactory(input);
Besides object definitions which contain information on how to
- create a specific object, certain IObjectFactory
+ create a specific object, certain IObjectFactory
implementations also permit the registration of existing objects that
have been created outside the factory (by user code). The
- DefaultListableObjectFactory class supports this
+ DefaultListableObjectFactory class supports this
through the RegisterSingleton(..) method. (Typical
applications solely work with objects defined through metadata object
definitions though.)
-
+ Naming objectsEvery object has one or more ids (also called
@@ -508,14 +525,13 @@ IObjectFactory factory = new XmlObjectFactory(input);Aliasing objects
-
+
In an object definition itself, you may supply more than one
name for the object, by using a combination of the id and name
attributes as discussed in .
This approach to aliasing objects has some limitations when you
would like to assemble the main application configuration file from
- multiple files. See for more
- information. This usage pattern is common when each configuration
+ multiple files. This usage pattern is common when each configuration
file represents a logical layer or component within the application.
In this case you may want to refer to a common object dependency
using a name that is specific to each file. If the common object
@@ -563,7 +579,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
-
+ Object creationAn object definition essentially is a recipe for creating one or
@@ -592,7 +608,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
the invocation of the static factory method may be
the same type or another type entirely, it doesn't matter).
-
+ Object creation via constructor invocationWhen creating an object using the constructor approach, all
@@ -604,10 +620,10 @@ IObjectFactory factory = new XmlObjectFactory(input);
constructor (i.e. a constructor that has no parameters) in the source
code definition of your class.
- The XmlObjectFactory implementation of
- the IObjectFactory interface can consume object
+ The XmlObjectFactory implementation of
+ the IObjectFactory interface can consume object
definitions that have been defined in XML, for example...
- <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/>
+ <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/>The mechanism for supplying arguments to the constructor (if
required), or setting properties of the object instance after it has
@@ -615,7 +631,7 @@ IObjectFactory factory = new XmlObjectFactory(input);This XML fragment describes an object definition that will be
identified by the exampleObject name, instances
- of which will be of the Examples.ExampleObject
+ of which will be of the Examples.ExampleObject
type that has been compiled into the
ExamplesLibrary assembly. Take special note of the
structure of the type attribute's value... the
@@ -645,7 +661,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
to reference the nested class. For example, if the class
Examples.ExampleObject had a nested class
Person the XML declaration would be
- <object id="exampleObject" type="Examples.ExampleObject+Person, ExamplesLibrary"/>
+ <object id="exampleObject" type="Examples.ExampleObject+Person, ExamplesLibrary"/>If you are defining classes that have been compiled into
assemblies that are available to your application (such as the
@@ -661,7 +677,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
(and their attendant classes) from that point forward.
-
+ Object creation via a static factory methodWhen defining an object which is to be created using a static
@@ -679,7 +695,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
that the definition does not specify the type (class) of the returned
object, only the type containing the factory method. In this example,
CreateInstance must be a static method.
- <object id="exampleObject"
+ <object id="exampleObject"
type="Examples.ExampleObjectFactory, ExamplesLibrary"
factory-method="CreateInstance"/>
@@ -688,7 +704,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
returned from the factory, will be described shortly.
-
+ Object creation via an instance factory methodIn a fashion similar to instantiation using a static factory
@@ -700,7 +716,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
an object in the current (or parent/ancestor) container that contains
the instance method that is to be invoked to create the object. The
name of the factory method itself should still be set via the
- 'factory-method' attribute.<!-- the factory object, which contains an instance method called 'CreateInstance' -->
+ 'factory-method' attribute.<!-- the factory object, which contains an instance method called 'CreateInstance' -->
<object id="exampleFactory" type="...">
<!-- inject any dependencies required by this object -->
</object>
@@ -725,19 +741,19 @@ IObjectFactory factory = new XmlObjectFactory(input);
-
+ Object creation of generic typesGeneric types can also be created in much the same manner an
non-generic types.
-
+ Object creation of generic types via constructor
invocationThe following examples shows the definition of simple generic
types and how they can be created in Spring's XML based configuration
- file. namespace GenericsPlay
+ file. namespace GenericsPlay
{
public class FilterableList<T>
{
@@ -765,7 +781,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
}
} The XML configuration to create and configure this object
- is shown below <object id="myFilteredIntList" type="GenericsPlay.FilterableList<int>, GenericsPlay">
+ is shown below <object id="myFilteredIntList" type="GenericsPlay.FilterableList<int>, GenericsPlay">
<property name="Name" value="My Integer List"/>
</object> There are a few items to note in terms how to
specify a generic type. First, the left bracket that specifies the
@@ -777,28 +793,27 @@ IObjectFactory factory = new XmlObjectFactory(input);
Alternative characters used to overcome the two quirks can be
implemented in the future but so far, all proposals don't seem to help
clarify the text. The suggested solution to improve readability is to
- use type aliases as shown below
-<typeAliases>
+ use type aliases as shown below <typeAliases>
<alias name="GenericDictionary" type=" System.Collections.Generic.Dictionary<,>" />
<alias name="myDictionary" type="System.Collections.Generic.Dictionary<int,string>" />
</typeAliases>
- So that instead of something like this <object id="myGenericObject"
+ So that instead of something like this <object id="myGenericObject"
type="GenericsPlay.ExampleGenericObject<System.Collections.Generic.Dictionary<int , string>>, GenericsPlay" />
- It can be shortened to <object id="myOtherGenericObject"
+ It can be shortened to <object id="myOtherGenericObject"
type="GenericsPlay.ExampleGenericObject<GenericDictionary<int , string>>, GenericsPlay" />
- or even shorter <object id="myOtherOtherGenericObject"
+ or even shorter <object id="myOtherOtherGenericObject"
type="GenericsPlay.ExampleGenericObject<MyIntStringDictionary>, GenericsPlay" />
Refer to for
additional information on using type aliases.
-
+ Object creation of generic types via static factory
methodThe following classes are used to demonstrate the ability to
create instances of generic types that themselves are created via a
- static generic factory method. public class TestGenericObject<T, U>
+ static generic factory method. public class TestGenericObject<T, U>
{
public TestGenericObject()
{
@@ -821,7 +836,7 @@ IObjectFactory factory = new XmlObjectFactory(input);
set { someStringKeyedDictionary = value; }
}
-} The accompanying factory class is
+} The accompanying factory class is
public class TestGenericObjectFactory
{
public static TestGenericObject<V, W> StaticCreateInstance<V, W>()
@@ -836,7 +851,7 @@ public class TestGenericObjectFactory
}
The XML snippet to create an instance of TestGenericObject
where V is a List of integers and
- W is an integer is shown below <object id="myTestGenericObject"
+ W is an integer is shown below <object id="myTestGenericObject"
type="GenericsPlay.TestGenericObjectFactory, GenericsPlay"
factory-method="StaticCreateInstance<System.Collections.Generic.List<int>,int>"
/> The StaticCreateInstance method is responsible for
@@ -844,13 +859,13 @@ public class TestGenericObjectFactory
'myTestGenericObject'.
-
+ Object creation of generic types via instance factory
methodUsing the class from the previous example the XML snippet to
create an instance of a generic type via an instance factory method is
- shown below <object id="exampleFactory" type="GenericsPlay.TestGenericObject<int,string>, GenericsPlay"/>
+ shown below <object id="exampleFactory" type="GenericsPlay.TestGenericObject<int,string>, GenericsPlay"/>
<object id="anotherTestGenericObject"
factory-object="exampleFactory"
@@ -860,24 +875,24 @@ public class TestGenericObjectFactory
-
+ Using the container
- An IApplicationContext is essentially
+ An IApplicationContext is essentially
nothing more than the interface for an advanced factory capable of
maintaining a registry of different objects and their dependencies. The
- IApplicationContext enables you to read object
+ IApplicationContext enables you to read object
definitions and access them. You create one and read in some object
definition in the XML format as follows:
- IApplicationContext context = new XmlApplicationContext("file://objects.xml");
+ IApplicationContext context = new XmlApplicationContext("file://objects.xml");
Basically that is all there is to it. Using
GetObject(string) or the indexer
[string], you can retrieve instances of your object;
- the client-side view of the IApplicationContext
- is simple. The IApplicationContext interface has
+ the client-side view of the IApplicationContext
+ is simple. The IApplicationContext interface has
just a few other methods related to finding objects in the contianer,
but ideally your application code should never use them... indeed, your
application code should have no calls to the
@@ -886,7 +901,7 @@ public class TestGenericObjectFactory
-
+ DependenciesYour typical enterprise application is not made up of a single
@@ -898,7 +913,7 @@ public class TestGenericObjectFactory
collaborate) together to achieve some goal (usually an application that
does what the end-user wants).
-
+ Injecting dependenciesThe basic principle behind Dependency Injection (DI) is that
@@ -920,7 +935,7 @@ public class TestGenericObjectFactory
in two major variants, namely Constructor Injection and Setter
Injection.
-
+ Constructor InjectionConstructor-based DI is effected by invoking a constructor with
@@ -932,7 +947,7 @@ public class TestGenericObjectFactory
could only be dependency injected using constructor injection. Notice
that there is nothing special about this class.
- public class SimpleMovieLister
+ public class SimpleMovieLister
{
// the SimpleMovieLister has a dependency on a MovieFinder
private IMovieFinder movieFinder;
@@ -947,7 +962,7 @@ public class TestGenericObjectFactory
}
-
+ Constructor Argument ResolutionConstructor argument resolution matching occurs using the
@@ -958,7 +973,7 @@ public class TestGenericObjectFactory
appropriate constructor when it is being instantiated. Consider the
following class:
- namespace X.Y
+ namespace X.Y
{
public class Foo
{
@@ -975,7 +990,7 @@ public class TestGenericObjectFactory
and you do not need to specify the constructor argument indexes and
/ or types explicitly.
- <object name="Foo" type="X.Y.Foo, Example">
+ <object name="Foo" type="X.Y.Foo, Example">
<constructor-arg>
<object type="X.Y.Bar, Example"/>
</constructor-arg>
@@ -991,7 +1006,7 @@ public class TestGenericObjectFactory
determine the type of the value, and so cannot match by type without
help. Consider the following class:
- using System;
+ using System;
namespace SimpleApp
{
@@ -1009,13 +1024,13 @@ namespace SimpleApp
}
-
+ Constructor Argument Type MatchingThe above scenario can use type
matching with simple types by explicitly specifying the type of
the constructor argument using the type
- attribute. For example: <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
+ attribute. For example: <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="string" value="42"/>
</object>
@@ -1153,12 +1168,12 @@ namespace SimpleApp
-
+ Constructor Argument IndexConstructor arguments can have their index specified
explicitly by use of the index attribute. For
- example: <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
+ example: <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</object>As well as solving the ambiguity problem of
@@ -1168,14 +1183,14 @@ namespace SimpleApp
based.
-
+ Constructor Arguments by NameConstructor arguments can also be specified by name by using
the name attribute of the
<constructor-arg> element.
- <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
+ <object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</object>
@@ -1183,7 +1198,7 @@ namespace SimpleApp
-
+ Setter InjectionSetter-based DI is realized by calling setter methods on your
@@ -1193,7 +1208,7 @@ namespace SimpleApp
Find below an example of a class that can only be dependency
injected using pure setter injection.
- public class MovieLister
+ public class MovieLister
{
private IMovieFinder movieFinder;
@@ -1233,12 +1248,12 @@ namespace SimpleApp
only type of DI available to you.
- The IObjectFactory supports both of these
+ The IObjectFactory supports both of these
variants for injecting dependencies into objects it manages. (It in
fact also supports injecting setter-based dependencies after some
dependencies have already been supplied via the constructor approach.)
The configuration for the dependencies comes in the form of the
- IObjectDefinition class, which is used together
+ IObjectDefinition class, which is used together
with TypeConverters to know how to convert
properties from one format to another. However, most users of
Spring.NET will not be dealing with these classes directly (that is
@@ -1249,11 +1264,11 @@ namespace SimpleApp
Object dependency resolution generally happens as follows:
- The IObjectFactory is created and
+ The IObjectFactory is created and
initialized with a configuration which describes all the
objects. Most Spring.NET users use an
- IObjectFactory or
- IApplicationContext variant that supports
+ IObjectFactory or
+ IApplicationContext variant that supports
XML format configuration files.
@@ -1282,12 +1297,12 @@ namespace SimpleApp
id="object-factory-collaborators-typeconverter" />Each property
or constructor argument which is a value must be able to be
converted from whatever format it was specified in, to the
- actual System.Type of that property or
+ actual System.Type of that property or
constructor argument. By default Spring.NET can convert a value
supplied in string format to all built-in types, such as
int, long,
string, bool, etc.
- Spring.NET uses TypeConverter definitions
+ Spring.NET uses TypeConverter definitions
to be able to convert string values to other, arbitrary types.
Refer to for more
information regarding type conversion, and how you can design
@@ -1301,7 +1316,7 @@ namespace SimpleApp
However, the object properties themselves are not set until the object
is actually created. For those object that defined as singletons and
set to be pre-instantiated (such as singleton object in an
- IApplicationContext), creation happens at the
+ IApplicationContext), creation happens at the
time that the container is created, but otherwise this is only when
the object is requested. When an object actually has to be created,
this will potentially cause a graph of other objects to be created, as
@@ -1321,7 +1336,7 @@ namespace SimpleApp
constructor injection. If you configure object for classes A and B
to be injected into each other, the Spring IoC container will detect
this circular reference at runtime, and throw a
- ObjectCurrentlyInCreationException.
+ ObjectCurrentlyInCreationException.One possible solution to this issue is to edit the source code
of some of your classes to be configured via setters instead of via
@@ -1347,11 +1362,11 @@ namespace SimpleApp
that object or one of its dependencies. This could happen if the
object throws an exception as a result of a missing or invalid
property, for example. This potentially delayed visibility of some
- configuration issues is why IApplicationContext
+ configuration issues is why IApplicationContext
by default pre-instantiates singleton objects. At the cost of some
upfront time and memory to create these objects before they are
actually needed, you find out about configuration issues when the
- IApplicationContext is created, not later. If
+ IApplicationContext is created, not later. If
you wish, you can still override this default behavior and set any of
these singleton objects to lazy-load (not be preinstantiated)
@@ -1366,16 +1381,16 @@ namespace SimpleApp
configure' to mean that the object will be instantiated (if
not a pre-instantiated singleton), all of its dependencies will be
set, and the relevant lifecycle methods (such as a configured init
- method or the IIntializingObject callback
+ method or the IIntializingObject callback
method) will all be invoked.
-
+ Some examplesFirst, an example of using XML-based configuration metadata for
setter-based DI. Find below a smallpart of a Spring XML configuration
- file specifying some object definitions. <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary">
+ file specifying some object definitions. <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary">
<!-- setter injection using the ref attribute -->
<property name="objectOne" ref="anotherExampleObject"/>
@@ -1385,7 +1400,7 @@ namespace SimpleApp
<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>
- [C#]
+ [C#]
public class ExampleObject
{
private AnotherObject objectOne;
@@ -1410,7 +1425,7 @@ public class ExampleObject
As you can see, setters have been declared to match against the
properties specified in the XML file. Find below an example of using
- constructor-based DI.<object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary">
+ constructor-based DI.<object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary">
<constructor-arg name="objectOne" ref="anotherExampleObject"/>
<constructor-arg name="objectTwo" ref="yetAnotherObject"/>
<constructor-arg name="IntegerProperty" value="1"/>
@@ -1418,7 +1433,7 @@ public class ExampleObject
<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>
- [Visual Basic.NET]
+ [Visual Basic.NET]
Public Class ExampleObject
Private myObjectOne As AnotherObject
@@ -1436,11 +1451,11 @@ Public Class ExampleObject
End Sub
End ClassAs you can see, the constructor arguments specified
in the object definition will be used to pass in as arguments to the
- constructor of the ExampleObject.
+ constructor of the ExampleObject.Now consider a variant of this where instead of using a
constructor, Spring is told to call a static factory method to return
- an instance of the object <object id="exampleObject" type="Examples.ExampleFactoryMethodObject, ExamplesLibrary"
+ an instance of the object <object id="exampleObject" type="Examples.ExampleFactoryMethodObject, ExamplesLibrary"
factory-method="CreateInstance">
<constructor-arg name="objectOne" ref="anotherExampleObject"/>
<constructor-arg name="objectTwo" ref="yetAnotherObject"/>
@@ -1449,7 +1464,7 @@ End ClassAs you can see, the constructor arguments specified
<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>
- [C#]
+ [C#]
public class ExampleFactoryMethodObject
{
private AnotherObject objectOne;
@@ -1488,7 +1503,7 @@ public class ExampleFactoryMethodObject
Note that Setter Injection and Constructor Injectionare not
mutually exclusive. It is perfectly reasonable to use both for a
single object definition, as can be seen in the following example:
- <object id="exampleObject" type="Examples.MixedIocObject, ExamplesLibrary">
+ <object id="exampleObject" type="Examples.MixedIocObject, ExamplesLibrary">
<constructor-arg name="objectOne" ref="anotherExampleObject"/>
<property name="objectTwo" ref="yetAnotherObject"/>
<property name="IntegerProperty" value="1"/>
@@ -1496,7 +1511,7 @@ public class ExampleFactoryMethodObject
<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>
- [C#]
+ [C#]
public class MixedIocObject
{
private AnotherObject objectOne;
@@ -1521,7 +1536,7 @@ public class MixedIocObject
-
+ Dependencies and configuration in detailAs mentioned in the previous section, object properties and
@@ -1539,16 +1554,16 @@ public class MixedIocObject
The <value/> element specifies a
property or constructor argument as a human-readable string
representation. As mentioned previously,
- TypeConverter instances are used to convert
- these string values from a System.String to the
+ TypeConverter instances are used to convert
+ these string values from a System.String to the
actual property or argument type. Custom
- TypeConverter implementations in the
+ TypeConverter implementations in the
Spring.Objects.TypeConverters namespace are used to
augment the functionality offered by the .NET BCL's default
- TypeConverter implementations.
+ TypeConverter implementations.In the following example, we use a
- SqlConnection from the
+ SqlConnection from the
System.Data.SqlClient namespace of the BCL. This
class (like many other existing classes) can easily be used in a
Spring.NET object factory, as it offers a convenient public property
@@ -1556,7 +1571,7 @@ public class MixedIocObject
property.
- objects xmlns="http://www.springframework.net">
+ <objects xmlns="http://www.springframework.net">
<object id="myConnection" type="System.Data.SqlClient.SqlConnection">
<!-- results in a call to the setter of the ConnectionString property -->
<property
@@ -1572,7 +1587,7 @@ public class MixedIocObject
An idref element is simply a shorthand and error-proof way to
set a property to the String id or
name of another object in the
- container.<object id="theTargetObject" type="...">
+ container.<object id="theTargetObject" type="...">
. . .
</object>
@@ -1581,7 +1596,7 @@ public class MixedIocObject
<idref object="theTargetObject"/>
</property>
</object>This is exactly equivalent at runtime to the
- following fragment:<object id="theTargetObject" type="...">
+ following fragment:<object id="theTargetObject" type="...">
. . .
</object>
@@ -1600,13 +1615,13 @@ public class MixedIocObject
actual XML file, and the object name is the object
id, the local attribute may
be used, which will allow the XML parser itself to validate the
- object name even earlier, at parse time. <property name="targetName">
+ object name even earlier, at parse time. <property name="targetName">
<idref local="theTargetObject"/>
</property>
-
+ Referring to collaborating objectsThe ref element is the final element allowed
@@ -1614,7 +1629,7 @@ public class MixedIocObject
set the value of the specified property to be a reference to another
object managed by the container, a collaborator, so to speak. As you
saw in the previous example to set collection properties, we used the
- SqlConnection instance from the initial example
+ SqlConnection instance from the initial example
as a collaborator and specified it using a <ref object/>
element. As mentioned in a previous section, the referred-to object is
considered to be a dependency of the object who's property is being
@@ -1628,14 +1643,14 @@ public class MixedIocObject
Specifying the target object by using the
object attribute of the ref tag
is the most general form, and will allow creating a reference to any
- object in the same IObjectFactory /
- IApplicationContext (whether or not in the same
- XML file), or parent IObjectFactory /
- IApplicationContext. The value of the
+ object in the same IObjectFactory /
+ IApplicationContext (whether or not in the same
+ XML file), or parent IObjectFactory /
+ IApplicationContext. The value of the
object attribute may be the same as either the
id attribute of the target object, or one of the
values in the name attribute of the target
- object.<ref object="someObject"/>
+ object.<ref object="someObject"/>Specifying the target object by using the
local attribute leverages the ability of the XML
@@ -1645,31 +1660,31 @@ public class MixedIocObject
will issue an error if no matching element is found in the same file.
As such, using the local variant is the best choice (in order to know
about errors are early as possible) if the target object is in the
- same XML file.<ref local="someObject"/>
+ same XML file.<ref local="someObject"/>Specifying the target object by using the
parent attribute allows a reference to be created
- to an object that is in a parent IObjectFactory
- (orIApplicationContext) of the current
- IObjectFactory (or
- IApplicationContext). The value of the
+ to an object that is in a parent IObjectFactory
+ (orIApplicationContext) of the current
+ IObjectFactory (or
+ IApplicationContext). The value of the
parent attribute may be the same as either the
id attribute of the target object, or one of the
values in the name attribute of the target object,
and the target object must be in a
- parent IObjectFactory or
- IApplicationContext of the current one. The
+ parent IObjectFactory or
+ IApplicationContext of the current one. The
main use of this object reference variant is when there is a need to
wrap an existing object in a parent context with some sort of proxy
(which may have the same name as the parent), and needs the original
object so it may wrap it.
- <ref parent="someObject"/>
+ <ref parent="someObject"/>
-
+ Inline objectsAn object element inside the
@@ -1677,7 +1692,7 @@ public class MixedIocObject
inline, instead of referring to an object defined elsewhere in the
container. The inline object definition does not need to have any id
or name defined (indeed, if any are defined, they will be ignored).
- <object id="outer" type="...">
+ <object id="outer" type="...">
<!-- Instead of using a reference to target, just use an inner object -->
@@ -1690,7 +1705,7 @@ public class MixedIocObject
</object>
-
+ Setting collection valuesThe list, set,
@@ -1699,7 +1714,7 @@ public class MixedIocObject
IList, ISet,
NameValueCollection and
IDictionary, respectively, to be defined and set.
- <objects xmlns="http://www.springframework.net">
+ <objects xmlns="http://www.springframework.net">
<object id="moreComplexObject" type="Example.ComplexObject">
<!--
results in a call to the setter of the SomeList (System.Collections.IList) property
@@ -1761,30 +1776,30 @@ public class MixedIocObject
linkend="objects-shortcutforms" /> for more information.
-
+ Setting generic collection valuesSpring supports setting values for classes that expose
properties based on the generic collection interfaces
- IList<T> and
- IDictionary<TKey, TValue>. The type
+ IList<T> and
+ IDictionary<TKey, TValue>. The type
parameter for these collections is specified by using the XML
attribute element-type for
- IList<T> and the XML attributes
+ IList<T> and the XML attributes
key-type and value-type for
- IDictionary<TKey, TValue>. The values of
+ IDictionary<TKey, TValue>. The values of
the collection are automaticaly converted from a string to the
appropriate type. If you are using your own user-defined type as a
generic type parameter you will likely need to register a custom type
converter. Refer to for
more information. The implementations of
- IList<T> and
- IDictionary<TKey, TValue> that is created
- are System.Collections.Generic.List and
- System.Collections.Generic.Dictionary.
+ IList<T> and
+ IDictionary<TKey, TValue> that is created
+ are System.Collections.Generic.List and
+ System.Collections.Generic.Dictionary.
The following class represents a lottery ticket and demonstrates
- how to set the values of a generic IList. public class LotteryTicket {
+ how to set the values of a generic IList. public class LotteryTicket {
List<int> list;
@@ -1800,7 +1815,7 @@ public class MixedIocObject
set { date = value; }
}
} The XML fragment that can be used to configure this class
- is shown below <object id="MyLotteryTicket" type="GenericsPlay.Lottery.LotteryTicket, GenericsPlay">
+ is shown below <object id="MyLotteryTicket" type="GenericsPlay.Lottery.LotteryTicket, GenericsPlay">
<property name="Numbers">
<list element-type="int">
<value>11</value>
@@ -1816,12 +1831,12 @@ public class MixedIocObject
The following shows the definition of a more complex class that
demonstrates the use of generics using the
- Spring.Expressions.IExpression interface as the
+ Spring.Expressions.IExpression interface as the
generic type parameter for the IList element-type and the value-type
- for IDictionary. Spring.Expressions.IExpression
+ for IDictionary. Spring.Expressions.IExpression
has an associated type converter,
- Spring.Objects.TypeConverters.ExpressionConverter
- that is already pre-registered with Spring. public class GenericExpressionHolder
+ Spring.Objects.TypeConverters.ExpressionConverter
+ that is already pre-registered with Spring. public class GenericExpressionHolder
{
private System.Collections.Generic.IList<IExpression> expressionsList;
@@ -1850,7 +1865,7 @@ public class MixedIocObject
get { return this.expressionsDictionary[key]; }
}
} An example XML configuration of this class is shown
- below <object id="genericExpressionHolder"
+ below <object id="genericExpressionHolder"
type="Spring.Objects.Factory.Xml.GenericExpressionHolder,
Spring.Core.Tests">
<property name="ExpressionsList">
@@ -1880,16 +1895,16 @@ public class MixedIocObject
</object>
-
+ Setting null valuesThe <null> element is used to handle
null values. Spring.NET treats empty arguments for
properties and constructor arguments as empty
- string instances. The following configuration
+ string instances. The following configuration
demonstrates this behaviour...
- <object type="Examples.ExampleObject, ExamplesLibrary">
+ <object type="Examples.ExampleObject, ExamplesLibrary">
<property name="email"><value></value></property>
<!-- equivalent, using value attribute as opposed to nested <value/> element...
@@ -1898,17 +1913,17 @@ public class MixedIocObject
This results in the email property being set to the empty string
value (""), in much the same way as can be seen in
- the following snippet of C# code... exampleObject.Email = "";
+ the following snippet of C# code... exampleObject.Email = "";
The special <null/> element may be used to
indicate a null value; to wit...
- <object type="Examples.ExampleObject, ExamplesLibrary">
+ <object type="Examples.ExampleObject, ExamplesLibrary">
<property name="email"><null/></property>
</object>This results in the email property being set to
null, again in much the same way as can be seen in
- the following snippet of C# code... exampleObject.Email = null;
+ the following snippet of C# code... exampleObject.Email = null;
@@ -1921,7 +1936,7 @@ public class MixedIocObject
property expression parser described in
is used to perform the type conversion of the indexer name argument
from a string in the XML file to a matching target type. As an example
- consider the following class public class Person
+ consider the following class public class Person
{
private IList favoriteNames = new ArrayList();
@@ -1945,7 +1960,7 @@ public class MixedIocObject
set { properties.Add(keyName, value); }
}
} The XML configuration snippet to populate this object with
- data is shown below <object id="person" type="Test.Objects.Person, Test.Objects">
+ data is shown below <object id="person" type="Test.Objects.Person, Test.Objects">
<property name="[0]" value="Master Shake"/>
<property name="['one']" value="uno"/>
</object>
@@ -1953,7 +1968,7 @@ public class MixedIocObject
The use of the property expression parser in Release 1.0.2
changed how you configure indexer properties. The following section
describes this usage. The older style configuration uses the
- following syntax <object id="objectWithIndexer" type="Spring.Objects.TestObject, Spring.Core.Tests">
+ following syntax <object id="objectWithIndexer" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="Item[0]" value="my string value"/>
</object> You can also change the name used to identify
the indexer by adorning your indexer method declaration with the
@@ -1967,7 +1982,7 @@ public class MixedIocObject
use the IndexerName attribute.
-
+ Value and ref shortcut formsThere are also some shortcut forms that are less verbose than
@@ -1976,7 +1991,7 @@ public class MixedIocObject
constructor-arg, and entry
elements all support a value attribute which may be
used instead of embedding a full value element.
- Therefore, the following: <property name="myProperty">
+ Therefore, the following: <property name="myProperty">
<value>hello</value>
</property>
@@ -1986,7 +2001,7 @@ public class MixedIocObject
<entry key="myKey">
<value>hello</value>
-</entry> are equivalent to:<property name="myProperty" value="hello"/>
+</entry> are equivalent to:<property name="myProperty" value="hello"/>
<constructor-arg value="hello"/>
@@ -1998,13 +2013,13 @@ public class MixedIocObject
constructor-arg elements support a similar shortcut
ref attribute which may be used instead of a full
nested ref element. Therefore, the following...
- <property name="myProperty">
+ <property name="myProperty">
<ref object="anotherObject"/>
</property>
<constructor-arg index="0">
<ref object="anotherObject"/>
-</constructor-arg> is equivalent to... <property name="myProperty" ref="anotherObject"/>
+</constructor-arg> is equivalent to... <property name="myProperty" ref="anotherObject"/>
<constructor-arg index="0" ref="anotherObject"/>
@@ -2016,18 +2031,18 @@ public class MixedIocObject
Finally, the entry element allows a shortcut form the specify
the key and/or value of a dictionary, in the form of key/key-ref and
- value/value-ref attributes. Therefore, the following <entry>
+ value/value-ref attributes. Therefore, the following <entry>
<key>
<ref object="MyKeyObject"/>
</key>
<ref object="MyValueObject"/>
-</entry> Is equivalent to: <entry key-ref="MyKeyObject" value-ref="MyValueObject"/>
+</entry> Is equivalent to: <entry key-ref="MyKeyObject" value-ref="MyValueObject"/>
As mentioned previously, the equivalence is to <ref
object="xxx"> and not the local or parent forms of object
references.
-
+ Compound property names and Spring expression
references
@@ -2039,7 +2054,7 @@ public class MixedIocObject
example, in this object definition a simple nested property name is
configured
- <object id="foo" type="Spring.Foo, Spring.Foo">
+ <object id="foo" type="Spring.Foo, Spring.Foo">
<property name="bar.baz.name" value="Bingo"/>
</object>
@@ -2050,7 +2065,7 @@ public class MixedIocObject
use the 'expression' element to refer to a Spring expression as the
value of the property. Simple examples of this are shown below
- <property name=“minValue” expression=“int.MinValue” />
+ <property name=“minValue” expression=“int.MinValue” />
<property name=“weekFromToday” expression="DateTime.Today + 7"/>
@@ -2059,7 +2074,7 @@ public class MixedIocObject
configuraiton.
-
+ Using depends-onFor most situations, the fact that an object is a dependency of
@@ -2072,7 +2087,7 @@ public class MixedIocObject
attribute may be used to explicitly force one or more objects to be
initialized before the object using this element is initialized. Find
below an example of using the 'depends-on' attribute
- to express a dependency on a single object.. <object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager">
+ to express a dependency on a single object.. <object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager">
<property name="manager" ref="manager"/>
</object>
@@ -2083,7 +2098,7 @@ public class MixedIocObject
'depends-on' attribute, with commas, whitespace and
semicolons all valid delimiters, like so:
- <object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager,accountDao">
+ <object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</object>
@@ -2105,9 +2120,9 @@ public class MixedIocObject
Lazily-instantiated objectsThe default behavior for
- IApplicationContext implementations is to eagerly
+ IApplicationContext implementations is to eagerly
pre-instantiate all singleton objects at startup. Pre-instantiation
- means that an IApplicationContext will eagerly
+ means that an IApplicationContext will eagerly
create and configure all of its singleton objects as part of its
initialization process. Generally this is a good thing, because it means
that any errors in the configuration or in the surrounding environment
@@ -2116,7 +2131,7 @@ public class MixedIocObject
However, there are times when this behavior is not what is wanted.
If you do not want a singleton object to be pre-instantiated when using
- an IApplicationContext, you can selectively
+ an IApplicationContext, you can selectively
control this by marking an object definition as lazy-initialized. A
lazily-initialized object indicates to the IoC container whether or not
an object instance should be created at startup or when it is first
@@ -2126,21 +2141,21 @@ public class MixedIocObject
by the 'lazy-init'attribute on the
<object/> element; for example:
- <object id="lazy" type="MyCompany.ExpensiveToCreateObject, MyApp" lazy-init="true"/>
+ <object id="lazy" type="MyCompany.ExpensiveToCreateObject, MyApp" lazy-init="true"/>
<object name="not.lazy" type="MyCompany.AnotherObject, MyApp"/>When the above configuration is consumed by an
- IApplicationContext, the object named
+ IApplicationContext, the object named
'lazy' will not be eagerly pre-instantiated when the
- IApplicationContext is starting up, whereas the
+ IApplicationContext is starting up, whereas the
'not.lazy' object will be eagerly pre-instantiated.One thing to understand about lazy-initialization is that even
though an object definition may be marked up as being lazy-initialized,
if the lazy-initialized object is the dependency of a singleton object
that is not lazy-initialized, when the
- IApplicationContext is eagerly pre-instantiating
+ IApplicationContext is eagerly pre-instantiating
the singleton, it will have to satisfy all of the singletons
dependencies, one of which will be the lazy-initialized object! So don't
be confused if the IoC container creates one of the objects that you
@@ -2153,12 +2168,12 @@ public class MixedIocObject
'default-lazy-init'attribute on the <objects/>
element; for example:
- <objects default-lazy-init="true">
+ <objects default-lazy-init="true">
<!-- no objects will be pre-instantiated... -->
</objects>
-
+ Autowiring collaboratorsThe Spring container is able to autowire relationships between
@@ -2221,10 +2236,10 @@ public class MixedIocObject
This option gives you the ability to resolve
collaborators by type instead of by name. Supposing you have
- an IObjectDefinition with a
- collaborator typed SqlConnection,
+ an IObjectDefinition with a
+ collaborator typed SqlConnection,
Spring.NET will search the entire object factory for an object
- definition of type SqlConnection and
+ definition of type SqlConnection and
use it as the collaborator. If 0 (zero) or more than
1 (one) object definitions of the desired type exist in the
container, a failure will be reported and you won't be able to
@@ -2322,7 +2337,7 @@ public class MixedIocObject
definitions.
-
+ Checking for dependenciesSpring.NET has the ability to try to check for the existence of
@@ -2392,7 +2407,7 @@ public class MixedIocObject
-
+ Method InjectionFor most users, the majority of the objects in the container will
@@ -2412,13 +2427,13 @@ public class MixedIocObject
control. Object A can be made aware of the
container by implementing the
- IObjectFactoryAware interface, and IObjectFactoryAware interface, and use programmatic means to ask
the container via a GetObject("B") call for (a
typically new) object B every time it needs it. Find below an admittedly
somewhat contrived example of this approach
- using System.Collections;
+ using System.Collections;
using Spring.Objects.Factory;
namespace Fiona.Apple
@@ -2454,7 +2469,7 @@ namespace Fiona.Apple
Method Injection, a somewhat advanced feature of the Spring IoC
container, allows this use case to be handled in a clean fashion.
-
+ Lookup Method InjectionLookup method injection refers to the ability of the container
@@ -2473,11 +2488,11 @@ namespace Fiona.Apple
CommandManager class), the Spring container is
going to dynamically override the implementation of the
CreateCommand() method. Your
- CommandManager class is not going to have any
+ CommandManager class is not going to have any
Spring dependencies, as can be seen in this reworked example
below:
- using System.Collections;
+ using System.Collections;
namespace Fiona.Apple
{
@@ -2500,14 +2515,14 @@ namespace Fiona.Apple
CommandManager in this case) the method definition must observe the
following form:
- <public|protected> [abstract] <return-type> TheMethodName(no-arguments);
+ <public|protected> [abstract] <return-type> TheMethodName(no-arguments);If the method is abstract, the
dynamically-generated subclass will implement the method. Otherwise,
the dynamically-generated subclass will override the concrete method
defined in the original class. Let's look at an example:
- <!-- a stateful object deployed as a prototype (non-singleton) -->
+ <!-- a stateful object deployed as a prototype (non-singleton) -->
<object id="command" class="Fiona.Apple.AsyncCommand, Fiona" singleton="false">
<!-- inject dependencies here as required -->
</object>
@@ -2533,7 +2548,7 @@ namespace Fiona.Apple
properties on the object being constructed).
-
+ Arbitrary method replacementA less commonly useful form of method injection than Lookup
@@ -2542,13 +2557,13 @@ namespace Fiona.Apple
skip the rest of this section (which describes this somewhat advanced
feature), until this functionality is actually needed.
- In an XmlObjectFactory, the
+ In an XmlObjectFactory, the
replaced-method element may be used to replace an
existing method implementation with another. Consider the following
class, with a method ComputeValue, which we want to
override:
- public class MyValueCalculator {
+ public class MyValueCalculator {
public virtual string ComputeValue(string input) {
// ... some real code
@@ -2558,11 +2573,11 @@ namespace Fiona.Apple
}A class implementing the
- Spring.Objects.Factory.Support.IMethodReplacer
+ Spring.Objects.Factory.Support.IMethodReplacer
interface is needed to provide the new (injected) method
definition.
- /// <summary>
+ /// <summary>
/// Meant to be used to override the existing ComputeValue(string)
/// implementation in MyValueCalculator.
/// </summary>
@@ -2580,7 +2595,7 @@ public class ReplacementComputeValue : IMethodReplacer
The object definition to deploy the original class and specify
the method override would look like this:
- <object id="myValueCalculator" type="Examples.MyValueCalculator, ExampleAssembly">
+ <object id="myValueCalculator" type="Examples.MyValueCalculator, ExampleAssembly">
<!-- arbitrary method replacement -->
<replaced-method name="ComputeValue" replacer="replacementComputeValue">
<arg-type match="String"/>
@@ -2597,9 +2612,9 @@ public class ReplacementComputeValue : IMethodReplacer
variants within the class. For convenience, the type string for an
argument may be a substring of the fully qualified type name. For
example, all the following would match
- System.String.
+ System.String.
- System.String
+ System.String
String
Str
@@ -2609,7 +2624,7 @@ public class ReplacementComputeValue : IMethodReplacer
-
+ Setting a reference using the members of other objects and
classes.
@@ -2620,14 +2635,14 @@ public class ReplacementComputeValue : IMethodReplacer
change to accommodate some of Spring.NET's conventions... consider the
case of a class that has a constructor argument that can only be
calculated by going to say, a database. The
- MethodInvokingFactoryObject handles exactly this
+ MethodInvokingFactoryObject handles exactly this
scenario ... it will allow you to inject the result of an arbitrary
method invocation into a constructor (as an argument) or as the value of
a property setter. Similarly,
- PropertyRetrievingFactoryObject and
- FieldRetrievingFactoryObject allow you to
+ PropertyRetrievingFactoryObject and
+ FieldRetrievingFactoryObject allow you to
retrieve values from another object's property or field value. These
- classes implement the IFactoryObject interface
+ classes implement the IFactoryObject interface
which indicates to Spring.NET that this object is itself a factory and
the factories product, not the factory itself, is what will be
associated with the object id. Factory objects are discussed further in
@@ -2636,8 +2651,8 @@ public class ReplacementComputeValue : IMethodReplacer
Setting a reference to the value of property.
- The PropertyRetrievingFactoryObject is an
- IFactoryObject that addresses the scenario of
+ The PropertyRetrievingFactoryObject is an
+ IFactoryObject that addresses the scenario of
setting one of the properties and / or constructor arguments of an
object to the value of a property exposed on another object or class.
One can use it to get the value of any In the case of a property exposed on an instance, the target
- object that a PropertyRetrievingFactoryObject
+ object that a PropertyRetrievingFactoryObject
will evaluate can be either an object instance specified directly
inline or a reference to another arbitrary object. In the case of a
static property exposed on a class, the target object will be the
- class (the .NET System.Type) exposing the
+ class (the .NET System.Type) exposing the
property.The result of evaluating the property lookup may then be used in
another object definition as a property value or constructor argument.
Note that nested properties are supported for both instance and class
- property lookups. The IFactoryObject is
+ property lookups. The IFactoryObject is
discussed more generally in .Here's an example where a property path is used against another
object instance. In this case, an inner object definition is used and
- the property path is nested, i.e. spouse.age. <object name="person" type="Spring.Objects.TestObject, Spring.Core.Tests">
+ the property path is nested, i.e. spouse.age. <object name="person" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="age" value="20"/>
<property name="spouse">
<object type="Spring.Objects.TestObject, Spring.Core.Tests">
@@ -2678,10 +2693,10 @@ public class ReplacementComputeValue : IMethodReplacer
</object>An example of using a
- PropertyRetrievingFactoryObject to evaluate a
+ PropertyRetrievingFactoryObject to evaluate a
static property is shown below.
- <object id="cultureAware"
+ <object id="cultureAware"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests">
<property name="culture" ref="cultureFactory"/>
</object>
@@ -2696,7 +2711,7 @@ public class ReplacementComputeValue : IMethodReplacer
Similarly, an example showing the use of an instance property is
shown below.
- <object id="instancePropertyCultureAware"
+ <object id="instancePropertyCultureAware"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests">
<property name="Culture" ref="instancePropertyCultureFactory"/>
</object>
@@ -2715,21 +2730,21 @@ public class ReplacementComputeValue : IMethodReplacer
Setting a reference to the value of field.
- The FieldRetrievingFactoryObject class
+ The FieldRetrievingFactoryObject class
addresses much the same area of concern as the
- PropertyRetrievingFactoryObject described in
+ PropertyRetrievingFactoryObject described in
the previous section. However, as its name might suggest, the
- FieldRetrievingFactoryObject class is concerned
+ FieldRetrievingFactoryObject class is concerned
with looking up the value of a public
field exposed on either an instance or a class (and similarly, in the
case of a field exposed on a class, the field must obviously be
static).The following example demonstrates using a
- FieldRetrievingFactoryObject to look up the
+ FieldRetrievingFactoryObject to look up the
value of a (public, static) field exposed on a class
- <object id="withTypesField"
+ <object id="withTypesField"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests">
<property name="Types" ref="emptyTypesFactory"/>
</object>
@@ -2744,7 +2759,7 @@ public class ReplacementComputeValue : IMethodReplacer
The example in the next section demonstrates the look up of a
(public) field exposed on an object instance.
- <object id="instanceCultureAware"
+ <object id="instanceCultureAware"
type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject, Spring.Core.Tests">
<property name="Culture" ref="instanceCultureFactory"/>
</object>
@@ -2760,22 +2775,22 @@ public class ReplacementComputeValue : IMethodReplacer
-
+ Setting a property or constructor argument to the return value
of a method invocation.
- The MethodInvokingFactoryObject rounds
+ The MethodInvokingFactoryObject rounds
out the trio of classes that permit the setting of properties and
constructor arguments using the members of other objects and classes.
- Whereas the PropertyRetrievingFactoryObject and
- FieldRetrievingFactoryObject classes dealt with
+ Whereas the PropertyRetrievingFactoryObject and
+ FieldRetrievingFactoryObject classes dealt with
simply looking up and returning the value of property or field on an
object or class, the
- MethodInvokingFactoryObject allows one to set a
+ MethodInvokingFactoryObject allows one to set a
constructor or property to the return value of an arbitrary method
invocation,
- The MethodInvokingFactoryObject class
+ The MethodInvokingFactoryObject class
handles both the case of invoking an (instance) method on another
object in the container, and the case of a static method call on an
arbitrary class. Additionally, it is sometimes necessary to invoke a
@@ -2786,17 +2801,17 @@ public class ReplacementComputeValue : IMethodReplacer
mechanisms do not permit any arguments to be passed to any
initialization method, and are confined to invoking an initialization
method on the object that has just been instantiated by the container.
- The MethodInvokingFactoryObject allows one to
+ The MethodInvokingFactoryObject allows one to
invoke pretty much any method on any
object (or class in the case of a static method).The following example (in an XML based
- IObjectFactory definition) uses the
- MethodInvokingFactoryObject class to force a
+ IObjectFactory definition) uses the
+ MethodInvokingFactoryObject class to force a
call to a static factory method prior to the instantiation of the
object...
- <object id="force-init"
+ <object id="force-init"
type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="StaticMethod">
<value>ExampleNamespace.ExampleInitializerClass.Initialize</value>
@@ -2810,7 +2825,7 @@ public class ReplacementComputeValue : IMethodReplacer
thus the calling of its configured StaticMethod
static initializer method, when myService is first
initialized. Please note that in order to effect this initialization,
- the MethodInvokingFactoryObject object
+ the MethodInvokingFactoryObject object
must be operating in
singleton mode (the default.. see the next
paragraph).
@@ -2818,9 +2833,9 @@ public class ReplacementComputeValue : IMethodReplacer
Note that since this class is expected to be used primarily for
accessing factory methods, this factory defaults to operating in
singleton mode. As such, as soon as all of the
- properties for a MethodInvokingFactoryObject
+ properties for a MethodInvokingFactoryObject
object have been set, and if the
- MethodInvokingFactoryObject object is still in
+ MethodInvokingFactoryObject object is still in
singleton mode, the method will be invoked
immediately and the return value cached for later access. The first
request by the container for the factory to produce an object will
@@ -2835,7 +2850,7 @@ public class ReplacementComputeValue : IMethodReplacer
targetMethod property to a string
representing the static method name, with
TargetType specifying the
- Type that the static method is defined on.
+ Type that the static method is defined on.
Alternatively, a target instance method may be specified, by setting
the TargetObject property to the name of
another Spring.NET managed object definition (the target object), and
@@ -2849,8 +2864,8 @@ public class ReplacementComputeValue : IMethodReplacer
arguments is significant... the order of the values passed to the
Arguments property must be the same as the
order of the arguments defined on the method signature, including the
- argument Type. This is shown in the example
- below <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
+ argument Type. This is shown in the example
+ below <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetType" value="Whatever.MyClassFactory, MyAssembly"/>
<property name="TargetMethod" value="GetInstance"/>
@@ -2867,11 +2882,11 @@ public class ReplacementComputeValue : IMethodReplacer
The second way involves passing an arguments dictionary to the
NamedArguments property... this dictionary
- maps argument names (Strings) to argument
+ maps argument names (Strings) to argument
values (any object). The argument names are not case-sensitive, and
order is (obviously) not significant (since dictionaries by definition
do not have an order). This is shown in the example below
- <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
+ <object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetObject">
<object type="Whatever.MyClassFactory, MyAssembly"/>
</property>
@@ -2888,8 +2903,8 @@ public class ReplacementComputeValue : IMethodReplacer
</object>The following example shows how use
- MethodInvokingFactoryObject to call an instance
- method.<object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />
+ MethodInvokingFactoryObject to call an instance
+ method.<object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />
<object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetObject" ref="myMethodObject"/>
@@ -2902,19 +2917,19 @@ public class ReplacementComputeValue : IMethodReplacer
invoked to the surrounding factory object.Finally, if you want to use
- MethodInvokingFactoryObject in conjunction with
+ MethodInvokingFactoryObject in conjunction with
a method that has a variable length argument list, then please note
that the variable arguments need to be passed (and configured) as a
list. Let us consider the following method
- definition that uses the params keyword (in
- C#), and its attendant (XML) configuration... [C#]
+ definition that uses the params keyword (in
+ C#), and its attendant (XML) configuration... [C#]
public class MyClassFactory
{
public object CreateObject(Type objectType, params string[] arguments)
{
return ... // implementation elided for clarity...
}
-}<object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />
+}<object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />
<object id="paramsMethodObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetObject" ref="myMethodObject"/>
@@ -2932,28 +2947,28 @@ public class MyClassFactory
-
+ Provided IFactoryObject implementationsIn addition to
- PropertyRetrievingFactoryObject,
- MethodInvokingFactoryObject, and
- FieldRetrievingFactoryObject Spring.NET comes
+ PropertyRetrievingFactoryObject,
+ MethodInvokingFactoryObject, and
+ FieldRetrievingFactoryObject Spring.NET comes
with other useful implementations of the
- IFactoryObject interface. These are discussed
+ IFactoryObject interface. These are discussed
below.
-
+ Common logging
- The LogFactoryObject is useful when you
+ The LogFactoryObject is useful when you
would like to share a Common.Logging log object across a number of
classes instead of creating a logging instance per class or class
hierarchy. Information on the Common.Logging project can be found
here. In the
example shown below the same logging instance, with a logging category
name of "DAOLogger", is used in both the SimpleAccountDao and
- SimpleProductDao data access objects. <objects xmlns="http://www.springframework.net"
+ SimpleProductDao data access objects. <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd" >
@@ -2983,7 +2998,7 @@ public class MyClassFactory
-
+ Object ScopesWhen you create a object definition what you are actually creating
@@ -3065,7 +3080,7 @@ public class MyClassFactory
-
+ The singleton scopeWhen an object is a singleton, only one shared instance of the
@@ -3092,7 +3107,7 @@ public class MyClassFactory
scope is the default scope in Spring. To define an object as a singleton
in XML, you would write configuration like so:
- <object id="accountService" type="MyApp.DefaultAccountService, MyApp"/>
+ <object id="accountService" type="MyApp.DefaultAccountService, MyApp"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<object id="accountService" type="MyApp.DefaultAccountService, MyApp" singleton="true"/>
@@ -3100,7 +3115,7 @@ public class MyClassFactory
-
+ The prototype scopeThe non-singleton, prototype scope of object deployment results in
@@ -3114,7 +3129,7 @@ public class MyClassFactory
To define an object as a prototype in XML, you would write
configuration like so:
- <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary" singleton="false"/>
+ <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary" singleton="false"/>There is one quite important thing to be aware of when deploying
an object in the prototype scope, in that the lifecycle of the object
@@ -3141,7 +3156,7 @@ public class MyClassFactory
callbacks”.)
-
+ Singleton objecgts with prototype-object dependenciesWhen using singleton-scoped objects that have dependencies on
@@ -3175,17 +3190,17 @@ public class MyClassFactory
-
+ Type conversionType converters are responsible for converting objects from one type
to another. When using the XML based file to configure the IoC container,
string based property values are converted to the target property type.
Spring will rely on the standard .NET support for type conversion unless
- an alternative TypeConverter is registered for a
+ an alternative TypeConverter is registered for a
given type. How to register custom TypeConverters will be described
shortly. As a reminder, the standard .NET type converter support works by
- associating a TypeConverter attribute with the
+ associating a TypeConverter attribute with the
class definition by passing the type of the converter as an attribute
argument. More information about creating custom
@@ -3193,7 +3208,7 @@ public class MyClassFactory
at Microsoft's MSDN website, by searching for Implementing a
Type Converter. For example, an abbreviated class definition for the BCL
- type Font is shown below. [Serializable, TypeConverter(typeof(FontConverter)), ...]
+ type Font is shown below. [Serializable, TypeConverter(typeof(FontConverter)), ...]
public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDisposable
{
// Methods
@@ -3201,36 +3216,36 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
... etc ..
}
-
+ Type Conversion for EnumerationsThe default type converter for enumerations is the
- System.ComponentModel.EnumConverter class. To
+ System.ComponentModel.EnumConverter class. To
specify the value for an enumerated property, simply use the name of the
- property. For example the TestObject class has a
- property of the enumerated type FileMode. One of
+ property. For example the TestObject class has a
+ property of the enumerated type FileMode. One of
the values for this enumeration is named Create. The
following XML fragment shows how to configure this property
- <object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests">
+ <object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="name" value="Rod"/>
<property name="FileMode" value="Create"/>
</object>
-
+ Built-in TypeConvertersSpring.NET pre-registers a number of custom
- TypeConverter instances (for example, to convert
+ TypeConverter instances (for example, to convert
a type expressed as a string into a real
- System.Type object). Each of those is listed
+ System.Type object). Each of those is listed
below and they are all located in the
Spring.Objects.TypeConverters namespace of the
Spring.Core library.
- Built-in TypeConverters
+ Built-in TypeConverters
@@ -3250,8 +3265,8 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
RuntimeTypeConverterParses strings representing
- System.Types to actual
- System.Types and the other way
+ System.Types to actual
+ System.Types and the other way
around.
@@ -3259,7 +3274,7 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
FileInfoConverterCapable of resolving strings to a
- System.IO.FileInfo object.
+ System.IO.FileInfo object.
@@ -3304,7 +3319,7 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
Capable of resolving a two part string (resource name,
assembly name) to a
- System.Resources.ResourceManager
+ System.Resources.ResourceManager
object.
@@ -3313,14 +3328,14 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
Capable of resolving a comma separated list of Red,
Green, Blue integer values to a
- System.Drawing.Color structure.
+ System.Drawing.Color structure.
ExpressionConverterCapable of resolving a string into an instance of an
- object that implements the IExpression
+ object that implements the IExpression
interface.
@@ -3349,28 +3364,28 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
Spring.NET uses the standard .NET mechanisms for the resolution of
- System.Types, including, but not limited to
+ System.Types, including, but not limited to
checking any configuration files associated with your application,
checking the Global Assembly Cache (GAC), and assembly probing.
-
+ Custom Type ConversionThere are a few ways to register custom type converters. The
fundamental storage area in Spring for custom type converters is the
- TypeConverterRegistry class. The most
+ TypeConverterRegistry class. The most
convenient way if using an XML based implementation of
- IObjectFactory or
- IApplicationContext is to use the custom
+ IObjectFactory or
+ IApplicationContext is to use the custom
configuration section handler
- TypeConverterSectionHandler This is demonstrated
+ TypeConverterSectionHandler This is demonstrated
in section An alternate approach, present for legacy reasons in the port of
Spring.NET from the Java code base, is to use the object factory
post-processor
- Spring.Objects.Factory.Config.CustomConverterConfigurer.
+ Spring.Objects.Factory.Config.CustomConverterConfigurer.
This is described in the next section.If you are constructing your IoC container Programatically then
@@ -3378,19 +3393,19 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
TypeConverter converter) method of the
ConfigurableObjectFactory interface.
-
+ Using CustomConverterConfigurerThis section shows in detail how to define a custom type
converter that does not use the .NET
- TypeConverter attribute. The type converter
+ TypeConverter attribute. The type converter
class is standalone and inherits from the
- TypeConverter class. It uses the legacy factory
+ TypeConverter class. It uses the legacy factory
post-processor approach.Consider a user class ExoticType, and
another class DependsOnExoticType which needs
- ExoticType set as a property:public class ExoticType
+ ExoticType set as a property:public class ExoticType
{
private string name;
@@ -3403,7 +3418,7 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
{
get { return this.name; }
}
-} and public class DependsOnExoticType
+} and public class DependsOnExoticType
{
public DependsOnExoticType() {}
@@ -3422,10 +3437,10 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
} When things are properly set up, we want to be able to
assign the type property as a string, which a TypeConverter will
convert into a real ExoticType object behind the scenes:
- <object name="sample" type="SimpleApp.DependsOnExoticType, SimpleApp">
+ <object name="sample" type="SimpleApp.DependsOnExoticType, SimpleApp">
<property name="exoticType" value="aNameForExoticType"/>
</object> The TypeConverter looks like this:
- public class ExoticTypeConverter : TypeConverter
+ public class ExoticTypeConverter : TypeConverter
{
public ExoticTypeConverter()
{
@@ -3454,10 +3469,10 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
return base.ConvertFrom (context, culture, value);
}
} Finally, we use the
- CustomConverterConfigurer to register the new
- TypeConverter with the
- IApplicationContext, which will then be able to
- use it as needed: <object id="customConverterConfigurer"
+ CustomConverterConfigurer to register the new
+ TypeConverter with the
+ IApplicationContext, which will then be able to
+ use it as needed: <object id="customConverterConfigurer"
type="Spring.Objects.Factory.Config.CustomConverterConfigurer, Spring.Core">
<property name="CustomConverters">
<dictionary>
@@ -3471,10 +3486,10 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
-
+ Customizing the nature of an object
-
+ Lifecycle interfacesSpring.NET uses several marker interfaces to change the behaviour
@@ -3488,25 +3503,25 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
objects.Internally, Spring.NET uses implementations of the
- IObjectPostProcessor interface to process any
+ IObjectPostProcessor interface to process any
marker interfaces it can find and call the appropriate methods. If you
need custom features or other lifecycle behavior Spring.NET doesn't
offer out-of-the-box, you can implement an
- IObjectPostProcessor yourself. More information
+ IObjectPostProcessor yourself. More information
about this can be found in .All the different lifecycle marker interfaces are described
below.
-
+ IInitializingObject / init-methodThe
- Spring.Objects.Factory.IInitializingObject
+ Spring.Objects.Factory.IInitializingObject
interface gives you the ability to perform initialization work after
all the necessary properties on an object are set by the container.
- The IInitializingObject interface specifies
+ The IInitializingObject interface specifies
exactly one method: void AfterPropertiesSet(): called
@@ -3514,7 +3529,7 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
enables you to do checking to see if all necessary properties
have been set correctly, or to perform further initialization
work. You can throw any
- Exception to indicate misconfiguration,
+ Exception to indicate misconfiguration,
initialization failures, etc.
@@ -3522,7 +3537,7 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
Generally, the use of the
- IInitializingObject
+ IInitializingObject
can be avoided. The
@@ -3531,7 +3546,7 @@ public sealed class Font : MarshalByRefObject, ICloneable, ISerializable, IDispo
library provides support for a generic init-method, given to the object definition in the object configuration store (be it XML, or a database, etc).
- <object id="exampleInitObject" type="Examples.ExampleObject" init-method="init"/>
+ <object id="exampleInitObject" type="Examples.ExampleObject" init-method="init"/>
[C#]
public class ExampleObject
{
@@ -3539,7 +3554,7 @@ public class ExampleObject
{
// do some initialization work
}
-} Is exactly the same as... <object id="exampleInitObject" type="Examples.AnotherExampleObject"/>
+} Is exactly the same as... <object id="exampleInitObject" type="Examples.AnotherExampleObject"/>
[C#]
public class AnotherExampleObject : IInitializingObject
{
@@ -3570,34 +3585,34 @@ public class AnotherExampleObject : IInitializingObject
-
+ IDisposable / destroy-method
- The System.IDisposable interface provides
+ The System.IDisposable interface provides
you with the ability to get a callback when an
- IObjectFactory is destroyed. The
- IDisposable interface specifies exactly one
+ IObjectFactory is destroyed. The
+ IDisposable interface specifies exactly one
method: void Dispose(): and is called on
destruction of the container. This allows you to release any
resources you are keeping in this object (such as database
connections). You can throw any
- Exception here... however, any such
- Exception will not stop the destruction
+ Exception here... however, any such
+ Exception will not stop the destruction
of the container - it will only get logged.Note: If you choose you can avoid having your class
- implement IDisposable since the
+ implement IDisposable since the
Spring.Core library provides support for a
generic destroy-method, given to the object definition in the object
configuration store (be it XML, or a database, etc).
- <object id="exampleInitObject" type="Examples.ExampleObject" destroy-method="cleanup"/>
+ <object id="exampleInitObject" type="Examples.ExampleObject" destroy-method="cleanup"/>
[C#]
public class ExampleObject
{
@@ -3605,7 +3620,7 @@ public class ExampleObject
{
// do some destruction work (such as closing any open connection (s))
}
-} is exactly the same as: <object id="exampleInitObject" type="Examples.AnotherExampleObject"/>
+} is exactly the same as: <object id="exampleInitObject" type="Examples.AnotherExampleObject"/>
[C#]
public class AnotherExampleObject : IDisposable
{
@@ -3617,16 +3632,16 @@ public class AnotherExampleObject : IDisposable
-
+ Knowing who you are
-
+ IObjectFactoryAwareA class which implements the
- Spring.Objects.Factory.IObjectFactoryAware
+ Spring.Objects.Factory.IObjectFactoryAware
interface is provided with a reference to the
- IObjectFactory that created it. The interface
+ IObjectFactory that created it. The interface
specifies one (write-only) property: IObjectFactory ObjectFactory: the
@@ -3637,8 +3652,8 @@ public class AnotherExampleObject : IDisposable
This allows objects to manipulate the
- IObjectFactory that created them
- Programatically, through the IObjectFactory
+ IObjectFactory that created them
+ Programatically, through the IObjectFactory
interface, or by casting the reference to a known subclass of this
which exposes additional functionality. Primarily this would consist
of programmatic retrieval of other objects. While there are cases when
@@ -3648,11 +3663,11 @@ public class AnotherExampleObject : IDisposable
properties.
-
+ IObjectNameAwareThe
- Spring.Objects.Factory.IObjectNameAware
+ Spring.Objects.Factory.IObjectNameAware
interface gives you the ability to let the container set the name of
the object definition on the object instance itself. In those cases
where your object needs to know what its name is, implement this
@@ -3666,7 +3681,7 @@ public class AnotherExampleObject : IDisposable
-
+ Object definition inheritanceAn object definition potentially contains a large amount of
@@ -3678,17 +3693,17 @@ public class AnotherExampleObject : IDisposable
parent and child object definitions can potentially save a lot of typing.
Effectively, this is a form of templating.
- When working with an IObjectFactory
+ When working with an IObjectFactory
Programatically, child object definitions are represented by the
- ChildObjectDefinition class. Most users will never
+ ChildObjectDefinition class. Most users will never
work with them on this level, instead configuring object definitions
declaratively in something like the
- XmlObjectFactory. In an
- XmlObjectFactory object definition, a child object
+ XmlObjectFactory. In an
+ XmlObjectFactory object definition, a child object
definition is indicated simply by using the parent attribute, specifying
the parent object definition as the value of this attribute.
- <object id="inheritedTestObject" type="Spring.Objects.TestObject, Spring.Core.Tests">
+ <object id="inheritedTestObject" type="Spring.Objects.TestObject, Spring.Core.Tests">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</object>
@@ -3717,7 +3732,7 @@ public class AnotherExampleObject : IDisposable
In the case where the parent definition does not specify a
class...
- <object id="inheritedTestObjectWithoutClass" abstract="true">
+ <object id="inheritedTestObjectWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</object>
@@ -3751,22 +3766,22 @@ public class AnotherExampleObject : IDisposable
-
+ Interacting with the containerThe Spring container is essentially nothing more than an advanced
factory capable of maintaining a registry of different objects and their
- dependencies. The IObjectFactory enables you to
+ dependencies. The IObjectFactory enables you to
read object definitions and access them using the object factory. When
- using just the IObjectFactory you would create an
+ using just the IObjectFactory you would create an
instance of one and then read in some object definitions in the XML format
- as follows: [C#]
+ as follows: [C#]
IResource input = new FileSystemResource ("objects.xml");
XmlObjectFactory factory = new XmlObjectFactory(input);That is pretty much it. Using GetObject(string)
(or the more concise indexer method factory ["string"])
- you can retrieve instances of your objects... [C#]
+ you can retrieve instances of your objects... [C#]
object foo = factory.GetObject ("foo"); // gets the object defined as 'foo'
object bar = factory ["bar"]; // same thing, just using the indexer
@@ -3774,9 +3789,9 @@ object bar = factory ["bar"]; // same thing, just using the indexer
You'll get a reference to the same object if you defined it as a
singleton (the default) or you'll get a new instance each time if you set
the singleton property of your object definition to
- false. <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/>
+ false. <object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/>
<object id="anotherObject" type="Examples.ExampleObject, ExamplesLibrary" singleton="false"/>
- [C#]
+ [C#]
object one = factory ["exampleObject"]; // gets the object defined as 'exampleObject'
object two = factory ["exampleObject"];
Console.WriteLine (one == two) // prints 'true'
@@ -3785,13 +3800,13 @@ object four = factory ["anotherObject"];
Console.WriteLine (three == four); // prints 'false'
- The client-side view of the IObjectFactory is
- surprisingly simple. The IObjectFactory interface
+ The client-side view of the IObjectFactory is
+ surprisingly simple. The IObjectFactory interface
has only seven methods (and the aforementioned indexer) for clients to
call: bool ContainsObject(string): returns true
- if the IObjectFactory contains an object
+ if the IObjectFactory contains an object
definition that matches the given name.
@@ -3799,7 +3814,7 @@ Console.WriteLine (three == four); // prints 'false'
object GetObject(string): returns an
instance of the object registered under the given name. Depending on
how the object was configured by the
- IObjectFactory configuration, either a
+ IObjectFactory configuration, either a
singleton (and thus shared) instance or a newly created object will
be returned. An ObjectsException will be thrown
when either the object could not be found (in which case it'll be a
@@ -3809,7 +3824,7 @@ Console.WriteLine (three == four); // prints 'false'
Object this [string]: this is the indexer
- for the IObjectFactory interface. It
+ for the IObjectFactory interface. It
functions in all other respects in exactly the same way as the
GetObject(string) method. The rest of this
documentation will always refer to the
@@ -3821,7 +3836,7 @@ Console.WriteLine (three == four); // prints 'false'
Object GetObject(string, Type): returns an
object, registered under the given name. The object returned will be
- cast to the given Type. If the object could
+ cast to the given Type. If the object could
not be cast, corresponding exceptions will be thrown
(ObjectNotOfRequiredTypeException). Furthermore,
all rules of the GetObject(string) method apply
@@ -3840,7 +3855,7 @@ Console.WriteLine (three == four); // prints 'false'
string[] GetAliases(string): returns the
aliases for the given object name, if any were defined in the
- IObjectDefinition.
+ IObjectDefinition.
@@ -3862,8 +3877,8 @@ Console.WriteLine (three == four); // prints 'false'
- A sub-interface of IObjectFactory,
- IConfigurableObjectFactory adds some convenient
+ A sub-interface of IObjectFactory,
+ IConfigurableObjectFactory adds some convenient
methods such as
@@ -3881,27 +3896,27 @@ Console.WriteLine (three == four); // prints 'false'
Check the SDK docs for additional details on
IConfigurableObjectFactory methods and properties and the full
- IObjectFactory class hierarchy.
+ IObjectFactory class hierarchy.
- Obtaining an IFactoryObject, not its
+ Obtaining an IFactoryObject, not its
productSometimes there is a need to ask an
- IObjectFactory for an actual
- IFactoryObject instance itself, not the object it
+ IObjectFactory for an actual
+ IFactoryObject instance itself, not the object it
produces. This may be done by prepending the object id with
& when calling the
GetObject method of the
- IObjectFactory and
- IApplicationContext interfaces. So for a given
- IFactoryObject with an id
+ IObjectFactory and
+ IApplicationContext interfaces. So for a given
+ IFactoryObject with an id
myObject, invoking
GetObject("myObject") on the
- IObjectFactory will return the product of the
- IFactoryObject, but invoking
+ IObjectFactory will return the product of the
+ IFactoryObject, but invoking
GetObject("&myObject") will return the
- IFactoryObject instance itself.
+ IFactoryObject instance itself.
@@ -3910,66 +3925,66 @@ Console.WriteLine (three == four); // prints 'false'
The IoC component of the Spring Framework has been designed for
extension. There is typically no need for an application developer to
- subclass any of the various IObjectFactory or
- IApplicationContext implementation classes. The
+ subclass any of the various IObjectFactory or
+ IApplicationContext implementation classes. The
Spring IoC container can be infinitely extended by plugging in
implementations of special integration interfaces. The next few sections
are devoted to detailing all of these various integration
interfaces.
-
+ Customizing objects with
IObjectPostProcessorsThe first extension point that we will look at is the
- Spring.Objects.Factory.Config.IObjectPostProcessor
+ Spring.Objects.Factory.Config.IObjectPostProcessor
interface. This interface defines a number of callback methods that you
as an application developer can implement in order to provide your own
(or override the containers default) instantiation logic,
dependency-resolution logic, and so forth. If you want to do some custom
logic after the Spring container has finished instantiating, configuring
and otherwise initializing an object, you can plug in one or more
- IObjectPostProcessor implementations.
+ IObjectPostProcessor implementations.
You can configure multiple
- IObjectPostProcessors if you wish. You can
+ IObjectPostProcessors if you wish. You can
control the order in which these
- IObjectPostProcessor execute by setting the
+ IObjectPostProcessor execute by setting the
'Order' property (you can only set this property if the
- IObjectPostProcessor implements the
- IOrdered interface; if you write your own
- IObjectPostProcessor you should consider
- implementing the IOrdered interface too); consult
- the SDK docs for the IObjectPostProcessor and
- IOrdered interfaces for more details.
+ IObjectPostProcessor implements the
+ IOrdered interface; if you write your own
+ IObjectPostProcessor you should consider
+ implementing the IOrdered interface too); consult
+ the SDK docs for the IObjectPostProcessor and
+ IOrdered interfaces for more details.
- IObjectPostProcessor operate on object
+ IObjectPostProcessor operate on object
instances; that is to say, the Spring IoC container will have
instantiated a object instance for you, and then
- IObjectPostProcessors get a chance to do their
+ IObjectPostProcessors get a chance to do their
stuff. If you want to change the actual object definition (that is the
recipe that defines the object), then you rather need to use a
- IObjectFactoryPostProcessor (described below in
+ IObjectFactoryPostProcessor (described below in
the section entitled Customizing
configuration metadata with
IObjectFactoryPostProcessors.
- Also, IObjectPostProcessors are scoped
+ Also, IObjectPostProcessors are scoped
per-container. This is only relevant if you are using container
hierarchies. If you define a
- IObjectPostProcessor in one container, it will
+ IObjectPostProcessor in one container, it will
only do its stuff on the objects in that container. Objects that are
defined in another container will not be post-processed by
- IObjectPostProcessors in another container,
+ IObjectPostProcessors in another container,
even if both containers are part of the same hierarchy.The
- Spring.Objects.Factory.Config.IObjectPostProcessor
+ Spring.Objects.Factory.Config.IObjectPostProcessor
interface, which consists of two callback methods shown below.
- object PostProcessBeforeInitialization(object instance, string name);
+ object PostProcessBeforeInitialization(object instance, string name);
object PostProcessAfterInitialization(object instance, string name);When
such a class is registered as a post-processor with the container, for
@@ -3978,7 +3993,7 @@ object PostProcessAfterInitialization(object instance, string name);before any initialization methods
(such as the AfterPropertiesSet method of the
- IInitializingObject interface and any declared
+ IInitializingObject interface and any declared
init method) are called, and also afterwards. The post-processor is free
to do what it wishes with the object, including ignoring the callback
completely. An object post-processor will typically check for marker
@@ -3988,9 +4003,9 @@ object PostProcessAfterInitialization(object instance, string name);Other extensions to the IObjectPostProcessors
interface are
- IInstantiationAwareObjectPostProcessor and
- IDestructionAwareObjectPostProcessor defined
- below public interface IInstantiationAwareObjectPostProcessor : IObjectPostProcessor
+ IInstantiationAwareObjectPostProcessor and
+ IDestructionAwareObjectPostProcessor defined
+ below public interface IInstantiationAwareObjectPostProcessor : IObjectPostProcessor
{
object PostProcessBeforeInstantiation(Type objectType, string objectName);
@@ -4002,7 +4017,7 @@ object PostProcessAfterInitialization(object instance, string name); The PostProcessBeforeInstantiation
+} The PostProcessBeforeInstantiation
callback method is called right before the container creates the object.
If the object returned by this method is not null then the default
instantiation behavior of the container is short circuited. The returned
@@ -4010,38 +4025,38 @@ public interface IDestructionAwareObjectPostProcessor : IObjectPostProcessor
IObjectPostProcessor callbacks will be invoked on it.
This mechanism is useful if you would like to expose a proxy to the
object instead of the actual target object. The
- PostProcessAfterInstantiation callback method is
+ PostProcessAfterInstantiation callback method is
called after the object has been instantiated but before Spring performs
property population based on explicit properties or autowiring. A return
value of false would short circuit the standard Spring based property
population. The callback method
- PostProcessPropertyValues is called after Spring
+ PostProcessPropertyValues is called after Spring
collects all the property values to apply to the object, but before they
are applied. This gives you the opportunity to perform additional
processing such as making sure that a property is set to a value if it
- contains a [Required] attribute or to perform
+ contains a [Required] attribute or to perform
attribute based wiring, i.e. adding the attribute
- [Inject("objectName")] on a property. Both of
+ [Inject("objectName")] on a property. Both of
these features are scheduled to be included in Spring .12.
- The IDestructionAwareObjectPostProcessor
+ The IDestructionAwareObjectPostProcessor
callback contains a single method,
- PostProcessBeforeDestruction, which is called
+ PostProcessBeforeDestruction, which is called
before a singleton's destroy method is invoked.It is important to know that the
- IObjectFactory treats object post-processors
+ IObjectFactory treats object post-processors
slightly differently than the
- IApplicationContext. An
- IApplicationContext will automatically detect any
+ IApplicationContext. An
+ IApplicationContext will automatically detect any
objects which are deployed into it that implement the
- IObjectPostProcessor interface, and register them
+ IObjectPostProcessor interface, and register them
as post-processors, to be then called appropriately by the factory on
object creation. Nothing else needs to be done other than deploying the
post-processor in a similar fashion to any other object. On the other
hand, when using plain IObjectFactories, object
post-processors have to manually be explicitly registered, with a code
- sequence such as... ConfigurableObjectFactory factory = new .....; // create an IObjectFactory
+ sequence such as... ConfigurableObjectFactory factory = new .....; // create an IObjectFactory
... // now register some objects
// now register any needed IObjectPostProcessors
MyObjectPostProcessor pp = new MyObjectPostProcessor();
@@ -4051,8 +4066,8 @@ factory.AddObjectPostProcessor(pp);
This explicit registration step is not convenient, and this is one
of the reasons why the various
- IApplicationContext implementations are preferred
- above plain IObjectFactory implementations in the
+ IApplicationContext implementations are preferred
+ above plain IObjectFactory implementations in the
vast majority of Spring-backed applications, especially when using
IObjectPostProcessors.
@@ -4060,26 +4075,26 @@ factory.AddObjectPostProcessor(pp);
IObjectPostProcessors and AOP auto-proxyingClasses that implement the
- IObjectPostProcessor interface are special, and
+ IObjectPostProcessor interface are special, and
so they are treated differently by the container. All
- IObjectPostProcessors and their directly
+ IObjectPostProcessors and their directly
referenced object will be instantiated on startup, as part of the
special startup phase of the IApplicationContext, then all those
- IObjectPostProcessors will be registered in a
+ IObjectPostProcessors will be registered in a
sorted fashion - and applied to all further objects. Since AOP
auto-proxying is implemented as a
- IObjectPostProcessor itself, no
- IObjectPostProcessors or directly referenced
+ IObjectPostProcessor itself, no
+ IObjectPostProcessors or directly referenced
objects are eligible for auto-proxying (and thus will not have aspects
'woven' into them). For any such object, you should see an info log
message: “Object 'foo' is not eligible for getting processed by all
- IObjectPostProcessors (for example: not
+ IObjectPostProcessors (for example: not
eligible for auto-proxying)”.
-
+ Example: Hello World, IObjectPostProcessor-styleThis first example is hardly compelling, but serves to
@@ -4095,7 +4110,7 @@ factory.AddObjectPostProcessor(pp);
Find below the custom IObjectPostProcessor implementation class
definition
- using System;
+ using System;
using Spring.Objects.Factory.Config;
namespace Spring.IocQuickStart.MovieFinder
@@ -4115,7 +4130,7 @@ namespace Spring.IocQuickStart.MovieFinder
}
}And the following configuration
- <?xml version="1.0" encoding="utf-8" ?>
+ <?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net" >
<description>An example that demonstrates simple IoC features.</description>
@@ -4129,7 +4144,7 @@ namespace Spring.IocQuickStart.MovieFinder
<!-- when the above objects are instantiated, this custom IObjectPostProcessor implementation
will output the fact to the system console -->
- <object type="Spring.IocQuickStart.MovieFinder.TracingObjectPostProcessor, Spring.IocQuickStart.MovieFinder"/>
+ <object type="Spring.IocQuickStart.MovieFinder.TracingObjectPostProcessor, Spring.IocQuickStart.MovieFinder"/>
</objects>Notice how the TracingObjectPostProcessor is simply defined; it
@@ -4139,7 +4154,7 @@ namespace Spring.IocQuickStart.MovieFinder
Find below a small driver script to exercise the above code and
configuration;
- IApplicationContext ctx =
+ IApplicationContext ctx =
new XmlApplicationContext(
"assembly://Spring.IocQuickStart.MovieFinder/Spring.IocQuickStart.MovieFinder/AppContext.xml");
@@ -4162,7 +4177,7 @@ DEBUG - Movie Title = 'La vita e bella', Director = 'Roberto Benigni'.
DEBUG - MovieApp Done.
-
+ Example: the RequiredAttributeObjectPostProcessorUsing callback interfaces or annotations in conjunction with a
@@ -4173,13 +4188,13 @@ DEBUG - MovieApp Done.
being 'required-to-be-set' (i.e. an setter
property with this attribute applied must be configured to be
dependency injected with a value), else an
- ObjectInitializationException will be thrown by
+ ObjectInitializationException will be thrown by
the container at runtime.The best way to illustrate the usage of this attribute is with
an example.
- public class MovieLister
+ public class MovieLister
{
// the MovieLister has a dependency on the MovieFinder
private IMovieFinder _movieFinder;
@@ -4197,13 +4212,13 @@ DEBUG - MovieApp Done.Hopefully the above class definition reads easy on the eye. Any
and all IObjectDefinitions for the
- MovieLister class must be provided with a
+ MovieLister class must be provided with a
value.Let's look at an example of some XML configuraiton that will not
pass validation.
- <object id="MyMovieLister"
+ <object id="MyMovieLister"
type="Spring.IocQuickStart.MovieFinder.MovieLister, Spring.IocQuickStart.MovieFinder">
<!-- whoops, no MovieFinder is set (and this property is [Required]) -->
</object>
@@ -4221,81 +4236,81 @@ DEBUG - MovieApp Done.
appropriately.This component is the
- RequiredAttributeObjectPostProcessor class.
+ RequiredAttributeObjectPostProcessor class.
This is a special IObjectPostProcessor
implementation that is [Required]-aware and
actually provides the 'blow up if this required property has not been
set' logic. It is very easy to configure; simply drop the following
object definition into your Spring XML configuration.
- <object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core"/>
+ <object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core"/>Finally, one can configure an instance of the
- RequiredAttributeObjectPostProcessor class to
+ RequiredAttributeObjectPostProcessor class to
look for another Attribute type. This is great if
you already have your own [Required]-style
attribute. Simply plug it into the definition of a
- RequiredAttributeObjectPostProcessor and you
+ RequiredAttributeObjectPostProcessor and you
are good to go. By way of an example, let's suppose you (or your
organization / team) have defined an attribute called [Mandatory]. You
- can make a RequiredAttributeObjectPostProcessor
+ can make a RequiredAttributeObjectPostProcessor
instance [Mandatory]-aware like so:
- <object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core">
+ <object type="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor, Spring.Core">
<property name="RequiredAttributeType" value="MyApp.Attributes.MandatoryAttribute, MyApp"/>
</object>
-
+ Customizing configuration metadata with
ObjectFactoryPostProcessorsThe next extension point that we will look at is the
- Spring.Objects.Factory.Config.IObjectFactoryPostProcessor.
+ Spring.Objects.Factory.Config.IObjectFactoryPostProcessor.
The semantics of this interface are similar to the
- IObjectPostProcessor, with one major difference.
- IObjectFactoryPostProcessors operate on; that is
+ IObjectPostProcessor, with one major difference.
+ IObjectFactoryPostProcessors operate on; that is
to say, the Spring IoC container will allow
- IObjectFactoryPostProcessors to read the
+ IObjectFactoryPostProcessors to read the
configuration metadata and potentially change it before the container
has actually instantiated any other objects. By implementing this
interface, you will receive a callback after the all the object
definitions have been loaded into the IoC container but before they have
been instantiated. The signature of the interface is shown below
- public interface IObjectFactoryPostProcessor
+ public interface IObjectFactoryPostProcessor
{
void PostProcessObjectFactory (IConfigurableListableObjectFactory factory);
}
You can configure multiple
- IObjectFactoryPostProcessors if you wish. You can
+ IObjectFactoryPostProcessors if you wish. You can
control the order in which these
- IObjectFactoryPostProcessors execute by setting
+ IObjectFactoryPostProcessors execute by setting
the 'Order' property (you can only set this property if the
- IObjectFactoryPostProcessors implements the
- IOrdered interface; if you write your own
- IObjectFactoryPostProcessors you should consider
- implementing the IOrdered interface too); consult
- the SDK docs for the IObjectFactoryPostProcessors
- and IOrdered interfaces for more details.
+ IObjectFactoryPostProcessors implements the
+ IOrdered interface; if you write your own
+ IObjectFactoryPostProcessors you should consider
+ implementing the IOrdered interface too); consult
+ the SDK docs for the IObjectFactoryPostProcessors
+ and IOrdered interfaces for more details.
If you want to change the actual object instances (the objects
that are created from the configuration metadata), then you rather
- need to use a IObjectObjectPostProcessor
+ need to use a IObjectObjectPostProcessor
(described above in the section entitled Customizing objects with
IObjectPostProcessors.
- Also, IObjectFactoryPostProcessors are
+ Also, IObjectFactoryPostProcessors are
scoped per-container. This is only relevant if you are using container
hierarchies. If you define a
- IObjectFactoryPostProcessors in one container,
+ IObjectFactoryPostProcessors in one container,
it will only do its stuff on the object definitions in that container.
Object definitions in another container will not be post-processed by
- IObjectFactoryPostProcessors in another
+ IObjectFactoryPostProcessors in another
container, even if both containers are part of the same
hierarchy.
@@ -4311,11 +4326,11 @@ DEBUG - MovieApp Done.
objects transactionally or with any other kind of proxy, as described
later in this manual.
- In an IObjectFactory, the process of
- applying an IObjectFactoryPostProcessor is
+ In an IObjectFactory, the process of
+ applying an IObjectFactoryPostProcessor is
manual, and will be similar to this:
- XmlObjectFactory factory = new XmlObjectFactory(new FileSystemResource("objects.xml"));
+ XmlObjectFactory factory = new XmlObjectFactory(new FileSystemResource("objects.xml"));
// create placeholderconfigurer to bring in some property
// values from a Properties file
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
@@ -4326,13 +4341,13 @@ cfg.PostProcessObjectFactory(factory);This
explicit registration step is not convenient, and this is one of the
- reasons why the various IApplicationContext
+ reasons why the various IApplicationContext
implementations are preferred above plain
- IObjectFactory implementations in the vast
+ IObjectFactory implementations in the vast
majority of Spring-backed applications, especially when using
- IObjectFactoryPostProcessors.
+ IObjectFactoryPostProcessors.
- An IApplicationContext will detect any
+ An IApplicationContext will detect any
objects which are deployed into it that implement the
ObjectFactoryPostProcessor interface, and
automatically use them as object factory post-processors, at the
@@ -4341,22 +4356,22 @@ cfg.PostProcessObjectFactory(factory);Just as in the case of
- IObjectPostProcessors, you typically don't want
- to have IObjectFactoryPostProcessors marked as
+ IObjectPostProcessors, you typically don't want
+ to have IObjectFactoryPostProcessors marked as
being lazily-initialized. If they are marked as such, then the Spring
container will never instantiate them, and thus they won't get a
chance to apply their custom logic. If you are using the
'default-lazy-init' attribute on the declaration of your
<objects/> element, be sure to mark your various
- IObjectFactoryPostProcessor object definitions
+ IObjectFactoryPostProcessor object definitions
with 'lazy-init="false"'.
-
+ Example: The
- PropertyPlaceholderConfigurer
+ PropertyPlaceholderConfigurer
- The PropertyPlaceholderConfigurer is an
+ The PropertyPlaceholderConfigurer is an
excellent solution when you want to externalize a few properties from
a file containing object definitions. This is useful to allow the
person deploying an application to customize environment specific
@@ -4371,14 +4386,14 @@ cfg.PostProcessObjectFactory(factory);Note that IApplicationContexts are able to
automatically recognize and apply objects deployed in them that
- implement the IObjectFactoryPostProcessor
+ implement the IObjectFactoryPostProcessor
interface. This means that as described here, applying a
- PropertyPlaceholderConfigurer is much more
- convenient when using an IApplicationContext.
+ PropertyPlaceholderConfigurer is much more
+ convenient when using an IApplicationContext.
For this reason, it is recommended that users wishing to use this or
other object factory postprocessors use an
- IApplicationContext instead of an
- IObjectFactory.
+ IApplicationContext instead of an
+ IObjectFactory.In the example below a data access object needs to be configured
with a database connection and also a value for the maximum number of
@@ -4386,7 +4401,7 @@ cfg.PostProcessObjectFactory(factory);
the main Spring.NET configuration file we use place holders, in the
NAnt style of ${variableName}, and obtain their values from
NameValueSections in the standard .NET application configuration file.
- The Spring.NET configuration file looks like: <configuration>
+ The Spring.NET configuration file looks like: <configuration>
<configSections>
<sectionGroup name="spring">
@@ -4420,18 +4435,18 @@ cfg.PostProcessObjectFactory(factory);
in deployment. This Spring.NET configuration file is shown
below.
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd" >
<object name="productDao" type="DaoApp.SimpleProductDao, DaoApp ">
- <property name="maxResults" value="${maxResults}"/>
+ <property name="maxResults" value="${maxResults}"/>
<property name="dbConnection" ref="myConnection"/>
</object>
<object name="myConnection" type="System.Data.Odbc.OdbcConnection, System.Data">
- <property name="connectionstring" value="${connection.string}"/>
+ <property name="connectionstring" value="${connection.string}"/>
</object>
<object name="appConfigPropertyHolder"
@@ -4448,17 +4463,17 @@ cfg.PostProcessObjectFactory(factory);${connection.string} match the key names used in
the two NameValueSectionHandlers DaoConfiguration
and DatabaseConfiguration. The
- PropertyPlaceholderConfigurer refers to these
+ PropertyPlaceholderConfigurer refers to these
two sections via a comma delimited list of section names in the
configSections property. If you are using section
groups, prefix the section group name, for example
myConfigSection/DaoConfiguraiton.
- The PropertyPlaceholderConfigurer class
+ The PropertyPlaceholderConfigurer class
also supports retrieving name value pairs from other
- IResource locations. These can be specified
+ IResource locations. These can be specified
using the Location and Locations
- properties of the PropertyPlaceHolderConfigurer
+ properties of the PropertyPlaceHolderConfigurer
class.If there are properties with the same name in different resource
@@ -4471,11 +4486,11 @@ cfg.PostProcessObjectFactory(factory);
In an ASP.NET environment you must specify the full, four-part name of the assembly when using a
- NameValueFileSectionHandler
+ NameValueFileSectionHandler
-
+
<section name="hibernateConfiguration"
type="System.Configuration.NameValueFileSectionHandler, System,
Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
@@ -4491,7 +4506,7 @@ cfg.PostProcessObjectFactory(factory);
type names, which is sometimes useful when you have to pick a
particular implementation class at runtime. For example:
- <object id="MyMovieFinder" type="${custom.moviefinder.type}"/>
+ <object id="MyMovieFinder" type="${custom.moviefinder.type}"/>If the class is unable to be resolved at runtime to a valid
type, resolution of the object will fail once it is about to be
@@ -4501,13 +4516,13 @@ cfg.PostProcessObjectFactory(factory);Similarly you can replace 'ref' and 'expression' metadata, as
shown below
- <object id="TestObject" type="Simple.TestObject, MyAssembly">
+ <object id="TestObject" type="Simple.TestObject, MyAssembly">
<property name="age" expression="${ageExpression}"/>
<property name="spouse" ref="${spouse-ref}"/>
</object>
-
+ Replacement with Environment VariablesYou may also use the value environment variables to replace
@@ -4515,7 +4530,7 @@ cfg.PostProcessObjectFactory(factory);
controlled via the property
EnvironmentVariableMode. This property is an
enumeration of the type
- EnvironmentVariablesMode and has three
+ EnvironmentVariablesMode and has three
values, Never, Fallback, and Override. Fallback
is the default value and will resolve a property placeholder if it
was not already done so via a value from a resource location.
@@ -4523,8 +4538,8 @@ cfg.PostProcessObjectFactory(factory);
applying values defined from a resource location.
Never will, quite appropriately, disable
environment variable substitution. An example of how the
- PropertyPlaceholderConfigurer XML is modified
- to enable override usage is shown below <object name="appConfigPropertyHolder"
+ PropertyPlaceholderConfigurer XML is modified
+ to enable override usage is shown below <object name="appConfigPropertyHolder"
type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
<property name="configSections" value="DaoConfiguration,DatabaseConfiguration"/>
<property name="EnvironmentVariableMode" value="Override"/>
@@ -4533,13 +4548,13 @@ cfg.PostProcessObjectFactory(factory);
-
+ Example: The
- PropertyOverrideConfigurer
+ PropertyOverrideConfigurer
- The PropertyOverrideConfigurer, another
+ The PropertyOverrideConfigurer, another
object factory post-processor, is similar to the
- PropertyPlaceholderConfigurer, but in contrast
+ PropertyPlaceholderConfigurer, but in contrast
to the latter, the original definitions can have default values or no
values at all for object properties. If an overriding configuration
file does not have an entry for a certain object property, the default
@@ -4549,16 +4564,16 @@ cfg.PostProcessObjectFactory(factory);not aware of being overridden, so it is not
immediately obvious when looking at the XML definition file that the
override configurer is being used. In case that there are multiple
- PropertyOverrideConfigurer instances that
+ PropertyOverrideConfigurer instances that
define different values for the same object property, the last one
will win (due to the overriding mechanism).
The example usage is similar to when using
- PropertyPlaceHolderConfigurer except that the
+ PropertyPlaceHolderConfigurer except that the
key name refers to the name given to the object in the Spring.NET
configuration file and is suffixed via 'dot' notation with the name of
the property For example, if the application configuration file is
- <configuration>
+ <configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
@@ -4578,7 +4593,7 @@ cfg.PostProcessObjectFactory(factory);
</configuration> Then the value of 1000 will be used to
overlay the value of 2000 set in the Spring.NET configuration file
- shown below <objects xmlns="http://www.springframework.net"
+ shown below <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd" >
@@ -4607,7 +4622,7 @@ cfg.PostProcessObjectFactory(factory);
</objects>
-
+ IVariableSourceThe IVariableSource is the base interface for providing the
@@ -4622,45 +4637,45 @@ cfg.PostProcessObjectFactory(factory);
- ConfigSectionVariableSource
+ ConfigSectionVariableSource
- PropertyFileVariableSource
+ PropertyFileVariableSource
- EnvironmentVariableSource
+ EnvironmentVariableSource
- CommandLineArgsVariableSource
+ CommandLineArgsVariableSource
- RegistryVariableSource
+ RegistryVariableSource
- SpecialFolderVariableSource
+ SpecialFolderVariableSource
- ConnectionStringsVariableSource
+ ConnectionStringsVariableSourceYou use this by defining an instance of
- Spring.Objects.Factory.Config.VariablePlaceholderConfigurer
+ Spring.Objects.Factory.Config.VariablePlaceholderConfigurer
in your configuration and set the property
VariableSource to a single
- IVariableSource instance or the list property
+ IVariableSource instance or the list property
VariableSources to a list of
- IVariableSource instances. In the case of the
+ IVariableSource instances. In the case of the
same property defined in multiple
- IVariableSource implementations, the first one
+ IVariableSource implementations, the first one
in the list that contains the property value will be used.
- <object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core">
+ <object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core">
<property name="VariableSources">
<list>
<object type="Spring.Objects.Factory.Config.ConfigSectionVariableSource, Spring.Core">
@@ -4671,7 +4686,7 @@ cfg.PostProcessObjectFactory(factory);
</object>
The IVariableSource interface is shown below
- public interface IVariableSource
+ public interface IVariableSource
{
string ResolveVariable(string name);
}
@@ -4684,11 +4699,11 @@ cfg.PostProcessObjectFactory(factory);
-
+ Customizing instantiation logic using
IFactoryObjects
- The Spring.Objects.Factory.IFactoryObject
+ The Spring.Objects.Factory.IFactoryObject
interface is to be implemented by objects that are themselves
factories.
@@ -4700,7 +4715,7 @@ cfg.PostProcessObjectFactory(factory);
inside that class, and then plug your custom
IFactoryObject into the container.
- The IFactoryObject interface provides one
+ The IFactoryObject interface provides one
method and two (read-only) properties: object GetObject(): has to return an
@@ -4723,38 +4738,38 @@ cfg.PostProcessObjectFactory(factory);
- IFactoryObject
+ IFactoryObjectThe IFactoryObject concept and interface is used in a number of
places within the Spring Framework. Some examples of its use is
described in for the
- PropertyRetrievingFactoryObject and
- FieldRetrievingFactoryObject. An additional use
+ PropertyRetrievingFactoryObject and
+ FieldRetrievingFactoryObject. An additional use
of creating an custom IFactoryObject implementation is to retrieve an
object from an embedded resource file and use it to set another objects
dependency. An example of this is provided here.Finally, there is sometimes a need to ask a container for an
- actual IFactoryObject instance itself, not the
+ actual IFactoryObject instance itself, not the
object it produces. This may be achieved by prepending the object id
with '&' (sans quotes) when calling the
GetObject method of the
- IObjectFactory (including
- IApplicationContext). So for a given
- IFactoryObject with an id of
+ IObjectFactory (including
+ IApplicationContext). So for a given
+ IFactoryObject with an id of
'myObject', invoking
GetObject("myObject") on the container will return
- the product of the IFactoryObject, but invoking
+ the product of the IFactoryObject, but invoking
GetObject("&myObject") will return the
- IFactoryObject instance itself.
+ IFactoryObject instance itself.IConfigurableFactoryObjectThe
- Spring.Objects.Factory.IConfigurableFactoryObject
- interface inherits from IFactoryObject
+ Spring.Objects.Factory.IConfigurableFactoryObject
+ interface inherits from IFactoryObject
interface and adds the following property.
@@ -4765,36 +4780,36 @@ cfg.PostProcessObjectFactory(factory);
- IConfigurableFactoryObject implementions
+ IConfigurableFactoryObject implementions
you already have examples of in are
- WebServiceProxyFactory.
+ WebServiceProxyFactory.
-
- The IApplicationContext
+
+ The IApplicationContextWhile the Spring.Objects namespace provides basic
functionality for managing and manipulating objects, often in a
programmatic way, the Spring.Context namespace
- introduces the IApplicationContext interface, which
+ introduces the IApplicationContext interface, which
enhances the functionality provided by the
- IObjectFactory interface in a more
+ IObjectFactory interface in a more
framework-oriented style. Many users will use
ApplicationContext in a completely declarative fashion, not even having to
create it manually, but instead relying on support classes such as the
.NET configuration section handlers such as ContextHandler and
WebContextHandler together to declaratively define the ApplicationContext
and retrieve it though a ContextRegistry. (Of course it is still possible
- to create an IApplicationContext
+ to create an IApplicationContext
Programatically).The basis for the context module is the
- IApplicationContext interface, located in the
+ IApplicationContext interface, located in the
Spring.Context namespace. Deriving from the
- IObjectFactory interface, it provides all the
- functionality of the IObjectFactory. To be able to
+ IObjectFactory interface, it provides all the
+ functionality of the IObjectFactory. To be able to
work in a more framework-oriented fashion, using layering and hierarchical
contexts, the Spring.Context namespace also provides
the following functionality
@@ -4808,13 +4823,13 @@ cfg.PostProcessObjectFactory(factory);Access to localized resources at the
application level by implementing
- IMessageSource.
+ IMessageSource.
Uniform access to resources that can be
read in as an InputStream, such as URLs and files by implementing
- IResourceLoader
+ IResourceLoader
@@ -4829,36 +4844,36 @@ cfg.PostProcessObjectFactory(factory);
IObjectFactory or IApplicationContext?Short version: use an
- IApplicationContext unless
+ IApplicationContext unless
you have a really good reason for not doing so. For those of you that
are looking for slightly more depth as to the 'but why' of the above
recommendation, keep reading.
- As the IApplicationContext includes all the
+ As the IApplicationContext includes all the
functionality the object factory via its inheritance of the
- IObjectFactory interface, it is generally
- recommended to be used over the IObjectFactory
+ IObjectFactory interface, it is generally
+ recommended to be used over the IObjectFactory
except for a few limited situations where memory consumption might be
critical. This may become more important if the .NET Compact Framework
- is supported. The history of IObjectFactory comes
+ is supported. The history of IObjectFactory comes
from the Spring Java framework, where the use of Spring in Applets was a
concern to reduce memory consumption. However, for most 'typical'
enterprise applications and systems, the
- IApplicationContext is what you will want to use.
+ IApplicationContext is what you will want to use.
Spring generally makes heavy use of the
- IObjectPostProcessor extension point (to effect
+ IObjectPostProcessor extension point (to effect
proxying and suchlike), and if you are using just a plain
- IObjectFactory then a fair amount of support such
+ IObjectFactory then a fair amount of support such
as transactions and AOP will not take effect (at least not without some
extra steps on your part), which could be confusing because nothing will
actually be wrong with the configuration.Find below a feature matrix that lists what features are provided
- by the IObjectFactory and
- IApplicationContext interfaces (and attendant
+ by the IObjectFactory and
+ IApplicationContext interfaces (and attendant
implementations). The following sections describe functionality that
- IApplicationContext adds to the basic
- IObjectFactory capabilities in a lot more depth
+ IApplicationContext adds to the basic
+ IObjectFactory capabilities in a lot more depth
than the said feature matrix.)
FeatureIObjectFactory
+ align="center">IObjectFactoryIApplicationContext
+ align="center">IApplicationContext
@@ -4891,7 +4906,7 @@ cfg.PostProcessObjectFactory(factory);
Automatic
- IObjectPostProcessor
+ IObjectPostProcessor
registrationNo
@@ -4901,7 +4916,7 @@ cfg.PostProcessObjectFactory(factory);
Automatic
- IObjectFactoryPostProcessor
+ IObjectFactoryPostProcessor
registrationNo
@@ -4911,7 +4926,7 @@ cfg.PostProcessObjectFactory(factory);
Convenient
- IMessageSource
+ IMessageSource
accessNo
@@ -4920,7 +4935,7 @@ cfg.PostProcessObjectFactory(factory);
- ApplicationEvent
+ ApplicationEvent
publicationNo
@@ -4951,7 +4966,7 @@ cfg.PostProcessObjectFactory(factory);
-
+ Configuration of IApplicationContextWell known locations in the .NET application configuration file are
@@ -4960,7 +4975,7 @@ cfg.PostProcessObjectFactory(factory);
previously. A sample .NET application configuration file showing all these
features is shown below. Each section requires the use of a custom
configuration section handler. Note that the types shown for resource
- handlers and parsers are fictional. <configuration>
+ handlers and parsers are fictional. <configuration>
<configSections>
<sectionGroup name="spring">
@@ -4969,7 +4984,7 @@ cfg.PostProcessObjectFactory(factory);
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
- <section name="resources" type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/>
+ <section name="resources" type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/>
<section name="typeAliases" type="Spring.Context.Support.TypeAliasesSectionHandler, Spring.Core"/>
<section name="typeConverters" type="Spring.Context.Support.TypeConvertersSectionHandler, Spring.Core"/>
@@ -5013,13 +5028,13 @@ cfg.PostProcessObjectFactory(factory);
</configuration>
The new sections are described below. The attribute
caseSensitive allows the for both
- IObjectFactory and
- IApplicationContext implementations to not pay
+ IObjectFactory and
+ IApplicationContext implementations to not pay
attention to the case of the object names. This is important in web
applications so that ASP.NET pages can be resolved in a case independent
manner. The default value is true.
-
+ Registering custom parsersInstead of using the default XML schema that is generic in nature
@@ -5029,7 +5044,7 @@ cfg.PostProcessObjectFactory(factory);
being used. The downside is that you need to write code that will
transform this XML into Spring object definitions. One would typically
implement a custom parser by deriving from the class
- ObjectsNamespaceParser and overriding the methods
+ ObjectsNamespaceParser and overriding the methods
int ParseRootElement(XmlElement root, XmlResourceReader
reader) and int ParseElement(XmlElement element,
XmlResourceReader reader). Registering custom parsers outside
@@ -5042,7 +5057,7 @@ cfg.PostProcessObjectFactory(factory);
attribute. Below is an example that registers all the namespaces
provided in Spring.
- <configuration>
+ <configuration>
<configSections>
<sectionGroup name="spring">
@@ -5067,7 +5082,7 @@ cfg.PostProcessObjectFactory(factory);
NamespaceParserRegistry. Here is an example taken from the code used in
the Transactions Quickstart application.
- NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));
+ NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
@@ -5075,24 +5090,24 @@ IApplicationContext context =
new XmlApplicationContext("assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/system-test-local-config.xml");
-
+ Registering custom resource handlersCreating a custom resource handler means implementing the
- IResource interface. The base class
- AbstractResource is a useful starting point. Look
+ IResource interface. The base class
+ AbstractResource is a useful starting point. Look
at the Spring source for classes such as
- FileSystemResource or
- AssemblyResource for implementation tips. You can
+ FileSystemResource or
+ AssemblyResource for implementation tips. You can
register your custom resource handler either within App.config, as shown
in the program listing at the start of this section using a
- .ResourceHandlersSectionHandler or define an
+ .ResourceHandlersSectionHandler or define an
object of the type
- Spring.Objects.Factory.Config.ResourceHandlerConfigurer
+ Spring.Objects.Factory.Config.ResourceHandlerConfigurer
as you would any other Spring managed object. An example of the latter
is shown below:
- <object id="myResourceHandlers" type="Spring.Objects.Factory.Config.ResourceHandlersSectionHandler, Spring.Core">
+ <object id="myResourceHandlers" type="Spring.Objects.Factory.Config.ResourceHandlersSectionHandler, Spring.Core">
<property name="ResourceHandlers">
<dictionary>
<entry key="db" value="MyCompany.MyApp.Resources.MyDbResource, MyAssembly"/>
@@ -5101,7 +5116,7 @@ IApplicationContext context =
</object>
-
+ Registering Type AliasesType aliases allow you to simplify Spring configuration file by
@@ -5117,8 +5132,7 @@ IApplicationContext context =
configuration listing for an example that makes an alias for the
WebServiceExporter type. Once you have aliases defined, you can simply
use them anywhere where you would normally specify a fully qualified
- type name:
-<object id="MyWebService" type="WebServiceExporter">
+ type name:<object id="MyWebService" type="WebServiceExporter">
...
</object>
@@ -5138,7 +5152,7 @@ IApplicationContext context =
a type attribute. Below is an example that registers the alias for
WebServiceExporter
- <configuration>
+ <configuration>
<configSections>
<sectionGroup name="spring">
@@ -5159,14 +5173,14 @@ IApplicationContext context =
linkend="objects-creation-generic-types" />.
Another way is to define an object of the type
- Spring.Objects.Factory.Config.TypeAliasConfigurer
+ Spring.Objects.Factory.Config.TypeAliasConfigurer
within the regular <objects> section of any standard Spring
configuration file. This approach allows for more modularity in defining
type aliases, for example if you can't access App.config/Web.config. An
example of registration using a
- TypeAliasConfigurer is shown below
+ TypeAliasConfigurer is shown below
- <object id="myTypeAlias" type="Spring.Objects.Factory.Config.TypeAliasConfigurer, Spring.Core">
+ <object id="myTypeAlias" type="Spring.Objects.Factory.Config.TypeAliasConfigurer, Spring.Core">
<property name="TypeAliases">
<dictionary>
<entry key="WebServiceExporter" value="Spring.Web.Services.WebServiceExporter, Spring.Web"/>
@@ -5177,11 +5191,11 @@ IApplicationContext context =
</object>
-
+ Registering Type ConvertersThe standard .NET mechanism for specifying a type converter is to
- add a TypeConverter attribute to a type
+ add a TypeConverter attribute to a type
definition to specify the type of the Converter. This is the preferred
way of defining type converters if you control the source code for the
type that you want to define a converter for. However, this
@@ -5193,11 +5207,11 @@ IApplicationContext context =
You can specify the type converters in App.config by using
Spring.Context.Support.TypeConvertersSectionHandler as shown before or
define an object of the type
- Spring.Objects.Factory.Config.CustomConverterConfigurer.
+ Spring.Objects.Factory.Config.CustomConverterConfigurer.
An example of registration using a
- CustomConverterConfigurer is shown below
+ CustomConverterConfigurer is shown below
- <object id="myTypeConverters" type="Spring.Objects.Factory.Config.CustomConverterConfigurer, Spring.Core">
+ <object id="myTypeConverters" type="Spring.Objects.Factory.Config.CustomConverterConfigurer, Spring.Core">
<property name="CustomConverters">
<dictionary>
<entry key="System.Date" value="MyCompany.MyProject.MyNamespace.MyCustomDateConverter, MyAssembly"/>
@@ -5207,16 +5221,16 @@ IApplicationContext context =
-
+ Added functionality of the
- IApplicationContext
+ IApplicationContextAs already stated in the previous section, the
- IApplicationContext has a couple of features that
- distinguish it from the IObjectFactory. Let us
+ IApplicationContext has a couple of features that
+ distinguish it from the IObjectFactory. Let us
review them one-by-one.
-
+ Context HierarchiesYou can structure the configuration information of application
@@ -5224,7 +5238,7 @@ IApplicationContext context =
your application. As an example, abstract object definitions may appear
in a parent application context configuration file, possibly as an
embedded assembly resource so as not to invite accidental changes.
- <spring>
+ <spring>
<context>
<resource uri="assembly://MyAssembly/MyProject/root-objects.xml"/>
<context name="mySubContext">
@@ -5237,7 +5251,7 @@ IApplicationContext context =
application hierarchy. The xml file must contain the
<objects> as the root name. Another example of
a hierarchy, but using sections in the application configuration file is
- shown below. <configSections>
+ shown below. <configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
@@ -5274,17 +5288,17 @@ IApplicationContext context =
As a reminder, the type attribute of the
context tag is optional and defaults to
- Spring.Context.Support.XmlApplicationContext. The
+ Spring.Context.Support.XmlApplicationContext. The
name of the context can be used in conjunction with the service locator
- class, ContextRegistry, discussed in ContextRegistry, discussed in
-
+ Using IMessageSource
- The IApplicationContext interface extends
- an interface called IMessageSource and provides
+ The IApplicationContext interface extends
+ an interface called IMessageSource and provides
localization (i18n or internationalization) services for text messages
and other resource data types such as images. This functionality makes
it easier to use .NET's localization features at an application level
@@ -5296,21 +5310,21 @@ IApplicationContext context =
string GetMessage(string name): retrieves
- a message from the IMessageSource and using
+ a message from the IMessageSource and using
CurrentUICulture.string GetMessage(string name, CultureInfo
cultureInfo): retrieves a message from the
- IMessageSource using a specified
+ IMessageSource using a specified
culture.string GetMessage(string name, params object[]
args): retrieves a message from the
- IMessageSource using a variable list of
+ IMessageSource using a variable list of
arguments as replacement values in the message. The
CurrentUICulture is used to resolve the message.
@@ -5318,7 +5332,7 @@ IApplicationContext context =
string GetMessage(string name, CultureInfo
cultureInfo, params object[] args): retrieves a message
- from the IMessageSource using a variable
+ from the IMessageSource using a variable
list of arguments as replacement values in the message. The
specified culture is used to resolve the message.
@@ -5327,7 +5341,7 @@ IApplicationContext context =
string GetMessage(string name, string
defaultMessage, CultureInfo culture, params object[]
arguments): retrieves a message from the
- IMessageSource using a variable list of
+ IMessageSource using a variable list of
arguments as replacement values in the message. The specified
culture is used to resolve the message. If no message can be
resolved, the default message is used.
@@ -5335,7 +5349,7 @@ IApplicationContext context =
string GetMessage(IMessageSourceResolvable
- resolvable, CultureInfo culture)
+ resolvable, CultureInfo culture)
: all properties used in the methods above are also
wrapped in a class - the
MessageSourceResolvable, which you can use in
@@ -5365,15 +5379,15 @@ IApplicationContext context =
- When an IApplicationContext gets loaded, it
- automatically searches for an IMessageSource
+ When an IApplicationContext gets loaded, it
+ automatically searches for an IMessageSource
object defined in the context. The object has to have the name
messageSource. If such an object is found, all calls
to the methods described above will be delegated to the message source
that was found. If no message source was found, the
- IApplicationContext checks to see if it has a
+ IApplicationContext checks to see if it has a
parent containing a similar object, with a similar name. If so, it uses
- that object as the IMessageSource. If it can't
+ that object as the IMessageSource. If it can't
find any source for messages, an empty
StaticMessageSource will be instantiated in order to
be able to accept calls to the methods defined above.
@@ -5386,24 +5400,24 @@ IApplicationContext context =
The fallback rules for localized resources seem to have a bug that is fixed by applying Service Pack 1 for .NET 1.1. This affects the use of IMessageSource.GetMessage methods that specify CultureInfo. The core of the issue in the .NET BCL is the method ResourceManager.GetObject that accepts CultureInfo. .
- Spring.NET provides two IMessageSource
+ Spring.NET provides two IMessageSource
implementations. These are
- ResourceSetMessageSource and
- StaticMessageSource. Both implement
- IHierarchicalMessageSource to resolve messages
- hierarchically. The StaticMessageSource is hardly
+ ResourceSetMessageSource and
+ StaticMessageSource. Both implement
+ IHierarchicalMessageSource to resolve messages
+ hierarchically. The StaticMessageSource is hardly
ever used but provides programmatic ways to add messages to the source.
- The ResourceSetMessageSource is more interesting
+ The ResourceSetMessageSource is more interesting
and an example is provided for in the distribution and discussed more
extensively in the section. The
- ResourceSetMessageSource is configured by
- providing a list of ResourceManagers. When a
+ ResourceSetMessageSource is configured by
+ providing a list of ResourceManagers. When a
message code is to be resolved, the list of ResourceManagers is searched
- to resolve the code. For each ResourceManager a
- ResourceSet is retrieved and asked to resolve the
+ to resolve the code. For each ResourceManager a
+ ResourceSet is retrieved and asked to resolve the
code. Note that this search does not replace the standard hub-and-spoke
search for localized resources. The ResourceManagers list specifies the
- multiple 'hubs' where the standard search starts. <object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core">
+ multiple 'hubs' where the standard search starts. <object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core">
<property name="resourceManagers">
<list>
<value>Spring.Examples.AppContext.MyResource, Spring.Examples.AppContext</value>
@@ -5414,14 +5428,14 @@ IApplicationContext context =
You can specify the arguments to construct a ResourceManager as a
two part string value containing the base name of the resource and the
assembly name. This will be converted to a ResourceManager via the
- ResourceManagerConverter TypeConverter. This
+ ResourceManagerConverter TypeConverter. This
converter can be similarly used to set a property on any object that is
- of the type ResourceManager. You may also specify
- an instance of the ResourceManager to use via an
+ of the type ResourceManager. You may also specify
+ an instance of the ResourceManager to use via an
object reference. The convenience class
- Spring.Objects.Factory.Config.ResourceManagerFactoryObject
+ Spring.Objects.Factory.Config.ResourceManagerFactoryObject
can be used to conveniently create an instance of a ResourceManager.
- <object name="myResourceManager" type="Spring.Objects.Factory.Config.ResourceManagerFactoryObject, Spring.Core">
+ <object name="myResourceManager" type="Spring.Objects.Factory.Config.ResourceManagerFactoryObject, Spring.Core">
<property name="baseName">
<value>Spring.Examples.AppContext.MyResource</value>
</property>
@@ -5433,7 +5447,7 @@ IApplicationContext context =
In application code, a call to GetMessage will
retrieve a properly localized message string based on a code value. Any
arguments present in the retrieved string are replaced using
- String.Format semantics. The ResourceManagers,
+ String.Format semantics. The ResourceManagers,
ResourceSets and retrieved strings are cached to provide quicker lookup
performance. The key 'HelloMessage' is contained in the resource file
with a value of Hello {0} {1}. The following call on
@@ -5441,7 +5455,7 @@ IApplicationContext context =
Anderson. Note that the caching of
ResourceSets is via the concatenation of the ResourceManager base name
and the CultureInfo string. This combination must be unique.
- string msg = ctx.GetMessage("HelloMessage",
+ string msg = ctx.GetMessage("HelloMessage",
new object[] {"Mr.", "Anderson"},
CultureInfo.CurrentCulture );
@@ -5451,13 +5465,13 @@ IApplicationContext context =
flexibility in how you can structure your message resolution. This is
achieved by passing as an argument a class that implements
IMessageResolvable instead of a string literal. The
- convenience class DefaultMessageResolvable is
+ convenience class DefaultMessageResolvable is
available for this purpose. As an example if the resource file contains
a key name error.required that has the value
'{0} is required {1}' and another key name
field.firstname with the value 'First
name'. The following code will create the string
- 'First name is required dude!' string[] codes = {"field.firstname"};
+ 'First name is required dude!' string[] codes = {"field.firstname"};
DefaultMessageResolvable dmr = new DefaultMessageResolvable(codes, null);
ctx.GetMessage("error.required",
new object[] { dmr, "dude!" },
@@ -5468,31 +5482,31 @@ ctx.GetMessage("error.required",
program, Spring.Examples.AppContext, that
demonstrates usage of these features.
- The IMessageSourceAware interface can also
+ The IMessageSourceAware interface can also
be used to acquire a reference to any
- IMessageSource that has been defined. Any object
- that is defined in an IApplicationContext that
- implements the IMessageSourceAware interface will
+ IMessageSource that has been defined. Any object
+ that is defined in an IApplicationContext that
+ implements the IMessageSourceAware interface will
be injected with the application context's
- IMessageSource when it (the object) is being
+ IMessageSource when it (the object) is being
created and configured.
-
+ Using resources within Spring.NETA lot of applications need to access resources. Resources here,
might mean files, but also news feeds from the Internet or normal web
pages. Spring.NET provides a clean and transparent way of accessing
resources in a protocol independent way. The
- IApplicationContext has a method
+ IApplicationContext has a method
(GetResource(string)) to take care of this. Refer to
for more information on the string
- format to use and the IResource abstraction in
+ format to use and the IResource abstraction in
general.
-
+ Loosely coupled eventsThe Eventing Registry allows developers to utilize a loosely
@@ -5506,7 +5520,7 @@ ctx.GetMessage("error.required",
one subscriber to handle all events of a certain type without regards to
how many different instances of that type are created.
- The Spring.Objects.Events.IEventRegistry
+ The Spring.Objects.Events.IEventRegistry
interface represents the central registry and defines publish and
subscribe methods.
@@ -5527,12 +5541,12 @@ ctx.GetMessage("error.required",
from a source object of a particular type for which it has
matching handler methods.
- IApplicationContext implements
+ IApplicationContext implements
this interface and delegates the implementation to an instance of
- Spring.Objects.Events.Support.EventRegistry. You
+ Spring.Objects.Events.Support.EventRegistry. You
are free to create and use as many EventRegistries as you like but since
it is common to use only one in an application,
- IApplicationContext provides convenient access to
+ IApplicationContext provides convenient access to
a single instance.Within the
@@ -5541,10 +5555,10 @@ ctx.GetMessage("error.required",
When you open up the project, the most interesting file is the
EventRegistryApp.cs file. This application loads a set of object
definitions from the application configuration file into an
- IApplicationContext instance. From there, three
+ IApplicationContext instance. From there, three
objects are loaded up: one publisher and two subscribers. The publisher
- publishes its events to the IApplicationContext
- instance: // Create the Application context using configuration file
+ publishes its events to the IApplicationContext
+ instance: // Create the Application context using configuration file
IApplicationContext ctx = ContextRegistry.GetContext();
// Gets the publisher from the application context
@@ -5553,8 +5567,8 @@ MyEventPublisher publisher = (MyEventPublisher)ctx.GetObject("MyEventPublisher")
// Publishes events to the context.
ctx.PublishEvents( publisher );
One of the two subscribers subscribes to all events
- published to the IApplicationContext instance,
- using the publisher type as the filter criteria.// Gets first instance of subscriber
+ published to the IApplicationContext instance,
+ using the publisher type as the filter criteria.// Gets first instance of subscriber
MyEventSubscriber subscriber = (MyEventSubscriber)ctx.GetObject("MyEventSubscriber");
// Gets second instance of subscriber
@@ -5570,47 +5584,47 @@ ctx.Subscribe( subscriber, typeof(MyEventPublisher) ); This
prototype definition.
-
+ Event notification from
- IApplicationContext
+ IApplicationContext
- Event handling in the IApplicationContext
- is provided through the IApplicationListener
+ Event handling in the IApplicationContext
+ is provided through the IApplicationListener
interface that contains the single method void
OnApplicationEvent( object source, ApplicationEventArgs
applicationEventArgs ). Classes that implement the
- IApplicationListener interface are automatically
+ IApplicationListener interface are automatically
registered as a listener with the
- IApplicationContext. Publishing an event is done
+ IApplicationContext. Publishing an event is done
via the context's PublishEvent( ApplicationEventArgs eventArgs
) method. This implementation is based on the traditional
Observer design pattern.The event argument type,
- ApplicationEventArgs, adds the time of the event
+ ApplicationEventArgs, adds the time of the event
firing as a property. The derived class
- ContextEventArgs is used to notify observers on
+ ContextEventArgs is used to notify observers on
the lifecycle events of the application context. It contains a property
ContextEvent Event that returns the enumeration
Refreshed or Closed.. The
Refreshed enumeration value indicated that the
- IApplicationContext was either initialized or
+ IApplicationContext was either initialized or
refreshed. Initialized here means that all objects are loaded,
singletons are pre-instantiated and the
- IApplicationContext is ready for use. The
+ IApplicationContext is ready for use. The
Closed is published when the
- IApplicationContext is closed using the
+ IApplicationContext is closed using the
Dispose() method on the
- IConfigurableApplicationContext interface. Closed
+ IConfigurableApplicationContext interface. Closed
here means that singletons are destroyed.Implementing custom events can be done as well. Simply call the
PublishEvent method on the
- IApplicationContext, specifying a parameter which
+ IApplicationContext, specifying a parameter which
is an instance of your custom event argument subclass.Let's have a look at an example. First, the
- IApplicationContext: <object id="emailer" type="Example.EmailObject">
+ IApplicationContext: <object id="emailer" type="Example.EmailObject">
<property name="blackList">
<list>
<value>black@list.org</value>
@@ -5625,7 +5639,7 @@ ctx.Subscribe( subscriber, typeof(MyEventPublisher) ); This
<value>spam@list.org</value>
</property>
</object> and then, the actual objects:
- public class EmailObject : IApplicationContextAware {
+ public class EmailObject : IApplicationContextAware {
// the blacklist
private IList blackList;
@@ -5673,26 +5687,26 @@ public class BlackListNotifier : IApplicationListener
-
+ Customized behavior in the ApplicationContext
- The IObjectFactory already offers a number of
+ The IObjectFactory already offers a number of
mechanisms to control the lifecycle of objects deployed in it (such as
- marker interfaces like IInitializingObject and
- System.IDisposable, their configuration only
+ marker interfaces like IInitializingObject and
+ System.IDisposable, their configuration only
equivalents such as init-method and
destroy-method) attributes in an XmlObjectFactory
configuration, and object post-processors. In an
- IApplicationContext, all of these still work, but
+ IApplicationContext, all of these still work, but
additional mechanisms are added for customizing behavior of objects and
the container.
-
+ The IApplicationContextAware marker
interfaceAll marker interfaces available with ObjectFactories still work.
- The IApplicationContext does add one extra marker
+ The IApplicationContext does add one extra marker
interface which objects may implement,
IApplicationContextAware. An object which implements
this interface and is deployed into the context will be called back on
@@ -5702,47 +5716,47 @@ public class BlackListNotifier : IApplicationListener
the context.
-
+ The IObjectPostProcessorObject post-processors are classes which implement the
- Spring.Objects.Factory.Config.IObjectPostProcessor
+ Spring.Objects.Factory.Config.IObjectPostProcessor
interface, have already been mentioned. It
is worth mentioning again here though, that post-processors are much
- more convenient to use in IApplicationContexts
- than in plain IObjectFactory instances. In an
- IApplicationContext, any deployed object which
+ more convenient to use in IApplicationContexts
+ than in plain IObjectFactory instances. In an
+ IApplicationContext, any deployed object which
implements the above marker interface is automatically detected and
registered as an object post-processor, to be called appropriately at
creation time for each object in the factory.
-
+ The IObjectFactoryPostProcessorObject factory post-processors are classes which implement the
- Spring.Objects.Factory.Config.IObjectFactoryPostProcessor
+ Spring.Objects.Factory.Config.IObjectFactoryPostProcessor
interface, have already
been mentioned. It is worth mentioning again here though, that object
factory post-processors are much more convenient to use in
- IApplicationContexts. In an
- IApplicationContext, any deployed object which
+ IApplicationContexts. In an
+ IApplicationContext, any deployed object which
implements the above marker interface is automatically detected as an
object factory post-processor, to be called at the appropriate
time.
-
+ The PropertyPlaceholderConfigurerThe PropertyPlaceholderConfigurer has already been
described in the context of its use within an
- IObjectFactory. It is worth mentioning here
+ IObjectFactory. It is worth mentioning here
though, that it is generally more convenient to use it with an
- IApplicationContext, since the context will
+ IApplicationContext, since the context will
automatically recognize and apply any object factory post-processors,
such as this one, when they are simply deployed into it like any other
object. There is no need for a manual step to execute it.
@@ -5763,7 +5777,7 @@ public class BlackListNotifier : IApplicationListener
configure the GenericApplicationContext to read from XML, just so show
familiar API usage
- GenericApplicationContext ctx = new GenericApplicationContext();
+ GenericApplicationContext ctx = new GenericApplicationContext();
XmlObjectDefinitionReader reader = new XmlObjectDefinitionReader(ctx);
reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextB.xml");
reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextC.xml");
@@ -5780,7 +5794,7 @@ ctx.Refresh();
MyAssembly.dll located in the runtime path, would look something like
this
- GenericApplicationContext ctx = new GenericApplicationContext();
+ GenericApplicationContext ctx = new GenericApplicationContext();
ObjectDefinitionScanner scanner = new ObjectDefinitionScanner(ctx);
scanner.scan("MyAssembly.dll");
ctx.refresh();
@@ -5788,18 +5802,18 @@ ctx.refresh();Refer to the Spring API documentation for more information.
-
+ Service Locator accessThe majority of the code inside an application is best written in a
Dependency Injection (Inversion of Control) style, where that code is
- served out of an IObjectFactory or
- IApplicationContext container, has its own
+ served out of an IObjectFactory or
+ IApplicationContext container, has its own
dependencies supplied by the container when it is created, and is
completely unaware of the container. However, there is sometimes a need
for singleton (or quasi-singleton) style access to an
- IObjectFactory or
- IApplicationContext. For example, third party code
+ IObjectFactory or
+ IApplicationContext. For example, third party code
may try to construct a new object directly without the ability to force it
to get these objects out of the IObjectFactory. Similarly, nested user
control components in a WinForms application are created inside the
@@ -5809,22 +5823,22 @@ ctx.refresh();
obtain the object it requires. (Note support for DI in WinForms is under
development.)
- The Spring.Context.Support.ContextRegistry
+ The Spring.Context.Support.ContextRegistry
class allows you to obtain a reference to an
- IApplicationContext via a static locator method.
- The ContextRegistry is initialized when creating an
- IApplicationContext through use of the
- ContextHandler discussed previously. The simple
+ IApplicationContext via a static locator method.
+ The ContextRegistry is initialized when creating an
+ IApplicationContext through use of the
+ ContextHandler discussed previously. The simple
static method GetContext() can then be used to retrieve
the context. Alternatively, if you create an
- IApplicationContext though other means you can
- register it with the ContextRegistry via the method
+ IApplicationContext though other means you can
+ register it with the ContextRegistry via the method
void RegisterContext(IApplicationContext context) in
the start-up code of your application. Hierarchical context retrieval is
also supported though the use of the GetContext(string
- name) method, for example:IApplicationContex ctx = ContextRegistry.GetContext("mySubContext");
+ name) method, for example:IApplicationContex ctx = ContextRegistry.GetContext("mySubContext");
This would retrieve the nested context for the context configuration shown
- previously.<spring>
+ previously.<spring>
<context>
<resource uri="assembly://MyAssembly/MyProject/root-objects.xml"/>
<context name="mySubContext">
diff --git a/doc/reference/src/orm.xml b/doc/reference/src/orm.xml
index 05840e75..c0d8c111 100644
--- a/doc/reference/src/orm.xml
+++ b/doc/reference/src/orm.xml
@@ -1,8 +1,25 @@
-
+
+Object Relational Mapping (ORM) data access
-
+ IntroductionThe Spring Framework provides integration with NHibernate
@@ -31,8 +48,8 @@
Ease of testing. Spring's IoC approach
makes it easy to swap the implementations and config locations of
- Hibernate SessionFactory instances,
- ADO.NET DbProvider instances,
+ Hibernate SessionFactory instances,
+ ADO.NET DbProvider instances,
transaction managers, and mapper object implementations (if needed).
This makes it much easier to isolate and test each piece of
persistence-related code in isolation.
@@ -52,18 +69,18 @@
General resource management. Spring
application contexts can handle the location and configuration of
- Hibernate ISessionFactory instances,
- ADO.NET DbProvider instances and other
+ Hibernate ISessionFactory instances,
+ ADO.NET DbProvider instances and other
related resources. This makes these values easy to manage and change.
Spring offers efficient, easy and safe handling of persistence
resources. For example: related code using NHibernate generally needs
- to use the same NHibernate Session for
+ to use the same NHibernate Session for
efficiency and proper transaction handling. Spring makes it easy to
- transparently create and bind a Session
+ transparently create and bind a Session
to the current thread, either by using an explicit 'template' wrapper
class at the code level or by exposing a current
- Session through the Hibernate
- SessionFactory (for DAOs based on plain
+ Session through the Hibernate
+ SessionFactory (for DAOs based on plain
Hibernate 1.2 API). Thus Spring solves many of the issues that
repeatedly arise from typical NHibernate usage, for any transaction
environment (local or distributed).
@@ -110,7 +127,7 @@
value proposition.
-
+ NHibernateWe will start with a coverage of
-
+ Resource managementTypical business applications are often cluttered with repetitive
@@ -140,18 +157,18 @@
for appropriate conversion of specific API exceptions to a common
infrastructure exception hierarchy. Spring introduces a DAO exception
hierarchy, applicable to any data access strategy. For direct ADO.NET,
- the AdoTemplate class mentioned in a previous
+ the AdoTemplate class mentioned in a previous
section cares for connection handling, and for proper conversion of
ADO.NET data access exceptions (not even singly rooted in .NET 1.1) to
- Spring's DataAccessException hierarchy, including
+ Spring's DataAccessException hierarchy, including
translation of database-specific SQL error codes to meaningful exception
classes. It supports both distributed and local transactions, via
respective Spring transaction managers.Spring also offers Hibernate support, consisting of a
- HibernateTemplate analogous to
- AdoTemplate, a
- HibernateInterceptor, and a Hibernate transaction
+ HibernateTemplate analogous to
+ AdoTemplate, a
+ HibernateInterceptor, and a Hibernate transaction
manager. The major goal is to allow for clear application layering, with
any data access and transaction technology, and for loose coupling of
application objects. No more business service dependencies on the data
@@ -169,7 +186,7 @@
the business services),and so on.
-
+ Transaction ManagementWhile NHibernate offers an API for transaction management you will
@@ -183,8 +200,8 @@
the other the .NET 2.0 TransactionScope API.The first strategy is encapsulated in the class
- Spring.Data.NHibernate.HibernateTransactionManager
- in both the Spring.Data.NHibernate
+ Spring.Data.NHibernate.HibernateTransactionManager
+ in both the Spring.Data.NHibernate
namespace. This strategy is preferred when you are using a
single database. ADO.NET operations can also participate in the same
transaction, either by using AdoTemplate or by retrieving the ADO.NET
@@ -198,10 +215,10 @@
configuration file to gain the benefits of easy configuration for a
particular runtime environment and as the basis for the configuration of
a data access layer also configured using XML. An XML fragment showing
- the declaration of HibernateTransactionManager is
+ the declaration of HibernateTransactionManager is
shown below.
- <object id="HibernateTransactionManager"
+ <object id="HibernateTransactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">
<property name="DbProvider" ref="DbProvider"/>
@@ -210,14 +227,14 @@
</object>The important property of
- HibernateTransactionManager are the references to
+ HibernateTransactionManager are the references to
the DbProvider and the Hibernate ISessionFactory. For more information
on the DbProvider, refer to the chapter DbProvider and the following section on
SessionFactory set up.The second strategy is to use the class
- Sping.Data.TxScopeTransactionManager that uses
+ Sping.Data.TxScopeTransactionManager that uses
.NET 2.0 System.Transaction namespace and its corresponding
TransactionScope API. This is preferred when you are using multiple
transactional resources, such as multiple databases.
@@ -226,7 +243,7 @@
the transaction (scope in the general demarcation sense, not
System.Transaction sense). If there is no transaction then a new Session
will be opened for each operation. The exception to this rule is when
- using the OpenSessionInViewModule in a web
+ using the OpenSessionInViewModule in a web
application in single session mode (see ). In this case the session will be
created on the start of the web request and closed on the end of the
@@ -240,22 +257,22 @@
of the web request.
-
- SessionFactory set up in a Spring
+
+ SessionFactory set up in a Spring
containerTo avoid tying application objects to hard-coded resource lookups,
Spring allows you to define resources like a
- DbProvider or a Hibernate
- SessionFactory as objects in an
+ DbProvider or a Hibernate
+ SessionFactory as objects in an
application context. Application objects that need to access resources
just receive references to such pre-defined instances via object
references (the DAO definition in the next section illustrates this).
The following excerpt from an XML application context definition shows
how to set up Spring's ADO.NET DbProvider and a Hibernate
- SessionFactory on top of it:
+ SessionFactory on top of it:
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:db="http://www.springframework.net/database">
@@ -318,7 +335,7 @@
array so multiple configuration files are supported.There are other properties in
- LocalSessionFactoryObject that relate to the
+ LocalSessionFactoryObject that relate to the
integration of Spring with NHibernate. The property
ExposeTransactionAwareSessionFactory is discussed
below and allows you to use Spring's declarative transaction demarcation
@@ -335,7 +352,7 @@
- Delegate to the DbProvider itself as
+ Delegate to the DbProvider itself as
the NHibernate connection provider instead of listing it via
property hibernate.connection.provider via
HibernateProperties.
@@ -345,9 +362,9 @@
If you specify both the property hibernate.connection.provider and
DbProvider (as shown above) the configuration of the property
hibernate.connection.provider is used and a warning level message is
- logged. If you use Spring's DbProvider as the
+ logged. If you use Spring's DbProvider as the
NHibernate connection provider then you can take advantage of
- IDbProvider implementations that will let you
+ IDbProvider implementations that will let you
change the connection string at runtime such as UserCredentialsDbProvider
and MultiDelegatingDbProvider
only change the connection string at runtime based on values in thread
local storage and do not clear out the Hibernate cache that is unique
- to each ISessionFactory instance. As such, they
+ to each ISessionFactory instance. As such, they
are only useful for selecting at runtime a single database instance.
Cleaning up an existing session factory when switching to a new
database is left to user code. Creating a new session factory per
connection string (assuming the same mapping files can be used across
all databases connections) is not currently supported. To support this
functionality, you can subclass
- LocalSessionFactoryObject and override the
+ LocalSessionFactoryObject and override the
method ISessionFactory NewSessionFactory(Configuration
config) so that it returns an implementation of
- ISessionFactory that selects among multiple
+ ISessionFactory that selects among multiple
instances based on values in thread local storage, much like the
implementation of
- MultiDelegatingDbProvider.
+ MultiDelegatingDbProvider.
-
- The HibernateTemplate
+
+ The HibernateTemplateThe basic programming model for templating looks as follows for
methods that can be part of any custom data access object or business
service. There are no restrictions on the implementation of the
surrounding object at all, it just needs to provide a Hibernate
- SessionFactory. It can get the latter
+ SessionFactory. It can get the latter
from anywhere, but preferably as an object reference from a Spring IoC
container - via a simple SessionFactory
property setter. The following snippets show a DAO definition in a
Spring container, referencing the above defined
- SessionFactory, and an example for a DAO
+ SessionFactory, and an example for a DAO
method implementation.
- <objects>
+ <objects>
<object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
<property name="SessionFactory" ref="MySessionFactory"/>
@@ -402,7 +419,7 @@
- public class HibernateCustomerDao : ICustomerDao {
+ public class HibernateCustomerDao : ICustomerDao {
private HibernateTemplate hibernateTemplate;
@@ -418,15 +435,15 @@
}
}
- The HibernateTemplate class provides many
+ The HibernateTemplate class provides many
methods that mirror the methods exposed on the Hibernate
- Session interface, in addition to a
+ Session interface, in addition to a
number of convenience methods such as the one shown above. If you need
- access to the Session to invoke methods
- that are not exposed on the HibernateTemplate,
+ access to the Session to invoke methods
+ that are not exposed on the HibernateTemplate,
you can always drop down to a callback-based approach like so.
- public class HibernateCustomerDao : ICustomerDao {
+ public class HibernateCustomerDao : ICustomerDao {
private HibernateTemplate hibernateTemplate;
@@ -454,7 +471,7 @@
generics, you can avoid the typecast and write code like the
following
- IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>(
+ IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>(
delegate(ISession session)
{
return session.CreateQuery("from Supplier s were s.Code = ?")
@@ -466,22 +483,22 @@
inside the anonymous delegate implementation.A callback implementation effectively can be used for any
- Hibernate data access. HibernateTemplate will
- ensure that Session instances are
+ Hibernate data access. HibernateTemplate will
+ ensure that Session instances are
properly opened and closed, and automatically participate in
transactions. The template instances are thread-safe and reusable, they
can thus be kept as instance variables of the surrounding class. For
simple single step actions like a single Find, Load, SaveOrUpdate, or
- Delete call, HibernateTemplate offers alternative
+ Delete call, HibernateTemplate offers alternative
convenience methods that can replace such one line callback
implementations. Furthermore, Spring provides a convenient
- HibernateDaoSupport base class that provides a
+ HibernateDaoSupport base class that provides a
SessionFactory property for receiving a
- SessionFactory and for use by subclasses.
+ SessionFactory and for use by subclasses.
In combination, this allows for very simple DAO implementations for
typical requirements:
- public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
+ public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
{
public Customer SaveOrUpdate(Customer customer)
{
@@ -491,28 +508,28 @@
}
-
+ Implementing Spring-based DAOs without callbacksAs an alternative to using Spring's
- HibernateTemplate to implement DAOs, data access
+ HibernateTemplate to implement DAOs, data access
code can also be written in a more traditional fashion, without wrapping
the Hibernate access code in a callback, while still respecting and
participating in Spring's generic
- DataAccessException hierarchy. The
- HibernateDaoSupport base class offers methods to
- access the current transactional Session
+ DataAccessException hierarchy. The
+ HibernateDaoSupport base class offers methods to
+ access the current transactional Session
and to convert exceptions in such a scenario; similar methods are also
available as static helpers on the
- SessionFactoryUtils class. Note that such code
+ SessionFactoryUtils class. Note that such code
will usually pass 'false' as the value of the
DoGetSession(..) method's
'allowCreate' argument, to enforce running within a
transaction (which avoids the need to close the returned
- Session, as its lifecycle is managed by
+ Session, as its lifecycle is managed by
the transaction). Asking for the
- public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
+ public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
public Customer SaveOrUpdate(Customer customer)
{
@@ -527,18 +544,18 @@
DataAccessException.
-
+ Implementing DAOs based on plain Hibernate 1.2 APIHibernate 1.2 introduced a feature called "contextual Sessions",
where Hibernate itself manages one current
- ISession per transaction. This is roughly
+ ISession per transaction. This is roughly
equivalent to Spring's synchronization of one Hibernate
- Session per transaction. A corresponding
+ Session per transaction. A corresponding
DAO implementation looks like as follows, based on the plain Hibernate
API:
- public class ProductDaoImpl implements IProductDao {
+ public class ProductDaoImpl implements IProductDao {
private SessionFactory sessionFactory;
@@ -575,13 +592,13 @@ public class HibernateCustomerDao : ICustomerDao {
The above DAO follows the Dependency Injection pattern: it fits
nicely into a Spring IoC container, just like it would if coded against
- Spring's HibernateTemplate. Of course, such a DAO
+ Spring's HibernateTemplate. Of course, such a DAO
can also be set up in plain C# (for example, in unit tests): simply
instantiate it and call SessionFactory property
with the desired factory reference. As a Spring object definition, it
would look as follows:
-
+
<objects>
<object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
@@ -602,9 +619,9 @@ public class HibernateCustomerDao : ICustomerDao {
The first way is shown below
- <object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
+ <object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
- <property name="ExposeTransactionAwareSessionFactory" value="true" />
+ <property name="ExposeTransactionAwareSessionFactory" value="true" />
<!-- other configuration settings omitted -->
@@ -612,7 +629,7 @@ public class HibernateCustomerDao : ICustomerDao {
Which is simply a shortcut for the following configuration
- <object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
+ <object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
<!-- other configuration settings omitted -->
@@ -621,8 +638,8 @@ public class HibernateCustomerDao : ICustomerDao {
<!-- other dictionary entries omitted -->
- <entry key="hibernate.current_session_context_class"
- value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/>
+ <entry key="hibernate.current_session_context_class"
+ value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/>
</dictionary>
</property>
@@ -635,7 +652,7 @@ public class HibernateCustomerDao : ICustomerDao {
doubt feel more natural to Hibernate developers.
However, the DAO throws plain
- HibernateException which means that callers can
+ HibernateException which means that callers can
only treat exceptions as generally fatal - unless they want to depend on
Hibernate's own exception hierarchy. Catching specific causes such as an
optimistic locking failure is not possible without tying the caller to
@@ -644,11 +661,11 @@ public class HibernateCustomerDao : ICustomerDao {
special exception treatment.Fortunately, Spring's
- LocalSessionFactoryObject supports Hibernate's
+ LocalSessionFactoryObject supports Hibernate's
SessionFactory.GetCurrentSession() method for
any Spring transaction strategy, returning the current Spring-managed
- transactional Session even with
- HibernateTransactionManager.
+ transactional Session even with
+ HibernateTransactionManager.
In summary: DAOs can be implemented based on the plain Hibernate
1.2 API, while still being able to participate in Spring-managed
@@ -656,29 +673,29 @@ public class HibernateCustomerDao : ICustomerDao {
transaction.
-
+ Programmatic transaction demarcationTransactions can be demarcated in a higher level of the
application, on top of such lower-level data access services spanning
any number of operations. There are no restrictions on the
implementation of the surrounding business service here as well, it just
- needs a Spring PlatformTransactionManager. Again,
+ needs a Spring PlatformTransactionManager. Again,
the latter can come from anywhere, but preferably as an object reference
via a TransactionManager property - just like
- the productDAO should be set via a
+ the productDAO should be set via a
setProductDao(..) method. The following
snippets show a transaction manager and a business service definition in
a Spring application context, and an example for a business method
implementation.
- <objects>
+ <objects>
TO BE DONE
</objects>
- public class FulfillmentService : IFulfillmentService
+ public class FulfillmentService : IFulfillmentService
private TransactionTemplate transactionTemplate;
@@ -697,7 +714,7 @@ TO BE DONE
}
-
+ Declarative transaction demarcationAlternatively, one can use Spring's declarative transaction
@@ -711,7 +728,7 @@ TO BE DONE
An example showing attribute driven transaction is shown
below
- <objects>
+ <objects>
<object id="HibernateTransactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">
@@ -740,7 +757,7 @@ TO BE DONE
expresses the intent as compared to the contents of
DeclarativeServicesAttributeDriven.xml.
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.net/schema/tx"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/schema/objects/spring-objects.xsd
@@ -772,7 +789,7 @@ TO BE DONE
The placement of the transaction attribute in the service layer
method is shown below.
- public class FulfillmentService : IFulfillmentService
+ public class FulfillmentService : IFulfillmentService
{
// fields and properties for dao object omitted, see above
@@ -808,7 +825,7 @@ TO BE DONE
boundaries, you can import a configuration file with the following XML
instead of using <tx:attribute-driven/>
- <object id="TxProxyConfigurationTemplate" abstract="true"
+ <object id="TxProxyConfigurationTemplate" abstract="true"
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
<property name="PlatformTransactionManager" ref="HibernateTransactionManager"/>
@@ -825,23 +842,23 @@ TO BE DONE
configuration of other features, such as rollback rules.
-
+ Transaction management strategies
- Both TransactionTemplate and
- TransactionInterceptor (not yet seen explicitly
+ Both TransactionTemplate and
+ TransactionInterceptor (not yet seen explicitly
in above configuration, TransactionProxyFactoryObject uses a
TransactionInterceptor, you would have to specify it explicitly if you
were using an ordinary ProxyFactoryObject.) delegate the actual
transaction handling to a
- PlatformTransactionManager instance, which can be
- a HibernateTransactionManager (for a single
- Hibernate SessionFactory, using a
- ThreadLocal
- Session under the hood) or a
- TxScopeTransactionManager (delegating to MS-DTC
+ PlatformTransactionManager instance, which can be
+ a HibernateTransactionManager (for a single
+ Hibernate SessionFactory, using a
+ ThreadLocal
+ Session under the hood) or a
+ TxScopeTransactionManager (delegating to MS-DTC
for distributed transaction) for Hibernate applications. You could even
- use a custom PlatformTransactionManager
+ use a custom PlatformTransactionManager
implementation. So switching from native Hibernate transaction
management to TxScopeTransactionManager, such as when facing distributed
transaction requirements for certain deployments of your application, is
@@ -852,24 +869,24 @@ TO BE DONE
For distributed transactions across multiple Hibernate session
factories, simply combine
- TxScopeTransactionManager as a transaction
- strategy with multiple LocalSessionFactoryObject
+ TxScopeTransactionManager as a transaction
+ strategy with multiple LocalSessionFactoryObject
definitions. Each of your DAOs then gets one specific
- SessionFactory reference passed into it's
+ SessionFactory reference passed into it's
respective object property.TO BE DONE
- HibernateTransactionManager can export the
- ADO.NET Transaction used by Hibernate to
+ HibernateTransactionManager can export the
+ ADO.NET Transaction used by Hibernate to
plain ADO.NET access code, for a specific
- DbProvider. (matching connection string).
+ DbProvider. (matching connection string).
This allows for high-level transaction demarcation with mixed
Hibernate/ADO.NET data access!
-
+ Web Session ManagementThe open session in view pattern keeps the hibernate session open
@@ -877,7 +894,7 @@ TO BE DONE
displayed. You configure its use by adding an additional custom HTTP
module declaration as shown below
- <system.web>
+ <system.web>
<httpModules>
<add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate"/>
</httpModules>
@@ -890,7 +907,7 @@ TO BE DONE
will use by setting 'global' application key-value pairs as shown below.
(this will change in future releases)
- <appSettings>
+ <appSettings>
<add key="Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName" value="SessionFactory"/>
</appSettings>
@@ -933,7 +950,7 @@ TO BE DONE
you to use a single NHibernate session across multiple transactions. The
usage is shown below
- using (new SessionScope())
+ using (new SessionScope())
{
... do multiple operations with a single session, possibly in multiple transactions.
}
diff --git a/doc/reference/src/overview.xml b/doc/reference/src/overview.xml
index 84b29b21..e7dabb1f 100644
--- a/doc/reference/src/overview.xml
+++ b/doc/reference/src/overview.xml
@@ -1,8 +1,25 @@
-
+
+Introduction
-
+ OverviewSpring.NET is an application framework that provides comprehensive
@@ -79,11 +96,12 @@
started to use the term Dependency Injection. His article then continued
to explain the ideas underpinning the Inversion of Control (IoC) and
Dependency Injection (DI) principle. If you need a decent insight into IoC
- and DI, please do refer to the article :
- http://martinfowler.com/articles/injection.html.
+ and DI, please do refer to the article :
+
+ http://martinfowler.com/articles/injection.html.
-
+ ModulesThe Spring Framework contains a lot of features, which are
@@ -111,7 +129,7 @@
logging, performance monitoring, caching, method retry, and exception
handling.
- Spring.Data - Use this
+ Spring.Data - Use this
module to achieve greater efficiency and consistency in writing data
access functionality in ADO.NET and to perform declarative transaction
management.
@@ -133,7 +151,7 @@
data binding, validation, and ASP.NET page/control/module/provider
configuration.
- Spring.Services - Use this
+ Spring.Services - Use this
module to adapt plain .NET objects so they can be used with a specific
distributed communication technology, such as .NET Remoting, Enterprise
Services, and ASMX Web Services. These services can be configured via
@@ -296,10 +314,10 @@
scheduling.
-
+
NMS - Applicatoin
diff --git a/doc/reference/src/pool.xml b/doc/reference/src/pool.xml
index cd363449..b0e41ae0 100644
--- a/doc/reference/src/pool.xml
+++ b/doc/reference/src/pool.xml
@@ -1,8 +1,25 @@
-
+
+Object Pooling
-
+ IntroductionThe Spring.Pool namespace contains a generic API for implementing
@@ -37,7 +54,7 @@
Note, that if you are concerned only with applying pooling to an
existing object, the pooling APIs discussed here are not very important.
Instead the use and configuration of
- Spring.Aop.Target.SimplePoolTargetSource is more
+ Spring.Aop.Target.SimplePoolTargetSource is more
relevant. Pooling of objects can either be done Programatically or through
the XML configuration of the Spring .NET container. Attribute support for
pooling, similar to the ServicedComponent approach, will be available in a
@@ -47,21 +64,21 @@
use of the pooling API independent of AOP functionality.
-
+ Interfaces and ImplementationsThe Spring.Pool namespace provides two simple
interfaces to manage pools of objects. The first interface,
- IObjectPool describes how to take and put back an
+ IObjectPool describes how to take and put back an
object from the pool. The second interface
- IPoolableObjectFactory is meant to be used in
- conjunction with implementations of the IObjectPool
+ IPoolableObjectFactory is meant to be used in
+ conjunction with implementations of the IObjectPool
to provide guidance in calling various lifecycle events on the objects
managed by the pool. These interfaces are based on the Jakarta Commons
- Pool API. Spring.Pool.Support.SimplePool is a
- default implementation of IObjectPool and
- Spring.Aop.Target.SimplePoolTargetSource is the
- implementation of IPoolableObjectFactory for use
+ Pool API. Spring.Pool.Support.SimplePool is a
+ default implementation of IObjectPool and
+ Spring.Aop.Target.SimplePoolTargetSource is the
+ implementation of IPoolableObjectFactory for use
with AOP. The current goal of the Spring.Pool namespace is not to provide
a one-for-one replacement of the Jakarta Commons Pool API, but rather to
support basic object pooling needs for common AOP scenarios. Consequently,
diff --git a/doc/reference/src/pooling-example.xml b/doc/reference/src/pooling-example.xml
index c4a093f6..0d7527aa 100644
--- a/doc/reference/src/pooling-example.xml
+++ b/doc/reference/src/pooling-example.xml
@@ -60,12 +60,10 @@
In our case, as already said, we want to to implement a pool
of QueuedExecutor. Ok, here the declaration:
-
-public class QueuedExecutorPoolableFactory : IPoolableObjectFactory
+ public class QueuedExecutorPoolableFactory : IPoolableObjectFactory
{
the first task a factory should do is to create objects:
-
-object IPoolableObjectFactory.MakeObject()
+ object IPoolableObjectFactory.MakeObject()
{
// to actually make this work as a pooled executor
// use a bounded queue of capacity 1.
@@ -76,8 +74,7 @@ object IPoolableObjectFactory.MakeObject()
return new QueuedExecutor(new BoundedBuffer(1));
}
and should be also able to destroy them:
-
-void IPoolableObjectFactory.DestroyObject(object o)
+ void IPoolableObjectFactory.DestroyObject(object o)
{
// ah, self documenting code:
// Here you can see that we decided to let the
@@ -90,8 +87,7 @@ void IPoolableObjectFactory.DestroyObject(object o)
When an object is taken from the pool, to satisfy a client request,
may be the object should be activated. We can possibly implement the
activation like this:
-
-void IPoolableObjectFactory.ActivateObject(object o)
+ void IPoolableObjectFactory.ActivateObject(object o)
{
QueuedExecutor executor = o as QueuedExecutor;
executor.Restart();
@@ -113,8 +109,7 @@ void IPoolableObjectFactory.ActivateObject(object o)
).
Here we check that the worker thread exists:
-
-bool IPoolableObjectFactory.ValidateObject(object o)
+ bool IPoolableObjectFactory.ValidateObject(object o)
{
QueuedExecutor executor = o as QueuedExecutor;
return executor.Thread != null;
@@ -124,16 +119,14 @@ bool IPoolableObjectFactory.ValidateObject(object o)
Passivation, symmetrical to activation, is the process a pooled
object is subject to when the object is returned to the pool. In our
case we simply do nothing:
-
-void IPoolableObjectFactory.PassivateObject(object o)
+ void IPoolableObjectFactory.PassivateObject(object o)
{
}
At this point, creating a pool is simply a matter of creating an
SimplePool as in:
-
-pool = new SimplePool(new QueuedExecutorPoolableFactory(), size);
+ pool = new SimplePool(new QueuedExecutorPoolableFactory(), size);
@@ -143,8 +136,7 @@ pool = new SimplePool(new QueuedExecutorPoolableFactory(), size);c# days, so we
implement a very simple helper (PooledObjectHolder)
that can allow us to do things like:
-
-using (PooledObjectHolder holder = PooledObjectHolder.UseFrom(pool))
+ using (PooledObjectHolder holder = PooledObjectHolder.UseFrom(pool))
{
QueuedExecutor executor = (QueuedExecutor) holder.Pooled;
executor.Execute(runnable);
@@ -154,8 +146,7 @@ using (PooledObjectHolder holder = PooledObjectHolder.UseFrom(pool))
Here is the implementation:
-
-public class PooledObjectHolder : IDisposable
+ public class PooledObjectHolder : IDisposable
{
IObjectPool pool;
object pooled;
@@ -204,8 +195,7 @@ public class PooledObjectHolder : IDisposable
Please don't forget to destroy all the pooled istances once you have
finished! How? Well using something like this in
PooledQueuedExecutor:
-
-public void Stop ()
+ public void Stop ()
{
// waits for all the grep-task to have been queued ...
foreach (ISync sync in syncs)
@@ -221,8 +211,7 @@ public void Stop ()
The use of the just built executor is quite straigtforward but a
little tricky if we want to really exploit the pool.
-
-private PooledQueuedExecutor executor;
+ private PooledQueuedExecutor executor;
public ParallelGrep(int size)
{
@@ -246,9 +235,8 @@ public void Stop()
executor.Stop();
}
-
-
-public static void Main(string[] args)
+
+ public static void Main(string[] args)
{
if (args.Length < 3)
{
diff --git a/doc/reference/src/preface.xml b/doc/reference/src/preface.xml
index 67102bfa..5776bf6d 100644
--- a/doc/reference/src/preface.xml
+++ b/doc/reference/src/preface.xml
@@ -1,5 +1,22 @@
-
+
+PrefaceDeveloping software applications is hard enough even with good tools
diff --git a/doc/reference/src/psa-intro.xml b/doc/reference/src/psa-intro.xml
index 3793850b..19a3b009 100644
--- a/doc/reference/src/psa-intro.xml
+++ b/doc/reference/src/psa-intro.xml
@@ -1,5 +1,22 @@
-
+
+Introduction to Spring Services
diff --git a/doc/reference/src/quartz-quickstart.xml b/doc/reference/src/quartz-quickstart.xml
index 71f94e66..dc3f0ad1 100644
--- a/doc/reference/src/quartz-quickstart.xml
+++ b/doc/reference/src/quartz-quickstart.xml
@@ -1,5 +1,22 @@
-
+
+Quartz QuickStart
@@ -21,22 +38,22 @@
The full details of Quartz are outside the scope of this quickstart
but here is 'quick tour for the impatient' of the main classes and
interfaces used in Quartz so you can get your sea legs. A Quartz
- IJob interface represents the task you would like
+ IJob interface represents the task you would like
to execute. You either directly implement Quartz's
- IJob interface or a convenience base class. The
- Quartz Trigger controls when a job is executed, for
+ IJob interface or a convenience base class. The
+ Quartz Trigger controls when a job is executed, for
example in the wee hours of the morning every weekday . This would be done
- using Quartz's CronTrigger implementation.
+ using Quartz's CronTrigger implementation.
Instances of your job are created every time the trigger fires. As such,
in order to pass information between different job instances you stash
data away in a hashtable that gets passed to the each Job instance upon
- its creation. Quartz's JobDetail class combines the
- IJob and this hashtable of data. Instead of the
- standard System.Collections.Hashtable the class
- JobDataMap is used. Triggers are registered with a
- Quartz IScheduler implementation that manages the
+ its creation. Quartz's JobDetail class combines the
+ IJob and this hashtable of data. Instead of the
+ standard System.Collections.Hashtable the class
+ JobDataMap is used. Triggers are registered with a
+ Quartz IScheduler implementation that manages the
overall execution of the triggers and jobs. The
- StdSchedulerFactory implementation is generally
+ StdSchedulerFactory implementation is generally
used.
@@ -44,7 +61,7 @@
Application OverviewThe sample application has two types of Jobs. One that inherits from
- Spring's convenience base class QuartzJobObject and
+ Spring's convenience base class QuartzJobObject and
another which does not inherit from any base class. The latter class is
adapted by Spring to be a Job. Two triggers, one for each of the jobs, are
created. These triggers are in turn registered with a scheduler. In each
@@ -55,13 +72,13 @@
Standard job scheduling
- The Spring base class QuartzJobObject
- implements IJob and allows for your object's
+ The Spring base class QuartzJobObject
+ implements IJob and allows for your object's
properties to be set via values that are stored inside Quartz's
- JobDataMap that is passed along each time your job
+ JobDataMap that is passed along each time your job
is instantiated due a trigger firing. This class is shown below
- public class ExampleJob : QuartzJobObject
+ public class ExampleJob : QuartzJobObject
{
private string userName;
@@ -79,16 +96,16 @@
}
- The method ExecuteInternal is called when the
+ The method ExecuteInternal is called when the
trigger fires and is where you would put your business logic. The
- JobExecutionContext passed in lets you access
+ JobExecutionContext passed in lets you access
various pieces of information about the current job execution, such as the
JobDataMap or information on when the next time the trigger will fire. The
- ExampleJob is configured by creating a
- JobDetail object as shown below in the following
+ ExampleJob is configured by creating a
+ JobDetail object as shown below in the following
XML snippet taken from spring-objects.xml
- <object name="exampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
+ <object name="exampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
<property name="JobType" value="Spring.Scheduling.Quartz.Example.ExampleJob, Spring.Scheduling.Quartz.Example" />
<!-- We can inject values through JobDataMap -->
<property name="JobDataAsMap">
@@ -99,18 +116,18 @@
</object>The dictionary property of the
- JobDetailObject,
- JobDataAsMap, is used to set the values of the
+ JobDetailObject,
+ JobDataAsMap, is used to set the values of the
ExampleJob's properties. This will result in the ExampleJob being
instantiated with it's UserName property value set to 'Alexandre' the
first time the trigger fires.We then will schedule this job to be executed on 20 second
increments of every minute as shown below using Spring's
- CronTriggerObject which creates a Quartz
+ CronTriggerObject which creates a Quartz
CronTrigger.
- <object id="cronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz">
+ <object id="cronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz">
<property name="jobDetail" ref="exampleJob" />
<!-- run every 20 second of minute -->
<property name="cronExpressionString" value="0/20 * * * * ?" />
@@ -119,7 +136,7 @@
Lastly, we schedule this trigger with the scheduler as shown
below
- <object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
+ <object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
<property name="triggers">
<list>
<ref object="cronTrigger" />
@@ -141,7 +158,7 @@
The AdminService class in the example demonstrates this functionality and
is listed below.
- public class AdminService
+ public class AdminService
{
private string userName;
@@ -157,12 +174,12 @@
}Note that it does not inherit from any base class. To instruct
- Spring to create a JobDetail object for this method
+ Spring to create a JobDetail object for this method
we use Spring's factory object class
- MethodInvokingJobDetailFactoryObject as shown
+ MethodInvokingJobDetailFactoryObject as shown
below
- <object id="adminService" type="Spring.Scheduling.Quartz.Example.AdminService, Spring.Scheduling.Quartz.Example">
+ <object id="adminService" type="Spring.Scheduling.Quartz.Example.AdminService, Spring.Scheduling.Quartz.Example">
<!-- we inject straight to target object -->
<property name="UserName" value="admin-service" />
</object>
@@ -174,14 +191,14 @@
</object>
- Note that AdminService object is configured
+ Note that AdminService object is configured
using Spring as you would do normally, without consideration for Quartz.
The trigger associated with the jobDetail object is listed below. Also
note that when using MethodInvokingJobDetailFactoryObject you can't use
database persistence for Jobs. See the class documentation for additional
details.
- <object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz">
+ <object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz">
<!-- see the example of method invoking job above -->
<property name="jobDetail" ref="jobDetail" />
<!-- 5 seconds -->
@@ -200,7 +217,7 @@
This trigger can then be added to the scheduler's list of registered
triggers as shown below.
- <object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
+ <object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
<property name="triggers">
<list>
<ref object="cronTrigger" />
diff --git a/doc/reference/src/quickstarts.xml b/doc/reference/src/quickstarts.xml
index 475ef060..0fb02427 100644
--- a/doc/reference/src/quickstarts.xml
+++ b/doc/reference/src/quickstarts.xml
@@ -1,7 +1,7 @@
-
+IoC Quickstarts
@@ -26,7 +26,7 @@
the Spring.NET framework.
-
+ Movie FinderThe source material for this simple demonstration of Spring.NET's
@@ -65,12 +65,12 @@
-
+ Getting Started - Movie FinderThe startup class for the MovieFinder example is the
MovieApp class, which is an ordinary .NET class with
- a single application entry point... using System;
+ a single application entry point... using System;
namespace Spring.Examples.MovieFinder
{
public class MovieApp
@@ -91,7 +91,7 @@ namespace Spring.Examples.MovieFinder
custom configuration section in a standard .NET application config
file...
- <?xml version="1.0" encoding="utf-8" ?>
+ <?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
@@ -115,7 +115,7 @@ namespace Spring.Examples.MovieFinder
The body of the Main method in the
MovieApp class can now be fleshed out a little
- further...
+ further...
using System;
using Spring.Context;
...
@@ -129,14 +129,14 @@ using Spring.Context;
Spring.Context namespace gives the application access
to the IApplicationContext class that will serve as
the primary means for the application to access the IoC container. The
- line of code... IApplicationContext ctx = ContextRegistry.GetContext();
+ line of code... IApplicationContext ctx = ContextRegistry.GetContext();
... retrieves a fully configured IApplicationContext
implementation that has been configured using the named
<objects/> section from the application config
file.
-
+ First Object DefinitionAs yet, no objects have been defined in the application config
@@ -144,7 +144,7 @@ using Spring.Context;
MovieLister instance that we are going to use in the
application can be seen in the following XML snippet...
- <objects xmlns="http://www.springframework.net">
+ <objects xmlns="http://www.springframework.net">
<object name="MyMovieLister"
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
</object>
@@ -158,7 +158,7 @@ using Spring.Context;
object so defined can be retrieved from the
IApplicationContext reference like so...
- ...
+ ...
public static void Main ()
{
IApplicationContext ctx = ContextRegistry.GetContext();
@@ -177,21 +177,21 @@ using Spring.Context;
injected into the lister instance looks like
this...
- <objects xmlns="http://www.springframework.net">
+ <objects xmlns="http://www.springframework.net">
<object name="MyMovieFinder"
type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/>
</object>
</objects>
-
+ Setter InjectionWhat we want to do is inject the IMovieFinder
instance identified by the MyMovieFinder id into the
MovieLister instance identified by the
MyMovieLister id, which can be accomplished using
- Setter Injection and the following XML... <objects xmlns="http://www.springframework.net">
+ Setter Injection and the following XML... <objects xmlns="http://www.springframework.net">
<object name="MyMovieLister"
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
<!-- using setter injection... -->
@@ -210,7 +210,7 @@ using Spring.Context;
MovieLister object that is referenced in the
application is then fully configured and ready to be used in the
application to do what is does best... list movies by director.
- ...
+ ...
public static void Main ()
{
IApplicationContext ctx = ContextRegistry.GetContext();
@@ -235,12 +235,12 @@ using Spring.Context;
the reference documentation.
-
+ Constructor InjectionLet's define another implementation of the
IMovieFinder interface in the application config
- file......
+ file......
<object name="AnotherMovieFinder"
type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder">
</object>
@@ -248,18 +248,18 @@ using Spring.Context;
IMovieFinder implementation that uses a colon
delimited text file as it's movie source. The C# source code for this
class defines a single constructor that takes a
- System.IO.FileInfo as it's single constructor
+ System.IO.FileInfo as it's single constructor
argument. As this object definition currently stands, attempting to get
this object out of the IApplicationContext in the
- application with a line of code like so... IMovieFinder finder = (IMovieFinder) ctx.GetObject ("AnotherMovieFinder");
+ application with a line of code like so... IMovieFinder finder = (IMovieFinder) ctx.GetObject ("AnotherMovieFinder");
will result in a fatal
- Spring.Objects.Factory.ObjectCreationException,
+ Spring.Objects.Factory.ObjectCreationException,
because the
- Spring.Examples.MovieFinder.ColonDelimitedMovieFinder
+ Spring.Examples.MovieFinder.ColonDelimitedMovieFinder
class does not have a default constructor that takes no arguments. If we
want to use this implementation of the IMovieFinder
interface, we will have to supply an appropriate constructor
- argument......
+ argument......
<object name="AnotherMovieFinder"
type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder">
<constructor-arg index="0" value="movies.txt"/>
@@ -269,11 +269,11 @@ using Spring.Context;
Unsurprisingly, the <constructor-arg/> element is used to
supply constructor arguments to the constructors of managed objects. The
Spring.NET IoC container uses the functionality offered by
- System.ComponentModel.TypeConverter
+ System.ComponentModel.TypeConverter
specializations to convert the movies.txt string into
- an instance of the System.IO.FileInfo that is
+ an instance of the System.IO.FileInfo that is
required by the single constructor of the
- Spring.Examples.MovieFinder.ColonDelimitedMovieFinder
+ Spring.Examples.MovieFinder.ColonDelimitedMovieFinder
(see for a more in depth
treatment concerning the automatic type conversion functionality offered
by Spring.NET).
@@ -283,7 +283,7 @@ using Spring.Context;
distinct object definitions in the config file of the example
application; if we wanted to, we could switch the implementation that
the MyMovieLister object uses like
- so......
+ so......
<object name="MyMovieLister"
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
<!-- lets use the colon delimited implementation instead -->
@@ -306,7 +306,7 @@ using Spring.Context;
MyMovieLister object.
-
+ SummaryThis example application is quite simple, and admittedly it
@@ -345,8 +345,8 @@ using Spring.Context;
log4net in your main application, declare some loggers in code, and then
log log log. (Sing along...) We are using App.config to configure the
loggers. As such, we declare the log4net configuration section handler
- as shown below <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
- The corresponding configuration section looks like this
+ as shown below <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
+ The corresponding configuration section looks like this
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
@@ -379,7 +379,7 @@ using Spring.Context;
The logging name is up to you to decide when you declare the
logger in code. In the case of this example we used the convention of
giving the logging name the name of the fully qualified class name.
- private static readonly ILog LOG = LogManager.GetLogger(typeof (MovieApp));
+ private static readonly ILog LOG = LogManager.GetLogger(typeof (MovieApp));
Other conventions are to give the same logger name across multiple
classes that constitute a logical component or subsystem within the
application, for example a data access layer. One tip in selecting the
@@ -390,7 +390,7 @@ using Spring.Context;
format %logger{2}.To initialize the logging system add the following to the start of
- your application XmlConfigurator.Configure();
+ your application XmlConfigurator.Configure();
Note that if you are using or reading information on version 1.2.0 this
used to be called DOMConfigurator.Configure();
@@ -406,9 +406,9 @@ using Spring.Context;
objects. Coincidentally, the example code itself uses Spring in the
logger name, so this logger also controls the output level you see from
running MainApp. Finally, you are ready to use the simple logger api to
- log, i.e. LOG.Info("Searching for movie...");
+ log, i.e. LOG.Info("Searching for movie...");
Logging exceptions is another common task, which can be done using the
- error level try {
+ error level try {
//do work
{
catch (Exception e)
@@ -418,7 +418,7 @@ catch (Exception e)
-
+ ApplicationContext and IMessageSource
@@ -453,7 +453,7 @@ catch (Exception e)
to the ResourceManager in other parts of your application. In the
example program an embedded resource file, MyResource.resx and a Spanish
specific resource file, MyResources.es.resx are declared in this manner.
- The corresponding XML fragment is shown below ...
+ The corresponding XML fragment is shown below ...
<object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core">
<property name="resourceManagers">
<list>
@@ -484,7 +484,7 @@ catch (Exception e)
contains a text resource, Hello {0} {1} under the key
name HelloMessage (aka Keys.HELLO_MESSAGE) that can
be used for string text formatting purposes. The example code
-
+
string msg = ctx.GetMessage(Keys.HELLO_MESSAGE,
CultureInfo.CurrentCulture,
"Mr.", "Anderson");
@@ -492,7 +492,7 @@ string msg = ctx.GetMessage(Keys.HELLO_MESSAGE,
the string with the passed argument values resulting in the text, "Hello
Mr. Anderson". The current culture is used to select the resource file
MyResource.resx. If instead the Spanish culture is specified
-
+
CultureInfo spanishCultureInfo = new CultureInfo("es");
string esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
spanishCultureInfo,
@@ -510,7 +510,7 @@ string esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
into a key of its own, called FemaleGreeting (aka
Keys.FEMALE_GREETING). The replacement value for the message argument
{0} can then be made localization aware by wrapping the key in a
- convenience class DefaultMessageResolvable. The code
+ convenience class DefaultMessageResolvable. The code
string[] codes = {Keys.FEMALE_GREETING};
DefaultMessageResolvable dmr = new DefaultMessageResolvable(codes, null);
@@ -519,7 +519,7 @@ msg = ctx.GetMessage(Keys.HELLO_MESSAGE,
dmr, "Anderson");
will assign msg the value, Hello Mrs. Anderson, since the
value for the key FemaleGreeting in MyResource.resx
- is 'Mrs.' Similarly, the code
+ is 'Mrs.' Similarly, the code
esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
spanishCultureInfo,
dmr, "Anderson");
@@ -536,7 +536,7 @@ esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
property Name. The resource file, Person.resx contains key names that
follow the pattern, person.<PropertyName>. In this case it
contains person.Name and person.Age. The code to assign these resource
- values to an object is shown below
+ values to an object is shown below
Person p = new Person();
ctx.ApplyResources(p, "person", CultureInfo.CurrentUICulture);
While you could also use the Spring itself to set the
diff --git a/doc/reference/src/remoting-quickstart.xml b/doc/reference/src/remoting-quickstart.xml
index b47565e4..23931b61 100644
--- a/doc/reference/src/remoting-quickstart.xml
+++ b/doc/reference/src/remoting-quickstart.xml
@@ -1,8 +1,25 @@
-
+
+Portable Service Abstraction Quick Start
-
+ IntroductionThis quickstart demonstrates the basic usage of Spring.NET's
@@ -12,17 +29,17 @@
shows the use of the WebServiceExporter.
-
+ .NET Remoting ExampleThe infrastructure classes are located in the
Spring.Services assembly under the
Spring.Services.Remoting namespace. The overall
strategy is to export .NET objects on the server side as either CAO or SAO
- objects using CaoExporter or
- SaoExporter and obtain references to these objects
- on the client side using CaoFactoryObject and
- SaoFactoryObject. This quickstart does assume
+ objects using CaoExporter or
+ SaoExporter and obtain references to these objects
+ on the client side using CaoFactoryObject and
+ SaoFactoryObject. This quickstart does assume
familiarity with .NET Remoting on the part of the reader. If you are new
to .NET remoting you may find the links to introductory remoting material
presented at the conclusion of this quickstart of some help.
@@ -46,23 +63,23 @@
The Spring.Calculator.Contract project contains
- the interface ICalculator that defines the basic
+ the interface ICalculator that defines the basic
operations of a calculator and another interface
- IAdvancedCalculator that adds support for memory
+ IAdvancedCalculator that adds support for memory
storage for results. (woo hoo - big feature - HP-12C beware!) These
interfaces are shown below. The
Spring.Calculator.Services project contains an
implementation of the these interfaces, namely the classes
- Calculator and
- AdvancedCalculator. The purpose of the
- AdvancedCalculator implementation is to demonstrate
+ Calculator and
+ AdvancedCalculator. The purpose of the
+ AdvancedCalculator implementation is to demonstrate
the configuration of object state for SAO-singleton objects. Note that the
calculator implementations do not inherit from the
- MarshalByRefObject class. The
+ MarshalByRefObject class. The
Spring.Calculator.ClientApp project contains the client
application and the Spring.Calculator.RemoteApp project
contains a console application that will host a Remoted instance of the
- AdvancedCalculator class. The
+ AdvancedCalculator class. The
Spring.Aspects project contains some logging advice
that will be used to demonstrate the application of aspects to remoted
objects. Spring.Calculator.RegisterComponentServices is
@@ -70,7 +87,7 @@
quickstart. Spring.Calculator.Web is related to web
services exporters and is not relevant for this quickstart.
- public interface ICalculator
+ public interface ICalculator
{
int Add(int n1, int n2);
@@ -103,7 +120,7 @@ public class DivisionResult
An extension of this interface that supports having a slot for
calculator memory is shown below
- public interface IAdvancedCalculator : ICalculator
+ public interface IAdvancedCalculator : ICalculator
{
int GetMemory();
@@ -137,7 +154,7 @@ public class DivisionResult
barrage of OO design ranting finished, on to the implementation!
-
+ ImplementationThe implementation of the calculators contained in the
@@ -147,7 +164,7 @@ public class DivisionResult
using constructor injection. A subset of the implementation is shown
below.
- public class Calculator : ICalculator
+ public class Calculator : ICalculator
{
public int Add(int n1, int n2)
@@ -197,11 +214,11 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
}
- The Spring.Calculator.RemotedApp project
+ The Spring.Calculator.RemotedApp project
hosts remoted objects inside a console application. The code is also quite
simple and shown below
- public static void Main(string[] args)
+ public static void Main(string[] args)
{
try
{
@@ -227,7 +244,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
(App.config). In this case we are using the
tcp channel on port 8005.
- <system.runtime.remoting>
+ <system.runtime.remoting>
<application>
<channels>
<channel ref="tcp" port="8005" />
@@ -240,7 +257,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
remoting configurations. The AOP advice used in this example is a simple
Log4Net based around advice.
- <configSections>
+ <configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
@@ -310,8 +327,8 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
property values and / or object references is done as you would normally
do for any object declared in the Spring.NET configuration file. To expose
the calculator objects as .NET remoted objects the exporter
- Spring.Remoting.CaoExporter is used for CAO objects
- and Spring.Remoting.SaoExporter is used for SAO
+ Spring.Remoting.CaoExporter is used for CAO objects
+ and Spring.Remoting.SaoExporter is used for SAO
objects. Both exporters require the setting of a
TargetName property that refers to the name of the
object in Spring's IoC container that will be remoted. The semantics of
@@ -323,7 +340,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
property Infinite is set to true.
The configuration for the exporting a SAO-Singleton is shown
- below.<objects
+ below.<objects
xmlns="http://www.springframework.net"
xmlns:r="http://www.springframework.net/remoting">
@@ -334,16 +351,16 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
serviceName="RemotedSaoSingletonCalculator" />
</objects>The configuration shown above uses the Spring
Remoting schema but you can also choose to use the standard 'generic' XML
- configuration shown below.<object name="saoSingletonCalculator" type="Spring.Remoting.SaoExporter, Spring.Services">
+ configuration shown below.<object name="saoSingletonCalculator" type="Spring.Remoting.SaoExporter, Spring.Services">
<property name="TargetName" value="singletonCalculator" />
<property name="ServiceName" value="RemotedSaoSingletonCalculator" />
</object> This will result in the remote object being
identified by the URL
tcp://localhost:8005/RemotedSaoSingletonCalculator. The
- use of SaoExporter and
- CaoExporter for other configuration are similar,
+ use of SaoExporter and
+ CaoExporter for other configuration are similar,
look at the configuration files in the
- Spring.Calculator.RemotedApp project files for more
+ Spring.Calculator.RemotedApp project files for more
information.On the client side, the client application will connect a specific
@@ -354,7 +371,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
application configuration file (App.config), as can
been seen below.
- <system.runtime.remoting>
+ <system.runtime.remoting>
<application>
<channels>
<channel ref="tcp"/>
@@ -364,7 +381,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
The client implementation code is shown below.
- public static void Main(string[] args)
+ public static void Main(string[] args)
{
try
{
@@ -410,7 +427,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
Components (Enterprise Services) of the calculator object but are not
discussed in this QuickStart.
-
+
<spring>
<context>
<resource uri="config://spring/objects" />
@@ -450,7 +467,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
The inProcess.xml configuration file creates an instance of
- AdvancedCalculator directly
+ AdvancedCalculator directly
<objects xmlns="http://www.springframework.net">
<description>inProcess</description>
@@ -462,10 +479,10 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
Factory classes are used to create a client side reference to the
.NET remoting implementations. For SAO objects use the
- SaoFactoryObject class and for CAO objects use the
- CaoFactoryObject class. The configuration for
+ SaoFactoryObject class and for CAO objects use the
+ CaoFactoryObject class. The configuration for
obtaining a reference to the previously exported SAO singleton
- implementation is shown below <objects xmlns="http://www.springframework.net">
+ implementation is shown below <objects xmlns="http://www.springframework.net">
<description>saoSingleton</description>
@@ -486,7 +503,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
to easily switch between test, QA, and production (yea baby!)
environments. An example of how this would be expressed is...
- <property name="ServiceUrl" value="${protocol}://${host}:${port}/RemotedSaoSingletonCalculator" />
+ <property name="ServiceUrl" value="${protocol}://${host}:${port}/RemotedSaoSingletonCalculator" />The property values in this example are defined elsewhere; refer to
for additional
@@ -496,7 +513,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
making a simple change to the configuration file.The configuration for obtaining a reference to the previously
- exported CAO implementation is shown below <objects xmlns="http://www.springframework.net">
+ exported CAO implementation is shown below <objects xmlns="http://www.springframework.net">
<description>cao</description>
@@ -558,7 +575,7 @@ Memory = 2
definitions which should give you a good feel for how to use the
schema.
- <!-- Calculator definitions -->
+ <!-- Calculator definitions -->
<object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services">
<constructor-arg type="int" value="217" />
</object>
@@ -588,8 +605,8 @@ Memory = 2
method on the remoted object is invoked for the SAO case.
-
- .NET Enterprise Services Example
+
+ .NET Enterprise Services ExampleThe .NET Enterprise Services example is located in the project
Spring.Calculator.RegisterComponentServices.2005.csproj or
@@ -600,7 +617,7 @@ Memory = 2
Spring.Calculator.RegisterComponentServices.Config. The top level
configuration is shown below
- <spring>
+ <spring>
<context>
<resource uri="config://spring/objects" />
@@ -625,7 +642,7 @@ Memory = 2
AccessControl and Roles properties. The configuration file for
enterpriseServices.xml is shown below
- <objects xmlns="http://www.springframework.net">
+ <objects xmlns="http://www.springframework.net">
<description>enterpriseService</description>
@@ -681,7 +698,7 @@ Memory = 2
</objects>
-
+ Web Services ExampleThe WebServices example shows how to export the AdvancedCalculator
@@ -689,7 +706,7 @@ Memory = 2
logging advice applied to it. The main configuration file, Web.config,
includes information from three locations as shown below
- <context>
+ <context>
<resource uri="config://spring/objects"/>
<resource uri="~/Config/webServices.xml"/>
<resource uri="~/Config/webServices-aop.xml"/>
@@ -698,7 +715,7 @@ Memory = 2
The config section 'spring/objects' in Web.config contains the
definition for the 'plain' Advanced calculator, as well as the definitions
to create an AOP proxy of an AdvancedCalculator that adds logging advice.
- These definitions are shown below <objects xmlns="http://www.springframework.net">
+ These definitions are shown below <objects xmlns="http://www.springframework.net">
<!-- Aspect -->
@@ -724,7 +741,7 @@ Memory = 2
</objects>The configuration file webService.xml
simply exports the named calculator object
- <object id="calculatorService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
+ <object id="calculatorService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
<property name="TargetName" value="calculator" />
<property name="Namespace" value="http://SpringCalculator/WebServices" />
<property name="Description" value="Spring Calculator Web Services" />
@@ -733,7 +750,7 @@ Memory = 2
Whereas the webService-aop.xml exports the calculator instance that
has AOP advice applied to it.
- <object id="calculatorServiceWeaved" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
+ <object id="calculatorServiceWeaved" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
<property name="TargetName" value="calculatorWeaved" />
<property name="Namespace" value="http://SpringCalculator/WebServices" />
<property name="Description" value="Spring Calculator Web Services" />
@@ -780,7 +797,7 @@ Memory = 2
2007-10-15 17:59:47,421 [DEBUG] Spring.Aspects.Logging.CommonLoggingAroundAdvice - Intercepted call : returned '4'
-
+ Additional ResourcesSome introductory articles on .NET remoting can be found online at
diff --git a/doc/reference/src/remoting.xml b/doc/reference/src/remoting.xml
index ee81e7fa..623cebba 100644
--- a/doc/reference/src/remoting.xml
+++ b/doc/reference/src/remoting.xml
@@ -1,8 +1,25 @@
-
+
+.NET Remoting
-
+ IntroductionSpring's .NET Remoting support allows you to export a 'plain .NET
@@ -32,7 +49,7 @@
item.
-
+ Publishing SAOs on the ServerExposing a Singleton SAO service can be done in two ways. The first
@@ -45,7 +62,7 @@
RemotingServices.Marshal. This method overcomes the
limitations of the first method. Example server side code for publishing
an SAO singleton object with a predefined state is shown below
- AdvancedMBRCalculator calc = new AdvancedMBRCalculator(217);
+ AdvancedMBRCalculator calc = new AdvancedMBRCalculator(217);
RemotingServices.Marshal(calc, "MyRemotedCalculator");The class AdvancedMBRCalculator used above inherits from
@@ -54,18 +71,18 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");If your design calls for configuring a singleton SAO, or using a
non-default constructor, you can use the Spring IoC container to create
the SAO instance, configure it, and register it with the .NET remoting
- infrastructure. The SaoExporter class performs this
+ infrastructure. The SaoExporter class performs this
task and most importantly, will automatically create a proxy class that
inherits from MarshalbyRefObject if your business object does not already
do so. The following XML taken from the Remoting QuickStart demonstrates its
usage to an SAO Singleton object
-
+ SAO Singleton
- <object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services">
+ <object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services">
<constructor-arg type="int" value="217"/>
</object>
@@ -80,14 +97,14 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");
"RemotedSaoSingletonCalculator". (The fully qualified url is
tcp://localhost:8005/RemotedSaoSingleCallCalculator using the standard
.NET channel configuration shown further below.)
- AdvancedCalculator class implements the business
- interface IAdvancedCalculator. The current proxy
+ AdvancedCalculator class implements the business
+ interface IAdvancedCalculator. The current proxy
implementation requires that your business objects implement an interface.
The interfaces' methods will be the ones exposed in the generated .NET
remoting proxy. The initial memory of the calculator is set to 217 via the
- constructor. The class AdvancedCalculator
+ constructor. The class AdvancedCalculatordoes not inherit from
- MarshalByRefObject. Also note that the exporter
+ MarshalByRefObject. Also note that the exporter
sets the lifetime of the SAO Singleton to infinite so that the singleton
will not be garbage collected after 5 minutes (the .NET default lease
time). If you would like to vary the lifetime properties, they are
@@ -95,7 +112,7 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");A custom schema is provided to make the object declaration even
easier and with intellisense support for the attributes. This is shown
- below<objects xmlns="http://www.springframework.net"
+ below<objects xmlns="http://www.springframework.net"
xmlns:r="http://www.springframework.net/remoting">
<r:saoExporter targetName="singletonCalculator"
@@ -106,12 +123,12 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");
</objects>Refer to the end of this chapter for more
information on Spring's .NET custom schema.
-
+ SAO SingleCallThe following XML fragment shows how to expose the calculator
- service in SAO 'SingleCall' mode. <object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
+ service in SAO 'SingleCall' mode. <object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
singleton="false">
<constructor-arg type="int" value="217"/>
</object>
@@ -129,7 +146,7 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");
singleton calculator, the following standard AOP configuration is used to
create the target for the SaoExporter
- <object id="singletonCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
+ <object id="singletonCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="target" ref="singletonCalculator"/>
<property name="interceptorNames">
<list>
@@ -146,15 +163,15 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");As generally required with a .NET Remoting application, the
arguments to your service methods should be Serializable.
-
+ Console Application Configuration
- When using SaoExporter you can still use
+ When using SaoExporter you can still use
the standard remoting administration section in the application
configuration file to register the channel.
- ChannelServices as shown below
+ ChannelServices as shown below
- <system.runtime.remoting>
+ <system.runtime.remoting>
<application>
<channels>
<channel ref="tcp" port="8005" />
@@ -166,7 +183,7 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");
initialize the .NET Remoting infrastructure with a call to
RemotingConfiguration (since we are using the .config file for channel
registration) and then start the Spring application context. This is
- shown below RemotingConfiguration.Configure("RemoteApp.exe.config");
+ shown below RemotingConfiguration.Configure("RemoteApp.exe.config");
IApplicationContext ctx = ContextRegistry.GetContext();
@@ -176,23 +193,23 @@ Console.ReadLine();
You can also put in the configuration file an instance of the
- object Spring.Remoting.RemotingConfigurer to make
+ object Spring.Remoting.RemotingConfigurer to make
the RemotingConfiguration call show above on your behalf during
initialization of the IoC container. The
- RemotingConfigurer implements the
- IObjectFactoryPostProcessor interface,
+ RemotingConfigurer implements the
+ IObjectFactoryPostProcessor interface,
which gets called after all object definitions have been loaded but
before they have been instantiated, (See for more
information). The RemotingConfigurer has two properties you can
- configure. Filename, that specifies the filename
+ configure. Filename, that specifies the filename
to load the .NET remoting configuration from (if null the default file
- name is used) and EnsureSecurity which makes sure
+ name is used) and EnsureSecurity which makes sure
the channel in encrypted (available only on .NET 2.0). As a convenience,
the custom Spring remoting schema can be used to define an instance of
this class as shown below, taken from the Remoting QuickStart
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:r="http://www.springframework.net/remoting">
<r:configurer filename="Spring.Calculator.RemoteApp.exe.config" />
@@ -205,7 +222,7 @@ Console.ReadLine();
code in action.
-
+ IIS Application ConfigurationIf you are deploying a .NET remoting application inside IIS there
@@ -219,7 +236,7 @@ Console.ReadLine();
Spring IoC container inside the application start method defined in
Global.asax, as shown below
- void Application_Start(object sender, EventArgs e)
+ void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
@@ -241,7 +258,7 @@ Console.ReadLine();
-
+ Accessing a SAO on the ClientAdministrative type registration on the client side lets you easily
@@ -267,17 +284,17 @@ Console.ReadLine();
object is a SAO object. A call to Activator.GetObject
will instantiate a SAO proxy on the client. For CAO objects another
mechanism is used and is discussed later. The code to obtain the SAO proxy
- is shown below ICalculator calc = (ICalculator)Activator.GetObject (
+ is shown below ICalculator calc = (ICalculator)Activator.GetObject (
typeof (ICalculator),
"tcp://localhost:8005/MyRemotedCalculator");To obtain a reference to a SAO proxy within the IoC container, you
- can use the object factory SaoFactoryObject in the
+ can use the object factory SaoFactoryObject in the
Spring configuration file. The following XML taken from the Remoting QuickStart demonstrates its
usage.
- <object id="calculatorService" type="Spring.Remoting.SaoFactoryObject, Spring.Services">
+ <object id="calculatorService" type="Spring.Remoting.SaoFactoryObject, Spring.Services">
<property name="ServiceInterface" value="Spring.Calculator.Interfaces.IAdvancedCalculator, Spring.Calculator.Contract" />
<property name="ServiceUrl" value="tcp://localhost:8005/RemotedSaoSingletonCalculator" />
</object>
@@ -287,11 +304,11 @@ Console.ReadLine();
server and published object name.
Other objects in the IoC container that depend on an implementation
- of the interface ICalculator can now refer to the
+ of the interface ICalculator can now refer to the
object "calculatorService", thereby using a remote implementation of this
interface. The exposure of dependencies among objects within the IoC
container lets you easily switch the implementation of
- ICalculator. By using the IoC container changing
+ ICalculator. By using the IoC container changing
the application to use a local instead of remote implementation is a
configuration file change, not a code change. By promoting interface based
programing, the ability to switch implementation makes it easier to unit
@@ -304,7 +321,7 @@ Console.ReadLine();
integrate with the server implementation when it is ready.
-
+ CAO best practicesCreating a client activated object (CAO) is typically done by
@@ -320,7 +337,7 @@ Console.ReadLine();
factory per class, we can create a generic SAO object factory to return
CAO references to objects defined in Spring's application context. This
functionality is encapsulated in Spring's
- CaoExporter class. On the client side a reference
+ CaoExporter class. On the client side a reference
is obtained using CaoFactoryObject. The client side
factory object supports creation of the CAO object using constructor
arguments. In addition to reducing the clutter and tedium around creating
@@ -334,14 +351,14 @@ Console.ReadLine();
resources.
-
+ Registering a CAO object on the ServerTo expose an object as a CAO on the server you should declare an
object in the standard Spring configuration that is a 'prototype', that is
the singleton property is set to false. This results in a new object being
created each time it is retrieved from Spring's IoC container. An
- implementation of ICaoRemoteFactory is what
+ implementation of ICaoRemoteFactory is what
is exported via a call to RemotingServices.Marshal. This implementation
uses Spring's IoC container to create objects and then dynamically create
a .NET remoting proxy for the retrieved object. Note that the default
@@ -351,14 +368,14 @@ Console.ReadLine();
This is best shown using an example from the Remoting Quickstart
application. Here is the definition of a simple calculator object,
- <object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
+ <object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
singleton="false">
<constructor-arg type="int" value="217" />
</object>To export this as a CAO object we can declare
- the CaoExporter object directly in the server's XML
+ the CaoExporter object directly in the server's XML
configuration file, as shown below
- <object id="caoCalculator" type="Spring.Remoting.CaoExporter, Spring.Services">
+ <object id="caoCalculator" type="Spring.Remoting.CaoExporter, Spring.Services">
<property name="TargetName" value="prototypeCalculator" />
<property name="Infinite" value="false" />
<property name="InitialLeaseTime" value="2m" />
@@ -372,7 +389,7 @@ Console.ReadLine();
Alternatively, you can use the remoting schema and declare the CAO
object as shown below
- <r:caoExporter targetName="prototypeCalculator" infinite="false">
+ <r:caoExporter targetName="prototypeCalculator" infinite="false">
<r:lifeTime initialLeaseTime="2m" renewOnCallTime="1m" />
</r:caoExporter>
@@ -386,7 +403,7 @@ Console.ReadLine();
from the Remoting QuickStart, a calculator with logging around advice is
defined as shown below.
- <object id="prototypeCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
+ <object id="prototypeCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="targetSource">
<object type="Spring.Aop.Target.PrototypeTargetSource, Spring.Aop">
<property name="TargetObjectName" value="prototypeCalculator" />
@@ -403,19 +420,19 @@ Console.ReadLine();
linkend="aop" /> for more information. The CAO exporter then references
with the name 'prototypeCalculatorWeaved' as shown below.
- <r:caoExporter targetName="prototypeCalculatorWeaved" infinite="false">
+ <r:caoExporter targetName="prototypeCalculatorWeaved" infinite="false">
<r:lifeTime initialLeaseTime="2m" renewOnCallTime="1m" />
</r:caoExporter>
-
+ Accessing a CAO on the ClientOn the client side a CAO reference is obtained by using the
- CaoFactoryObject as shown below
+ CaoFactoryObject as shown below
- <object id="calculatorService" type="Spring.Remoting.CaoFactoryObject, Spring.Services">
+ <object id="calculatorService" type="Spring.Remoting.CaoFactoryObject, Spring.Services">
<property name="RemoteTargetName" value="prototypeCalculator" />
<property name="ServiceUrl" value="tcp://localhost:8005" />
</object>
@@ -424,14 +441,14 @@ Console.ReadLine();
previous section. The property 'RemoteTargetName' identifies the object on
the server side. Using this approach the client can obtain an reference
though standard DI techniques to a remote object that implements the
- IAdvancedCalculator interface. (As always,
+ IAdvancedCalculator interface. (As always,
that doesn't mean the client should treat the object as if it was an
in-process object).
Alternatively, you can use the Remoting schema to shorten this
definition and provide intellisense code completion
- <r:caoFactory id="calculatorService"
+ <r:caoFactory id="calculatorService"
remoteTargetName="prototypeCalculator"
serviceUrl="tcp://localhost:8005" />
@@ -440,12 +457,12 @@ Console.ReadLine();
Applying AOP advice to a client side CAO object is done just like
any other object. Simply use the id of the object created by the
- CaoFactoryObject as the AOP target, i.e.
+ CaoFactoryObject as the AOP target, i.e.
'calculatorService' in the previous example.
-
+ XML Schema for configurationPlease install the XSD schemas into VS.NET as described in
-
+ Additional ResourcesTwo articles that describe the process of creating a standard SAO
diff --git a/doc/reference/src/resources.xml b/doc/reference/src/resources.xml
index 9d1b34cc..3427d29d 100644
--- a/doc/reference/src/resources.xml
+++ b/doc/reference/src/resources.xml
@@ -1,14 +1,31 @@
-
+
+Resources
-
+ IntroductionThe IResource interface contained in the
Spring.Core.IO namespace provides a common interface to
describe and access data from diverse resource locations. This abstraction
- lets you treat the InputStream from a file and from
+ lets you treat the InputStream from a file and from
a URL in a polymorphic and protocol-independent manner... the .NET BCL
does not provide such an abstraction. The IResource
interface inherits from IInputStream that provides a
@@ -21,11 +38,11 @@
- The IResource interface
+ The IResource interfaceThe IResource interface is shown below
- public interface IResource : IInputStreamSource
+ public interface IResource : IInputStreamSource
{
bool IsOpen { get; }
@@ -61,7 +78,7 @@
InputStreamInherited from IInputStream. Opens and returns a
- System.IO.Stream. It is expected that each
+ System.IO.Stream. It is expected that each
invocation returns a fresh Stream. It is the responsibility of the
caller to close the stream.
@@ -81,7 +98,7 @@
cannot be read multiple times, and must be read once only and then
closed to avoid resource leaks. Will be false for all usual
resource implementations, with the exception of
- InputStreamResource.
+ InputStreamResource.
@@ -100,7 +117,7 @@
File
- Returns a System.IO.FileInfo for
+ Returns a System.IO.FileInfo for
this resource if it can be resolved to an absolute file
path.
@@ -145,7 +162,7 @@
The Resource abstraction is used extensively in Spring itself, as an
argument type in many method signatures when a resource is needed. Other
methods in some Spring APIs (such as the constructors to various
- IApplicationContext implementations), take
+ IApplicationContext implementations), take
a String which is used to create a Resource appropriate to that context
implementation
@@ -206,7 +223,7 @@
a wrapper around a raw
- System.IO.Stream
+ System.IO.Stream
. Uri syntax is not supported.
@@ -227,37 +244,37 @@
Registering custom IResource implementationsThe configuration section handler,
- ResourceHandlersSectionHandler, is used to
- register any custom IResource
+ ResourceHandlersSectionHandler, is used to
+ register any custom IResource
implementations you have created. In the configuration section you list
- the type of IResource implementation and
+ the type of IResource implementation and
the protocol prefix. Your custom
- IResource implementation must provide a
+ IResource implementation must provide a
constructor that takes a string as it's sole argument that represents
the URI string. Refer to the SDK documentation for
- ResourceHandlersSectionHandler for more
+ ResourceHandlersSectionHandler for more
information. An example of the
- ResourceHandlersSectionHandler is shown below for
- a fictional IResource implementation that
+ ResourceHandlersSectionHandler is shown below for
+ a fictional IResource implementation that
interfaces with a database.
- <configuration>
+ <configuration>
<configSections>
<sectionGroup name="spring">
<section name='context' type='Spring.Context.Support.ContextHandler, Spring.Core'/>
- <section name="resourceHandlers"
- type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/>
+ <section name="resourceHandlers"
+ type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/>
</sectionGroup>
</configSections>
<spring>
- <resourceHandlers>
+ <resourceHandlers>
<handler protocol="db" type="MyCompany.MyApp.Resources.MyDbResource, MyAssembly"/>
- </resourceHandlers>
+ </resourceHandlers>
<context>
<resource uri="db://user:pass@dbName/MyDefinitionsTable"/>
@@ -269,21 +286,21 @@
- The IResourceLoader
+ The IResourceLoaderTo load resources given their Uri syntax, an implementation of the
- IResourceLoader is used. The default implementation
- is ConfigurableResourceLoader. Typically you will
+ IResourceLoader is used. The default implementation
+ is ConfigurableResourceLoader. Typically you will
not need to access this class directly since the
- IApplicationContext implements the
- IResourceLoader interface that contains the single
+ IApplicationContext implements the
+ IResourceLoader interface that contains the single
method IResource GetResource(string location). The
provided implementations of IApplicationContext
delegate this method to an instance of
- ConfigurableResourceLoader which supports the Uri
+ ConfigurableResourceLoader which supports the Uri
protocols/schemes listed previously. If you do not specify a protocol then
the file protocol is used. The following shows some sample
- usage.IResource resource = appContext.GetResource("http://www.springframework.net/license.html");
+ usage.IResource resource = appContext.GetResource("http://www.springframework.net/license.html");
resource = appContext.GetResource("assembly://Spring.Core.Tests/Spring/TestResource.txt");
resource = appContext.GetResource("https://sourceforge.net/");
resource = appContext.GetResource("file:///C:/WINDOWS/ODBC.INI");
@@ -299,7 +316,7 @@ Console.WriteLine(reader.ReadToEnd()); Other protocols can be
The CreateRelative method allows you to easily
load resources based on a relative path name. In the case of relative
assembly resources, the relative path navigates the namespace within an
- assembly. For example: IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt");
+ assembly. For example: IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt");
IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");
This loads the resource TestResource.txt and then
navigates to the Spring.Core.IO namespace and loads the
@@ -307,14 +324,14 @@ IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");
- The IResourceLoaderAware
+ The IResourceLoaderAware
interface
- The IResourceLoaderAware interface is
+ The IResourceLoaderAware interface is
a special marker interface, identifying objects that expect to be provided
- with a IResourceLoader reference.
+ with a IResourceLoader reference.
- public interface IResourceLoaderAware
+ public interface IResourceLoaderAware
{
IResourceLoader ResourceLoader
{
@@ -324,29 +341,29 @@ IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");
}When a class implements
- IResourceLoaderAware and is deployed into
+ IResourceLoaderAware and is deployed into
an application context (as a Spring-managed object), it is recognized as
- IResourceLoaderAware by the application
+ IResourceLoaderAware by the application
context. The application context will then invoke the ResourceLoader
property, supplying itself as the argument (remember, all application
contexts in Spring implement the
- IResourceLoader interface).
+ IResourceLoader interface).
Of course, since an
- IApplicationContext is a
- IResourceLoader, the object could also
- implement the IApplicationContextAware
+ IApplicationContext is a
+ IResourceLoader, the object could also
+ implement the IApplicationContextAware
interface and use the supplied application context directly to load
resources, but in general, it's better to use the specialized
- IResourceLoader interface if that's all
+ IResourceLoader interface if that's all
that's needed. The code would just be coupled to the resource loading
interface, which can be considered a utility interface, and not the whole
- Spring IApplicationContext
+ Spring IApplicationContext
interface.
- Application contexts and IResource
+ Application contexts and IResource
pathsAn application context constructor (for a specific application
@@ -355,7 +372,7 @@ IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");
of the context. For example, you can create an XmlApplicationContext from
two resources as follows:
- IApplicationContext context = new XmlApplicationContext(
+ IApplicationContext context = new XmlApplicationContext(
"file://objects.xml", "assembly://MyAssembly/MyProject/objects-dal-layer.xml");
diff --git a/doc/reference/src/scheduling.xml b/doc/reference/src/scheduling.xml
index addbeda9..a0bc0d86 100644
--- a/doc/reference/src/scheduling.xml
+++ b/doc/reference/src/scheduling.xml
@@ -1,41 +1,58 @@
-
+
+Scheduling and Thread Pooling
-
+ IntroductionThe Spring Framework features integration classes for scheduling
support. Currently, Spring supports the Quartz Scheduler (). The scheduler is set up
- using a IFactoryObject with optional
- references to Trigger instances, respectively.
+ using a IFactoryObject with optional
+ references to Trigger instances, respectively.
Furthermore, a convenience class for both the Quartz Scheduler is
available that allows you to invoke a method of an existing target
object.
-
+ Using the Quartz.NET Scheduler
- Quartz uses Trigger,
- Job and JobDetail objects to
+ Quartz uses Trigger,
+ Job and JobDetail objects to
realize scheduling of all kinds of jobs. For the basic concepts behind
Quartz, have a look at . For convenience
purposes, Spring offers a couple of classes that simplify the usage of
Quartz within Spring-based applications.
-
+ Using the JobDetailObject
- JobDetail objects contain all information
+ JobDetail objects contain all information
needed to run a job. The Spring Framework provides a
- JobDetailObject that makes the
- JobDetail easier to configure and with sensible
+ JobDetailObject that makes the
+ JobDetail easier to configure and with sensible
defaults. Let's have a look at an example:
-
+
<object name="ExampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
<property name="JobType" value="Example.Quartz.ExampleJob, Example.Quartz" />
<property name="JobDataAsMap">
@@ -46,17 +63,17 @@
</object>The job detail object has all information it needs to run the job
- (ExampleJob). The timeout is specified in the job
+ (ExampleJob). The timeout is specified in the job
data dictionary. The job data dictonary is available through the
- JobExecutionContext (passed to you at execution
- time), but the JobDetailObject also maps the
+ JobExecutionContext (passed to you at execution
+ time), but the JobDetailObject also maps the
properties from the job data map to properties of the actual job. So in
- this case, if the ExampleJob contains a property
+ this case, if the ExampleJob contains a property
named Timeout, the
- JobDetailObject will automatically apply
+ JobDetailObject will automatically apply
it:
- namespace Example.Quartz;
+ namespace Example.Quartz;
public class ExampleJob extends QuartzJobObject {
@@ -85,15 +102,15 @@ public class ExampleJob extends QuartzJobObject {
ExampleJob).
-
+ Using the
- MethodInvokingJobDetailFactoryObject
+ MethodInvokingJobDetailFactoryObjectOften you just need to invoke a method on a specific object. Using
- the MethodInvokingJobDetailFactoryObject you can
+ the MethodInvokingJobDetailFactoryObject you can
do exactly this:
- <object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz">
+ <object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz">
<property name="TargetObject" ref="ExampleBusinessObject" />
<property name="TargetMethod" value="DoIt" />
</object>
@@ -102,7 +119,7 @@ public class ExampleJob extends QuartzJobObject {
method being called on the exampleBusinessObject
method (see below):
- public class ExampleBusinessObject {
+ public class ExampleBusinessObject {
// properties and collaborators
@@ -111,28 +128,28 @@ public class ExampleJob extends QuartzJobObject {
}
}
-
+
<object id="ExampleBusinessObject" type="Examples.BusinessObjects.ExampleBusinessObject, Examples.BusinessObjects"/>Using the
- MethodInvokingJobDetailFactoryObject, you don't
+ MethodInvokingJobDetailFactoryObject, you don't
need to create one-line jobs that just invoke a method, and you only
need to create the actual business object and wire up the detail
object.By default, Quartz Jobs are stateless, resulting in the
possibility of jobs interfering with each other. If you specify two
- triggers for the same JobDetail, it might be
+ triggers for the same JobDetail, it might be
possible that before the first job has finished, the second one will
- start. If JobDetail classes implement the
- Stateful interface, this won't happen.
+ start. If JobDetail classes implement the
+ Stateful interface, this won't happen.
The second job will not start before the first one has finished. To make
jobs resulting from the
- MethodInvokingJobDetailFactoryObject
+ MethodInvokingJobDetailFactoryObject
non-concurrent, set the concurrent flag to
false.
- <object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz">
+ <object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz">
<property name="TargetObject" ref="ExampleBusinessObject" />
<property name="TargetMethod" value="DoIt" />
<property name="Concurrent" value="false" />
@@ -148,27 +165,27 @@ public class ExampleJob extends QuartzJobObject {
-
+ Wiring up jobs using triggers and the
- SchedulerFactoryObject
+ SchedulerFactoryObjectWe've created job details and jobs. We've also reviewed the
convenience class that allows to you invoke a method on a specific
object. Of course, we still need to schedule the jobs themselves. This
is done using triggers and a
- SchedulerFactoryObject. Several triggers are
+ SchedulerFactoryObject. Several triggers are
available within Quartz. Spring offers two subclassed triggers with
- convenient defaults: CronTriggerObject and
- SimpleTriggerObject
+ convenient defaults: CronTriggerObject and
+ SimpleTriggerObjectTriggers need to be scheduled. Spring offers a
- SchedulerFactoryObject that exposes triggers to
- be set as properties. SchedulerFactoryObject
+ SchedulerFactoryObject that exposes triggers to
+ be set as properties. SchedulerFactoryObject
schedules the actual jobs with those triggers.Find below a couple of examples:
- <object id="SimpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz">
+ <object id="SimpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz">
<!-- see the example of method invoking job above -->
<property name="JobDetail" ref="ExampleJob" />
@@ -190,9 +207,9 @@ public class ExampleJob extends QuartzJobObject {
Now we've set up two triggers, one running every 50 seconds with a
starting delay of 10 seconds and one every morning at 6 AM. To finalize
everything, we need to set up the
- SchedulerFactoryObject:
+ SchedulerFactoryObject:
- <object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
+ <object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
<property name="triggers">
<list>
<ref object="CronTrigger" />
@@ -203,7 +220,7 @@ public class ExampleJob extends QuartzJobObject {
More properties are available for the
- SchedulerFactoryObjecct for you to set, such as
+ SchedulerFactoryObjecct for you to set, such as
the calendars used by the job details, properties to customize Quartz
with, etc. Have a look at the SchedulerFactoryObject
diff --git a/doc/reference/src/services.xml b/doc/reference/src/services.xml
index 2e2a6642..a37c4b36 100644
--- a/doc/reference/src/services.xml
+++ b/doc/reference/src/services.xml
@@ -1,8 +1,25 @@
-
+
+.NET Enterprise Services
-
+ IntroductionSpring's .NET Enterprise Services support allows you to export a
@@ -16,14 +33,14 @@
Programatically, as you would with any third party library.
-
+ Serviced ComponentsServices components in .NET are able to use COM+ services such as
declarative and distributed transactions, role based security, object
pooling messaging. To access these services your class needs to derive
from the class
- System.EnterpriseServices.ServicedComponent, adorn
+ System.EnterpriseServices.ServicedComponent, adorn
your class and assemblies with relevant attributes, and configure your
application by registering your serviced components with the COM+ catalog.
The overall landscape of accessing and using COM+ services within .NET
@@ -50,7 +67,7 @@
linkend="entsvc-example">NET Enterprise Services example.
-
+ Server SideOne of the main challenges for the exporting of a serviced component
@@ -64,7 +81,7 @@
- Spring.Enterprise.ServicedComponentExporter
+ Spring.Enterprise.ServicedComponentExporter
is responsible for exporting a single component and making sure that it derives from ServicedComponent class. It also allows you to specify class-level and method-level attributes for the component in order to define things such as transactional behavior, queuing, etc.
@@ -72,7 +89,7 @@
- Spring.Enterprise.EnterpriseServicesExporter
+ Spring.Enterprise.EnterpriseServicesExporter
corresponds to a COM+ application, and it allows you to specify list of components that should be included in the application, as well as the application name and other assembly-level attributes
@@ -81,7 +98,7 @@
Let's say that we have a simple service interface and implementation
class, such as these:
- namespace MyApp.Services
+ namespace MyApp.Services
{
public interface IUserManager
{
@@ -116,7 +133,7 @@
And the corresponding object definition for it in the application
context config file:
- <object id="userManager" type="MyApp.Services.SimpleUserManager">
+ <object id="userManager" type="MyApp.Services.SimpleUserManager">
<property name="UserDao" ref="userDao"/>
</object>
@@ -125,7 +142,7 @@
to export our service using the exporter
ServicedComponentExporter as shown below
- <object id="MyApp.EnterpriseServices.UserManager" type="Spring.Enterprise.ServicedComponentExporter, Spring.Services">
+ <object id="MyApp.EnterpriseServices.UserManager" type="Spring.Enterprise.ServicedComponentExporter, Spring.Services">
<property name="TargetName" value="userManager"/>
<property name="TypeAttributes">
<list>
@@ -152,7 +169,7 @@
The next thing we need to do is configure an exporter for the COM+
application that will host our new component:
- <object id="MyComponentExporter" type="Spring.Enterprise.EnterpriseServicesExporter, Spring.Services">
+ <object id="MyComponentExporter" type="Spring.Enterprise.EnterpriseServicesExporter, Spring.Services">
<property name="ApplicationName" value="My COM+ Application"/>
<property name="Description" value="My enterprise services application."/>
<property name="AccessControl">
@@ -182,18 +199,18 @@
AccessControl and Roles properties.
-
+ Client SideBecause serviced component classes are dynamically generated and
registered, you cannot instantiate them in your code using the new
operator. Instead, you need to use
- Spring.Enterprise.ServicedComponentFactory
+ Spring.Enterprise.ServicedComponentFactory
definition, which also allows you to specify the configuration template
for the component as well as the name of the remote server the component
is running on, if necessary. An example is shown below
- <object id="enterpriseUserManager" type="Spring.Enterprise.ServicedComponentFactory, Spring.Services">
+ <object id="enterpriseUserManager" type="Spring.Enterprise.ServicedComponentFactory, Spring.Services">
<property name="Name" value="MyApp.EnterpriseServices.UserManager"/>
<property name="Template" value="userManager"/>
</object>
diff --git a/doc/reference/src/springair.xml b/doc/reference/src/springair.xml
index 5e456834..6283e97d 100644
--- a/doc/reference/src/springair.xml
+++ b/doc/reference/src/springair.xml
@@ -1,5 +1,22 @@
-
+
+SpringAir - Reference Application
@@ -87,7 +104,7 @@
instantiate the IoC container. The important parts of that configuration
are shown below
- <spring>
+ <spring>
<parsers>
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
</parsers>
@@ -142,7 +159,7 @@
The XML configuration to configure the TripForm form is shown
below
- <object type="TripForm.aspx" parent="standardPage">
+ <object type="TripForm.aspx" parent="standardPage">
<property name="BookingAgent" ref="bookingAgent" />
<property name="AirportDao" ref="airportDao" />
<property name="TripValidator" ref="tripValidator" />
@@ -172,7 +189,7 @@
family of methods that are overridden to support the bi-directional data
binding are listed below.
- protected override void InitializeModel()
+ protected override void InitializeModel()
{
trip = new Trip();
trip.Mode = TripMode.RoundTrip;
@@ -215,7 +232,7 @@
below. Notice how much cleaner and more business focused the code reads
than if you were using standard ASP.NET APIs.
- protected void SearchForFlights(object sender, EventArgs e)
+ protected void SearchForFlights(object sender, EventArgs e)
{
if (Validate(trip, tripValidator))
{
@@ -234,7 +251,7 @@
defined declaratively in the XML configuration file and is shown
below.
- <v:group id="tripValidator">
+ <v:group id="tripValidator">
<v:required id="departureAirportValidator" test="StartingFrom.AirportCode">
<v:message id="error.departureAirport.required" providers="departureAirportErrors, validationSummary"/>
@@ -290,7 +307,7 @@
methods. Spring can expose this object as a web service by declaring the
following XML defined in the top level Config/Services.xml file
- <object id="bookingAgentWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
+ <object id="bookingAgentWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
<property name="TargetName" value="bookingAgent"/>
<property name="Name" value="BookingAgent"/>
<property name="Namespace" value="http://SpringAir/WebServices"/>
diff --git a/doc/reference/styles/html.css b/doc/reference/src/styles/html.css
similarity index 87%
rename from doc/reference/styles/html.css
rename to doc/reference/src/styles/html.css
index c9ccb50b..cfd5d178 100644
--- a/doc/reference/styles/html.css
+++ b/doc/reference/src/styles/html.css
@@ -264,14 +264,3 @@ div.warning * td {
font-size: 100%;
}
-.programlisting .interfacename,
-.programlisting .literal,
-.programlisting .classname {
- font-size: 95%;
-}
-
-/* everything in a is displayed in a nice green, comment-like color */
-.programlisting * .lineannotation,
-.programlisting * .lineannotation * {
- color: green;
-}
diff --git a/doc/reference/src/testing.xml b/doc/reference/src/testing.xml
index 6c8fcd0a..af78d1d0 100644
--- a/doc/reference/src/testing.xml
+++ b/doc/reference/src/testing.xml
@@ -1,8 +1,25 @@
-
+
+Testing
-
+ IntroductionThe Spring team considers developer testing to be an absolutely
@@ -14,7 +31,7 @@
linkend="integration-testing">integration testing.
-
+ Unit testingOne of the main benefits of Dependency Injection is that your code
@@ -39,7 +56,7 @@
unit tests for your IoC-based applications.
-
+ Integration testingHowever, it is also important to be able to perform some integration
@@ -72,7 +89,7 @@
with NUnit then you should add the following to your .config file, (in
the form of MyAssembly.dll.config)
- <runtime>
+ <runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
@@ -91,7 +108,7 @@
The Spring.Testing.NUnit namespace provides
- valuable NUnit TestCase superclasses for
+ valuable NUnit TestCase superclasses for
integration testing using a Spring container. Note that as of NUnit 2.4
these can be rewritten in terms of custom attributes via NUnit's new
extensibility mechanism. This will be an additional option in an upcoming
@@ -124,7 +141,7 @@
-
+ Context management and cachingThe Spring.Testing.NUnit
@@ -140,11 +157,11 @@
could reduce productivity.To address this issue, the
- AbstractDependencyInjectionSpringContextTests has
+ AbstractDependencyInjectionSpringContextTests has
an protected property that subclasses must implement
to provide the location of context definition files:
- protected abstract string[] ConfigLocations { get; }
+ protected abstract string[] ConfigLocations { get; }Implementations of this method must provide an array containing
the IResource locations of XML configuration metadata used to configure
@@ -160,34 +177,34 @@
reloading - for example, by changing an object definition or the state
of an application object - you can call the
SetDirty() method on
- AbstractDependencyInjectionSpringContextTests to
+ AbstractDependencyInjectionSpringContextTests to
cause the test fixture to reload the configurations and rebuild the
application context before executing the next test case.
-
+ Dependency Injection of test fixturesWhen
- AbstractDependencyInjectionSpringContextTests
+ AbstractDependencyInjectionSpringContextTests
(and subclasses) load your application context, they can optionally
configure instances of your test classes by Setter Injection. All you
need to do is to define instance variables and the corresponding
setters.
- AbstractDependencyInjectionSpringContextTests
+ AbstractDependencyInjectionSpringContextTests
will automatically locate the corresponding object in the set of
configuration files specified in the
ConfigLocations property.Consider the scenario where we have a class,
- HibernateTitleDao, that performs data access
- logic for say, the Title domain object. We want
+ HibernateTitleDao, that performs data access
+ logic for say, the Title domain object. We want
to write integration tests that test all of the following areas:The Spring configuration; basically, is everything related to
- the configuration of the HibernateTitleDao
+ the configuration of the HibernateTitleDao
object correct and present?
@@ -197,7 +214,7 @@
- The logic of the HibernateTitleDao;
+ The logic of the HibernateTitleDao;
does the configured instance of this class perform as
anticipated?
@@ -206,8 +223,8 @@
Let's look at the test class itself (we will look at the
configuration immediately afterwards).
- [TestFixture]
-public class HibernateTitleDaoTests : AbstractDependencyInjectionSpringContextTests {
+ [TestFixture]
+public class HibernateTitleDaoTests : AbstractDependencyInjectionSpringContextTests {
// this instance will be (automatically) dependency injected
private HibernateTitleDao titleDao;
@@ -234,10 +251,10 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
('classpath:com/foo/daos.xml') looks like
this:
- <?xml version="1.0" encoding="utf-8" ?>
+ <?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
- <!-- this object will be injected into the HibernateTitleDaoTests class -->
+ <!-- this object will be injected into the HibernateTitleDaoTests class -->
<object id="titleDao" type="Spring.Samples.HibernateTitleDao, Spring.Samples">
<property name="sessionFactory" ref="sessionFactory"/>
</object>
@@ -249,7 +266,7 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
</objects>The
- AbstractDependencyInjectionSpringContextTests
+ AbstractDependencyInjectionSpringContextTests
classes uses autowire
by type. Thus if you have multiple object definitions
of the same type, you cannot rely on this approach for those particular
@@ -260,13 +277,13 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
If you don't want dependency injection applied to your test cases,
simply don't declare any set properties. Alternatively, you can extend
- the AbstractSpringContextTests - the root of the
+ the AbstractSpringContextTests - the root of the
class hierarchy in the Spring.Testing.NUnit
namespace. It merely contains convenience methods to load Spring
contexts, and performs no Dependency Injection of the test
fixture.
-
+ Field level injectionIf, for whatever reason, you don't fancy having setter
@@ -276,8 +293,8 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
Spring XML configuration does not need to change, merely the test
fixture).
- [TestFixture]
-public class HibernateTitleDaoTests : AbstractDependencyInjectionSpringContextTests {
+ [TestFixture]
+public class HibernateTitleDaoTests : AbstractDependencyInjectionSpringContextTests{
public HibernateTitleDaoTests() {
// switch on field level injection
@@ -307,7 +324,7 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
-
+ Transaction managementOne common issue in tests that access a real database is their
@@ -317,23 +334,23 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
data - cannot be done (or verified) outside a transaction.The
- AbstractTransactionalDbProviderSpringContextTests
+ AbstractTransactionalDbProviderSpringContextTests
superclass (and subclasses) exist to meet this need. By default, they
create and roll back a transaction for each test. You simply write code
that can assume the existence of a transaction. If you call
transactionally proxied objects in your tests, they will behave
correctly, according to their transactional semantics.
- AbstractTransactionalSpringContextTests
- depends on a IPlatformTransactionManager object
+ AbstractTransactionalSpringContextTests
+ depends on a IPlatformTransactionManager object
being defined in the application context. The name doesn't matter, due
to the use of autowire by type.Typically you will extend the subclass,
- AbstractTransactionalDbProviderSpringContextTests.
- This also requires that a DbProvider object
+ AbstractTransactionalDbProviderSpringContextTests.
+ This also requires that a DbProvider object
definition - again, with any name - be present in the configurations. It
- creates an AdoTemplate instance variable that is
+ creates an AdoTemplate instance variable that is
useful for convenient querying, and provides handy methods to delete the
contents of selected tables (remember that the transaction will roll
back by default, so this is safe to do).
@@ -341,7 +358,7 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
If you want a transaction to commit - unusual, but occasionally
useful when you want a particular test to populate the database - you
can call the SetComplete() method inherited
- from AbstractTransactionalSpringContextTests.
+ from AbstractTransactionalSpringContextTests.
This will cause the transaction to commit instead of roll back.There is also convenient ability to end a transaction before the
@@ -357,27 +374,27 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
operation of the UI through your NUnit test suite.
-
+ Convenience variablesWhen you extend the
- AbstractTransactionalDbProviderSpringContextTests
+ AbstractTransactionalDbProviderSpringContextTests
class you will have access to the following protected
instance variables:applicationContext (a
- IConfigurableApplicationContext):
+ IConfigurableApplicationContext):
inherited from the
- AbstractDependencyInjectionSpringContextTests
+ AbstractDependencyInjectionSpringContextTests
superclass. Use this to perform explicit object lookup, or test the
state of the context as a whole.adoTemplate: inherited from
- AbstractTransactionalDbProviderSpringContextTests.
+ AbstractTransactionalDbProviderSpringContextTests.
Useful for querying to confirm state. For example, you might query
before and after testing application code that creates an object and
persists it using an ORM tool, to verify that the data appears in
@@ -385,7 +402,7 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
of the same transaction.) You will need to tell your ORM tool to
'flush' its changes for this to work correctly, for example using
the Flush() method on NHibernate's
- ISession interface.
+ ISession interface.
@@ -394,10 +411,10 @@ public class HibernateTitleDaoTests : AbstractDependencyIn
in many tests
-
+
-
+ Further ResourcesThis section contains links to further resources about testing in
diff --git a/doc/reference/src/threading.xml b/doc/reference/src/threading.xml
index 7eb3df3c..a69bd664 100644
--- a/doc/reference/src/threading.xml
+++ b/doc/reference/src/threading.xml
@@ -1,11 +1,28 @@
-
+
+Threading and Concurrency Support
-
+ Introduction
- The purpose of the Spring.Threading namespace
+ The purpose of the Spring.Threading namespace
is to provide a place to keep useful concurrency abstractions that augment
those in the BCL. Since Doug Lea has provided a wealth of mature public
domain concurrency abstractions in his Java based
@@ -26,8 +43,8 @@
to use for storing objects in thread local storage. If you are in web
applications a single Request may be executed on different threads. As
such, the location to store thread local objects is in
- HttpContext.Current. For other environments
- System.Runtime.Remoting.Messaging.CallContext is
+ HttpContext.Current. For other environments
+ System.Runtime.Remoting.Messaging.CallContext is
used. For more background information on the motivation behind these
choices, say as compared to the attribute [ThreadStatic] refer to
"Piers7"'s
- The API is quite simple and shown belowpublic interface IThreadStorage
+ The API is quite simple and shown belowpublic interface IThreadStorage
{
object GetData(string name)
@@ -58,27 +75,27 @@
the method FreeNamedDataSlot.In Spring.Core is the implementation,
- CallContextStorage, that directly uses
- CallContext and also the implementation
- LogicalThreadContext which by default uses
- CallContextStorage but can be configured via the
+ CallContextStorage, that directly uses
+ CallContext and also the implementation
+ LogicalThreadContext which by default uses
+ CallContextStorage but can be configured via the
static method SetStorage(IThreadStorage). The
methods on CallContextStorage and LogicalThreadContext are static.In Spring.Web is the implementation
- HttpContextStorage which uses the
- HttpContext to store thread local data and
- HybridContextStorage that uses
- HttpContext if within a web environment, i.e.
+ HttpContextStorage which uses the
+ HttpContext to store thread local data and
+ HybridContextStorage that uses
+ HttpContext if within a web environment, i.e.
HttpContext.Current != null, and
- CallContext otherwise.
+ CallContext otherwise.
- Spring internally uses LogicalThreadContext
+ Spring internally uses LogicalThreadContext
as this doesn't require a coupling to the System.Web
namespace. In the case of Spring based web applications, Spring's
- WebSupportModule sets the storage strategy of
- LogicalThreadContext to be
- HybridContextStorage.
+ WebSupportModule sets the storage strategy of
+ LogicalThreadContext to be
+ HybridContextStorage.
@@ -102,7 +119,7 @@
interface which has two basic use cases. The first case is to block
indefinitely until a condition is met:
- void ConcurrentRun(ISync lock) {
+ void ConcurrentRun(ISync lock) {
lock.Acquire(); // block until condition met
try {
// ... access shared resources
@@ -116,7 +133,7 @@
The other case is to specify a maximum amount of time to block
before the condition is met:
- void ImpatientConcurrentRun(ISync lock) {
+ void ImpatientConcurrentRun(ISync lock) {
// block for at most 10 milliseconds for condition
if ( lock.Attempt(10) ) {
try {
@@ -143,7 +160,7 @@
exiting from the block.
This should simplify the programming model for code using (!) an
- ISync:
+ ISync:
ISync sync = ...
...
using (new SyncHolder(sync))
@@ -152,7 +169,7 @@ using (new SyncHolder(sync))
// holding the ISync lock
}
There is also the timed version, a little more
- cumbersome as you must deal with timeouts:
+ cumbersome as you must deal with timeouts:
ISync sync = ...
long msecs = 100;
...
@@ -184,7 +201,7 @@ catch (TimeoutException)
unsignalled (Reset) and can only be Set(). A typical
use is to act as a start signal for a group of worker threads.
- class Boss {
+ class Boss {
Latch _startPermit;
void Worker() {
@@ -222,7 +239,7 @@ catch (TimeoutException)
keeps a count of the number available and acts accordingly. A typical
use is to control access to a pool of shared objects.
- class LimitedConcurrentUploader {
+ class LimitedConcurrentUploader {
// ensure we don't exceed maxUpload simultaneous uploads
Semaphore _available;
public LimitedConcurrentUploader(maxUploads) {
diff --git a/doc/reference/src/transaction.xml b/doc/reference/src/transaction.xml
index f1a00490..b9b1d1c9 100644
--- a/doc/reference/src/transaction.xml
+++ b/doc/reference/src/transaction.xml
@@ -1,8 +1,25 @@
-
+
+Transaction management
-
+ IntroductionSpring.NET provides a consistent abstraction for transaction
@@ -23,7 +40,7 @@
Provides a simple API for programmatic transaction management
+ linkend="transaction-programmatic">programmatic transaction management
@@ -59,14 +76,14 @@
- The fourth section, entitled Programmatic
+ The fourth section, entitled Programmatic
transaction management, covers support for programmatic
transaction management.
-
+ MotivationsThe data access technology landscape is a broad one, within the .NET
@@ -177,16 +194,16 @@
lets move on to see the code.
-
+ Key AbstractionsThe key to the Spring transaction management abstraction is the
notion of a transaction strategy. A transaction
strategy is defined by the
- Spring.Transaction.IPlatformTransactionManager
+ Spring.Transaction.IPlatformTransactionManager
interface, shown below:
- public interface IPlatformTransactionManager {
+ public interface IPlatformTransactionManager {
ITransactionStatus GetTransaction( ITransactionDefinition definition );
@@ -198,30 +215,30 @@
This is primarily a 'SPI' (Service Provider Interface), although it
can be used Programatically. Note that in keeping with the Spring
- Framework's philosophy, IPlatformTransactionManager
+ Framework's philosophy, IPlatformTransactionManager
is an interface, and can thus be easily mocked or stubbed as necessary.
- IPlatformTransactionManager implementations
+ IPlatformTransactionManager implementations
are defined like any other object in the IoC container. The following
implementations are provided
- AdoPlatformTransactionManager - local
+ AdoPlatformTransactionManager - local
ADO.NET based transactions
- ServiceDomainPlatformTransactionManager -
+ ServiceDomainPlatformTransactionManager -
distributed transaction manager from Enterprise Services
- TxScopePlatformTransactionManager -
+ TxScopePlatformTransactionManager -
local/distributed transaction manager from System.Transactions.
- HibernatePlatformTransactionManager -
+ HibernatePlatformTransactionManager -
local transaction manager for use with NHibernate or mixed
ADO.NET/NHibernate data access operations.
@@ -242,15 +259,15 @@
section .
The GetTransaction(..) method returns a
- ITransactionStatus object, depending on a
- ITransactionDefinition parameters. The returned
- ITransactionStatus might represent a new or
+ ITransactionStatus object, depending on a
+ ITransactionDefinition parameters. The returned
+ ITransactionStatus might represent a new or
existing transaction (if there was a matching transaction in the current
call stack - with the implication being that a
- ITransactionStatus is associated with a logical
+ ITransactionStatus is associated with a logical
thread of execution.
- The ITransactionDefinition interface
+ The ITransactionDefinition interface
specified
@@ -288,31 +305,31 @@
concepts is essential to using the Spring Framework or indeed any other
transaction management solution.
- The ITransactionStatus interface
+ The ITransactionStatus interface
provides a simple way for transactional code to control transaction
execution and query transaction status.Regardless of whether you opt for declarative or programmatic
transaction management in Spring, defining the correct
- IPlatformTransactionManager implementation
+ IPlatformTransactionManager implementation
is absolutely essential. In good Spring fashion, this important definition
typically is made using via Dependency Injection.
- IPlatformTransactionManager
+ IPlatformTransactionManager
implementations normally require knowledge of the environment in which
they work, ADO.NET, NHibernate, etc. The following example shows how a
standard ADO.NET based
- IPlatformTransactionManager can be
+ IPlatformTransactionManager can be
defined.
- We must define a Spring IDbProvider
+ We must define a Spring IDbProvider
and then use Spring's
- AdoPlatformTransactionManager, giving it a
- reference to the IDbProvider. For more information
- on the IDbProvider abstraction refer to the next
+ AdoPlatformTransactionManager, giving it a
+ reference to the IDbProvider. For more information
+ on the IDbProvider abstraction refer to the next
chapter.
- <objects xmlns='http://www.springframework.net'
+ <objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database">
<db:provider id="DbProvider"
@@ -332,7 +349,7 @@
We can also use a transaction manager based on System.Transactions
just as easily, as shown in the following example
- <object id="TransactionManager"
+ <object id="TransactionManager"
type="Spring.Data.TxScopeTransactionManager, Spring.Data">
</object>
@@ -347,7 +364,7 @@
local to global transactions or vice versa.
-
+ Resource synchronization with transactionsHow does application code participate with the resources (i.e.
@@ -355,7 +372,7 @@
the different transaction managers? There are two approaches - a
high-level and a low-level approach
-
+ High-level approachThe preferred approach is to use Spring's high level persistence
@@ -375,19 +392,19 @@
providing specific implementations of the callback interface.
-
+ Low-level approachA utility class can be used to directly obtain a
connection/transaction pair that is aware of the transactional calling
context and returns a pair suitable for that context. The class
- ConnectionUtils contains the static method
+ ConnectionUtils contains the static method
ConnectionTxPair GetConnectionTxPair(IDbProvider provider)
which serves this purpose.
-
+ Declarative transaction managementMost Spring users choose declarative transaction management. It is
@@ -446,7 +463,7 @@
specify which exceptions should cause automatic roll back. We specify this
declaratively, in configuration, not in code. So, while we can still set
RollbackOnly on the
- ITransactionStatus object to roll the
+ ITransactionStatus object to roll the
current transaction back Programatically, most often we can specify a rule
that MyApplicationException must always result in rollback. This has the
significant advantage that business objects don't need to depend on the
@@ -455,7 +472,7 @@
rollback the transaction programmatically and you are using declarative
transaction management, use the utility method
- TransactionInterceptor.CurrentTransactionStatus.SetRollbackOnly();
+ TransactionInterceptor.CurrentTransactionStatus.SetRollbackOnly();Prior to Spring.NET 1.2 RC1 the API call would be
@@ -463,8 +480,8 @@
true;
-
- Understanding
+
+ Understanding
Spring's declarative transaction implementationThe aim of this section is to dispel the mystique that is
@@ -490,8 +507,8 @@
proxies, and that the transactional advice is driven by metadata
(currently XML- or attribute-based). The combination of a proxy with
transactional metadata yields an AOP proxy that uses a
- TransactionInterceptor in conjunction with an
- appropriate IPlatformTransactionManager
+ TransactionInterceptor in conjunction with an
+ appropriate IPlatformTransactionManager
implementation to drive transactions around method invocations.
@@ -517,7 +534,7 @@
- ProxyFactoryObject. The common
+ ProxyFactoryObject. The common
properties to set are the reference to the object to proxy (the
target object) and a reference to the transaction advice. See for more details.
@@ -531,14 +548,14 @@
- ObjectNameAutoProxyCreator which
+ ObjectNameAutoProxyCreator which
specifies a collection of object names based on wildcard
matching of object names. See
- DefaultAdvisorAutoProxyCreator
+ DefaultAdvisorAutoProxyCreator
which specifies one or more "advisors" i.e an object
representing an aspect, including both an advice and a pointcut
targeting it to specific joinpoints. See There is also a convenience subclass of
- ProxyFactoryObject, namely
- TransactionProxyFactoryObject, that sets some
+ ProxyFactoryObject, namely
+ TransactionProxyFactoryObject, that sets some
common default values for the specific case of applying transactional
advice.
- The DefaultAdvisorAutoProxyCreator is very
+ The DefaultAdvisorAutoProxyCreator is very
powerful and is the means by which Spring can be configured to use
attributes to identify the pointcuts where transaction advice should be
applied. The advisor that performs that task is
@@ -587,19 +604,19 @@
advice.
-
+ A First ExampleConsider the following interface. The intent is to convey the
concepts to you so you can concentrate on the transaction usage and not
have to worry about domain specific details. The
- ITestObjectManager is a poor-mans
+ ITestObjectManager is a poor-mans
business service layer - the implementation of which will make two DAO
calls. Clearly this example is overly simplistic from the service layer
perspective as there isn't any business logic at all!. The 'service'
interface is shown below.
- public interface ITestObjectManager
+ public interface ITestObjectManager
{
void SaveTwoTestObjects(TestObject to1, TestObject to2);
@@ -607,9 +624,9 @@
}The implementation of
- ITestObjectManager is shown below
+ ITestObjectManager is shown below
- public class TestObjectManager : ITestObjectManager
+ public class TestObjectManager : ITestObjectManager
{
// Fields/Properties ommited
@@ -642,7 +659,7 @@
update delete and find method for the 'domain' object TestObject.
TestObject in turn has simple properties like name and age.
- public interface ITestObjectDao
+ public interface ITestObjectDao
{
void Create(string name, int age);
void Update(TestObject to);
@@ -652,12 +669,12 @@
}The Create and Delete method implementation is shown below. Note
- that this uses the AdoTemplate class discussed in
+ that this uses the AdoTemplate class discussed in
the following chapter. Refer to for
information on the interaction between Spring's high level persistence
integration APIs and transaction management features.
- public class TestObjectDao : AdoDaoSupport, ITestObjectDao
+ public class TestObjectDao : AdoDaoSupport, ITestObjectDao
{
public void Create(string name, int age)
{
@@ -674,19 +691,19 @@
}
}
- The TestObjectManager is configured with
+ The TestObjectManager is configured with
the DAO objects by standard dependency injection techniques. The client
code, which in this case directly asks the Spring IoC container for an
- instance of ITestObjectManager, will
+ instance of ITestObjectManager, will
receive a transaction proxy with transaction options based on the
attribute metadata. Note that typically the
- ITestObjectManager would be set on yet
+ ITestObjectManager would be set on yet
another higher level object via dependency injection, for example a web
service.The client calling code is shown below
- IApplicationContext ctx =
+ IApplicationContext ctx =
new XmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/autoDeclarativeServices.xml");
ITestObjectManager mgr = ctx["testObjectManager"] as ITestObjectManager;
@@ -708,7 +725,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
The configuration of the object definitions of the DAO and manager
classes is shown below.
- <objects xmlns='http://www.springframework.net'
+ <objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database">
<db:provider id="DbProvider"
@@ -745,7 +762,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
create a transactional proxy for the manager class is shown
below.
- <!-- The rest of the config file is common no matter how many objects you add -->
+ <!-- The rest of the config file is common no matter how many objects you add -->
<!-- that you would like to have declarative tx management applied to -->
<object id="autoProxyCreator"
@@ -783,67 +800,67 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
references it can be included in its own file and then imported via the
<import> element. In examples and test code this XML configuration
fragment is named autoDeclarativeServices.xml See for more information.
+ linkend="objects-factory-xml-import" /> for more information.
The classes and their roles in this configuration fragment are
listed below
- TransactionInterceptor is the AOP
+ TransactionInterceptor is the AOP
advice responsible for performing transaction management
functionality.
- TransactionAttributeSourceAdvisor is an
+ TransactionAttributeSourceAdvisor is an
AOP Advisor that holds the TransactionInterceptor, which is the
advice, and a pointcut (where to apply the advice), in the form of a
TransactionAttributeSource.
- AttributesTransactionAttributeSource is
+ AttributesTransactionAttributeSource is
an implementation of the
- ITransactionAttributeSource interface that
+ ITransactionAttributeSource interface that
defines where to get the transaction metadata defining the
transaction semantics (isolation level, propagation behavior, etc)
that should be applied to specific methods of specific classes. The
transaction metadata is specified via implementations of the
- ITransactionAttributeSource interface. This
+ ITransactionAttributeSource interface. This
example shows the use of the implementation
- Spring.Transaction.Interceptor.AttributesTransactionAttributeSource
+ Spring.Transaction.Interceptor.AttributesTransactionAttributeSource
to obtain that information from standard .NET attributes. By the
very nature of using standard .NET attributes, the attribute serves
double duty in identifying the methods where the transaction
semantics apply. Alternative implementations of
- ITransactionAttributeSource available are
- MatchAlwaysTransactionAttributeSource,
- NameMatchTransactionAttributeSource, or
- MethodMapTransactionAttributeSource.
+ ITransactionAttributeSource available are
+ MatchAlwaysTransactionAttributeSource,
+ NameMatchTransactionAttributeSource, or
+ MethodMapTransactionAttributeSource.
- MatchAlwaysTransactionAttributeSource
+ MatchAlwaysTransactionAttributeSource
is configured with a ITransactionAttribute instance that is
applied to all methods. The shorthand string representation,
i.e. PROPAGATION_REQUIRED can be used
- AttributesTransactionAttributeSource
+ AttributesTransactionAttributeSource
: Use a standard. .NET attributes to specify the transactional
information. See TransactionAttribute class
for more information.
- NameMatchTransactionAttributeSource
+ NameMatchTransactionAttributeSource
allows ITransactionAttributes to be matched by method name. The
NameMap IDictionary property is used to specify the mapping. For
example
- <object name="nameMatchTxAttributeSource" type="Spring.Transaction.Interceptor.NameMatchTransactionAttributeSource, Spring.Data"
+ <object name="nameMatchTxAttributeSource" type="Spring.Transaction.Interceptor.NameMatchTransactionAttributeSource, Spring.Data"
<property name="NameMap">
<dictionary>
<entry key="Execute" value="PROPAGATION_REQUIRES_NEW, -ApplicationException"/>
@@ -860,7 +877,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
- MethodMapTransactionAttributeSource
+ MethodMapTransactionAttributeSource
: Similar to NameMatchTransactionAttributeSource but specifies
that only fully qualified method names (i.e. type.method,
assembly) and wildcards can be used at the start or end of the
@@ -870,7 +887,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
- DefaultAdvisorAutoProxyCreator: looks
+ DefaultAdvisorAutoProxyCreator: looks
for Advisors in the context, and automatically creates proxy objects
which are the transactional wrappers
@@ -881,7 +898,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
attributes.
-
+ Declarative transactions using the transaction namespaceSpring provides a custom XML schema to simplify the configuration
@@ -890,7 +907,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
custom namespace parser for the transaction namespace. This can be done
in the application configuration file as shown below
- <?xml version="1.0" encoding="utf-8" ?>
+ <?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
@@ -921,7 +938,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
you have not installed Spring's schema into the proper VS.NET 2005
location. See the chapter on VS.NET integration for more details.
- <objects xmlns="http://www.springframework.net"
+ <objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.net/tx"
xmlns:db="http://www.springframework.net/database"
@@ -955,7 +972,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
</object>
- <tx:attribute-driven transaction-manager="transactionManager"/>
+ <tx:attribute-driven transaction-manager="transactionManager"/>
</objects>
@@ -964,10 +981,10 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
'transaction-manager' attribute in the
<tx:attribute-driven/> tag if the object
name of the
- IPlatformTransactionManager that you
+ IPlatformTransactionManager that you
want to wire in has the name
'transactionManager'. If the
- PlatformTransactionManager object
+ PlatformTransactionManager object
that you want to dependency inject has any other name, then you have
to be explicit and use the 'transaction-manager'
attribute as in the example above.
@@ -1015,7 +1032,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
Controls what type of transactional proxies are
created for classes annotated with the
- [Transaction] attribute. If
+ [Transaction] attribute. If
"proxy-target-type" attribute is set to
"true", then class-based proxies will be
created (proxy inherits from target class, however calls are
@@ -1054,7 +1071,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
The "proxy-target-type" attribute on the
<tx:attribute-driven/> element controls what
type of transactional proxies are created for classes annotated with
- the Transaction attribute. If
+ the Transaction attribute. If
"proxy-target-type" attribute is set to
"true", then inheritance-based proxies will be
created. If "proxy-target-type" is
@@ -1074,7 +1091,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
<tx:advice> instead of <tx:attribute-driven/> in the example
would look like the following
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
+ <tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="Save*"/>
<tx:method name="Delete*"/>
@@ -1089,7 +1106,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
Here is an example using other elements of the <tx:method/>
definition
- <!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> object below) -->
+ <!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> object below) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
@@ -1113,7 +1130,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
tie together a pointcut and the above defined advice as shown
below.
- <object id="serviceOperation" type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop">
+ <object id="serviceOperation" type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop">
<property name="pattern" value="Spring.TxQuickStart.Services.*"/>
</object>
@@ -1292,7 +1309,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");