the spring.net framework - documentation & help · introduction to adotemplate spring.net is an...

918
The Spring.NET Framework

Upload: others

Post on 22-May-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheSpring.NETFramework

Page 2: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ReferenceDocumentation

Authors

Mark Pollack , Rick Evans , Aleksandar Seovic , Bruno Baia ,FedericoSpinazzi ,RobHarrop ,GriffinCaprio ,RubenBartelink ,ChoyRim,TheSpringJavaTeam

Version1.2.0Copiesofthisdocumentmaybemadeforyourownuseandfordistributiontoothers,providedthatyoudonot charge any fee for such copies and further provided that each copy contains this Copyright Notice,whetherdistributedinprintorelectronically.

LastUpdatedNovermber10,2008(Latestdocumentation)

Page 3: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

1.Preface

Page 4: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

2.Introduction2.1.Overview2.2.Background2.3.Modules2.4.UsageScenarios2.5.Quickstartapplications2.6.LicenseInformation2.7.Support

Page 5: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

3.Backgroundinformation3.1.InversionofControl

Page 6: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

4.Migratingfrom1.1M24.1.Introduction4.2.ImportantChanges

4.2.1.Namespaces4.2.2.Core4.2.3.Web4.2.4.Data

I.CoreTechnologies

Page 7: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.TheIoCcontainer5.1.Introduction5.2.Basics-containersandobjects

5.2.1.Thecontainer5.2.1.1.Configurationmetadata

5.2.2.Instantiatingacontainer5.2.2.1.ComposingXML-basedconfigurationmetadata

5.2.3.TheObjects5.2.3.1.Namingobjects

5.2.4.Objectcreation5.2.4.1.Objectcreationviaconstructorinvocation5.2.4.2.Objectcreationviaastaticfactorymethod5.2.4.3.Objectcreationviaaninstancefactorymethod

5.2.5.Objectcreationofgenerictypes5.2.5.1.Objectcreationofgenerictypesviaconstructorinvocation5.2.5.2.Objectcreationofgenerictypesviastaticfactorymethod5.2.5.3.Objectcreationofgenerictypesviainstancefactorymethod

5.2.6.Usingthecontainer5.3.Dependencies

5.3.1.Injectingdependencies5.3.1.1.ConstructorInjection5.3.1.2.SetterInjection5.3.1.3.Someexamples

5.3.2.Dependenciesandconfigurationindetail5.3.2.1.Straightvalues(primitives,strings,etc.)5.3.2.2.Referringtocollaboratingobjects5.3.2.3.Inlineobjects5.3.2.4.Settingcollectionvalues5.3.2.5.Settinggenericcollectionvalues5.3.2.6.Settingnullvalues5.3.2.7.Settingindexerproperties5.3.2.8.Valueandrefshortcutforms5.3.2.9.CompoundpropertynamesandSpringexpressionreferences

5.3.3.DeclarativeEventListenerRegistration5.3.3.1.Declarativeeventhandlers5.3.3.2.Configuringamethodtobeinvokedwhenaneventisfired5.3.3.3.Registeringacollectionofhandlermethodsbasedona regularexpression5.3.3.4. Registering a handler method against an event name thatcontainsaregularexpression

5.3.4.Usingdepends-on5.3.5.Lazily-instantiatedobjects5.3.6.Autowiringcollaborators

Page 8: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.3.7.Checkingfordependencies5.3.8.MethodInjection

5.3.8.1.LookupMethodInjection5.3.8.2.Arbitrarymethodreplacement

5.3.9.Settingareferenceusingthemembersofotherobjectsandclasses.5.3.9.1.Settingareferencetothevalueofproperty.5.3.9.2.Settingareferencetothevalueoffield.5.3.9.3.Settingapropertyorconstructorargumenttothereturnvalueofamethodinvocation.

5.3.10.ProvidedIFactoryObjectimplementations5.3.10.1.Commonlogging

5.4.ObjectScopes5.4.1.Thesingletonscope5.4.2.Theprototypescope5.4.3.Singletonobjecgtswithprototype-objectdependencies5.4.4.Theotherscopes

5.5.Typeconversion5.5.1.TypeConversionforEnumerations5.5.2.Built-inTypeConverters5.5.3.CustomTypeConversion

5.5.3.1.UsingCustomConverterConfigurer5.6.Customizingthenatureofanobject

5.6.1.Lifecycleinterfaces5.6.1.1.IInitializingObject/init-method5.6.1.2.IDisposable/destroy-method

5.6.2.Knowingwhoyouare5.6.2.1.IObjectFactoryAware5.6.2.2.IObjectNameAware

5.7.Objectdefinitioninheritance5.8.Interactingwiththecontainer

5.8.1.ObtaininganIFactoryObject,notitsproduct5.9.Containerextensionpoints

5.9.1.CustomizingobjectswithIObjectPostProcessors5.9.1.1.Example:HelloWorld,IObjectPostProcessor-style5.9.1.2.Example:theRequiredAttributeObjectPostProcessor

5.9.2.CustomizingconfigurationmetadatawithObjectFactoryPostProcessors5.9.2.1.Example:ThePropertyPlaceholderConfigurer5.9.2.2.Example:ThePropertyOverrideConfigurer5.9.2.3.IVariableSource

5.9.3.CustomizinginstantiationlogicusingIFactoryObjects5.9.3.1.IConfigurableFactoryObject

5.10.TheIApplicationContext5.10.1.IObjectFactoryorIApplicationContext?

Page 9: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.11.ConfigurationofIApplicationContext5.11.1.Registeringcustomparsers5.11.2.Registeringcustomresourcehandlers5.11.3.RegisteringTypeAliases5.11.4.RegisteringTypeConverters

5.12.AddedfunctionalityoftheIApplicationContext5.12.1.ContextHierarchies5.12.2.UsingIMessageSource5.12.3.UsingresourceswithinSpring.NET5.12.4.Looselycoupledevents5.12.5.EventnotificationfromIApplicationContext

5.13.CustomizedbehaviorintheApplicationContext5.13.1.TheIApplicationContextAwaremarkerinterface5.13.2.TheIObjectPostProcessor5.13.3.TheIObjectFactoryPostProcessor5.13.4.ThePropertyPlaceholderConfigurer

5.14.ConfigurationofApplicationContextwithoutusingXML5.15.ServiceLocatoraccess5.16.Stereotypeattributes

Page 10: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

6.TheIObjectWrapperandTypeconversion6.1.Introduction6.2.ManipulatingobjectsusingtheIObjectWrapper

6.2.1.Settingandgettingbasicandnestedproperties6.2.2.Otherfeaturesworthmentioning

6.3.Typeconversion6.3.1.TypeConversionforEnumerations

6.4.Built-inTypeConverters6.4.1.Customtypeconverters

Page 11: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

7.Resources7.1.Introduction7.2.TheIResourceinterface7.3.Built-inIResourceimplementations

7.3.1.RegisteringcustomIResourceimplementations7.4.TheIResourceLoader7.5.TheIResourceLoaderAwareinterface7.6.ApplicationcontextsandIResourcepaths

Page 12: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

8.ThreadingandConcurrencySupport8.1.Introduction8.2.ThreadLocalStorage8.3.SynchronizationPrimitives

8.3.1.ISync8.3.2.SyncHolder8.3.3.Latch8.3.4.Semaphore

Page 13: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

9.ObjectPooling9.1.Introduction9.2.InterfacesandImplementations

Page 14: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

10.Spring.NETmiscellanea10.1.Introduction10.2.PathMatcher

10.2.1.Generalrules10.2.2.Matchingfilenames10.2.3.Matchingsubdirectories10.2.4.Casedoesmatter,slashesdon't

Page 15: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.ExpressionEvaluation11.1.Introduction11.2.EvaluatingExpressions11.3.LanguageReference

11.3.1.Literalexpressions11.3.2.Properties,Arrays,Lists,Dictionaries,Indexers

11.3.2.1.DefiningArrays,ListsandDictionariesInline11.3.3.Methods11.3.4.Operators

11.3.4.1.Relationaloperators11.3.4.2.Logicaloperators11.3.4.3.Mathematicaloperators

11.3.5.Assignment11.3.6.Expressionlists11.3.7.Types11.3.8.TypeRegistration11.3.9.Constructors11.3.10.Variables

11.3.10.1.The'#this'and'#root'variables11.3.11.TernaryOperator(If-Then-Else)11.3.12.ListProjectionandSelection11.3.13.CollectionProcessorsandAggregators

11.3.13.1.CountAggregator11.3.13.2.SumAggregator11.3.13.3.AverageAggregator11.3.13.4.MinimumAggregator11.3.13.5.MaximumAggregator11.3.13.6.Non-nullProcessor11.3.13.7.DistinctProcessor11.3.13.8.SortProcessor11.3.13.9.TypeConversionProcessor11.3.13.10.ReverseProcessor11.3.13.11.OrderByProcessor11.3.13.12.UserDefinedCollectionProcessor

11.3.14.SpringObjectReferences11.3.15.LambdaExpressions11.3.16.DelegateExpressions11.3.17.NullContext

11.4.Classesusedintheexamples

Page 16: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.ValidationFramework12.1.Introduction12.2.ExampleUsage12.3.ValidatorGroups12.4.Validators

12.4.1.ConditionValidator12.4.2.RequiredValidator12.4.3.RegularExpressionValidator12.4.4.GenericValidator12.4.5.ConditionalValidatorExecution

12.5.ValidatorActions12.5.1.ErrorMessageAction12.5.2.GenericActions

12.6.ValidatorReferences12.7.Progammaticusage12.8.UsagetipswithinASP.NET

12.8.1.RenderingValidationErrors12.8.1.1.ConfiguringwhichErrorRenderertouse.

Page 17: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.AspectOrientedProgrammingwithSpring.NET13.1.Introduction

13.1.1.AOPconcepts13.1.2.Spring.NETAOPcapabilities13.1.3.AOPProxiesinSpring.NET

13.2.PointcutAPIinSpring.NET13.2.1.Concepts13.2.2.Operationsonpointcuts13.2.3.Conveniencepointcutimplementations

13.2.3.1.Staticpointcuts13.2.3.2.DynamicPointcuts

13.2.4.Custompointcuts13.3.AdviceAPIinSpring.NET

13.3.1.AdviceLifecycle13.3.2.Advicetypes

13.3.2.1.InterceptionAroundAdvice13.3.2.2.Beforeadvice13.3.2.3.Throwsadvice13.3.2.4.AfterReturningadvice13.3.2.5.AdviceOrdering13.3.2.6.Introductionadvice

13.4.AdvisorAPIinSpring.NET13.5.UsingtheProxyFactoryObjecttocreateAOPproxies

13.5.1.Basics13.5.2.ProxyFactoryObjectProperties13.5.3.ProxyingInterfaces13.5.4.ProxyingClasses13.5.5.Conciseproxydefinitions

13.6.Proxyingmechanisms13.6.1.InheritanceBasedAopConfigurer

13.7.CreatingAOPProxiesProgramaticallywiththeProxyFactory13.8.ManipulatingAdvisedObjects13.9.Usingthe"autoproxy"facility

13.9.1.Autoproxyobjectdefinitions13.9.1.1.ObjectNameAutoProxyCreator13.9.1.2.DefaultAdvisorAutoProxyCreator13.9.1.3.PointcutFilteringAutoProxyCreator13.9.1.4.TypeNameAutoProxyCreator13.9.1.5.AttributeAutoProxyCreator13.9.1.6.AbstractFilteringAutoProxyCreator13.9.1.7.AbstractAutoProxyCreator

13.9.2.Usingattribute-drivenauto-proxying

Page 18: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.10.UsingAOPNamespace13.11.UsingTargetSources

13.11.1.Hotswappabletargetsources13.11.2.Poolingtargetsources13.11.3.Prototypetargetsources13.11.4.ThreadLocaltargetsources

13.12.DefiningnewAdvicetypes13.13.Furtherreadingandresources

Page 19: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

14.AspectLibrary14.1.Introduction14.2.Caching14.3.ExceptionHandling

14.3.1.LanguageReference14.4.Logging14.5.Retry

14.5.1.LanguageReference14.6.Transactions14.7.ParameterValidation

Page 20: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

15.CommonLogging15.1.Introduction

Page 21: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

16.Testing16.1.Introduction16.2.Unittesting16.3.Integrationtesting

16.3.1.Contextmanagementandcaching16.3.2.DependencyInjectionoftestfixtures

16.3.2.1.Fieldlevelinjection16.3.3.Transactionmanagement16.3.4.Conveniencevariables16.3.5.

16.4.FurtherResourcesII.MiddleTierDataAccess

Page 22: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.Transactionmanagement17.1.Introduction17.2.Motivations17.3.KeyAbstractions17.4.Resourcesynchronizationwithtransactions

17.4.1.High-levelapproach17.4.2.Low-levelapproach

17.5.Declarativetransactionmanagement17.5.1.UnderstandingSpring'sdeclarativetransactionimplementation17.5.2.AFirstExample17.5.3.Declarativetransactionsusingthetransactionnamespace17.5.4.Transactionattributesettings17.5.5.DeclarativeTransactionsusingAutoProxy

17.5.5.1. Creating transactional proxies withObjectNameAutoProxyCreator17.5.5.2. Creating transactional proxies withDefaultAdvisorAutoProxyCreator

17.5.6.DeclarativeTransactionsusingTransactionProxyFactoryObject17.5.7.Conciseproxydefinitions17.5.8.DeclarativeTransactionsusingProxyFactoryObject

17.6.Programmatictransactionmanagement17.6.1.UsingtheTransactionTemplate

17.6.1.1.Specifyingtransactionsettings17.6.2.UsingthePlatformTransactionManager

17.7.Choosingbetweenprogrammaticanddeclarativetransactionmanagement17.8.Transactionlifecycleandstatusinformation

Page 23: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

18.DAOsupport18.1.Introduction18.2.Consistentexceptionhierarchy18.3.ConsistentabstractclassesforDAOsupport

Page 24: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

19.DbProvider19.1.Introduction19.2.IDbProviderandDbProviderFactory19.3.XMLbasedconfiguration19.4.ConnectionStringmanagement19.5.AdditionalIDbProviderimplementations

19.5.1.UserCredentialsDbProvider19.5.2.MultiDelegatingDbProvider

Page 25: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.DataaccessusingADO.NET20.1.IntroductionMotivations20.3.ProviderAbstraction

20.3.1.CreatinganinstanceofIDbProvider20.4.Namespaces20.5.ApproachestoDataAccess20.6.IntroductiontoAdoTemplate

20.6.1.ExecuteCallback20.6.2.ExecuteCallbackin.NET2.020.6.3.ExecuteCallbackin.NET1.120.6.4.QuickGuidetoAdoTemplateMethods20.6.5.QuickGuidetoAdoTemplateProperties

20.7.TransactionManagement20.8.ExceptionTranslation20.9.ParameterManagement

20.9.1.IDbParametersBuilder20.9.2.IDbParameters

20.10.CustomIDataReaderimplementations20.11.Basicdataaccessoperations

20.11.1.ExecuteNonQuery20.11.2.ExecuteScalar

20.12.QueriesandLightweightObjectMapping20.12.1.ResultSetExtractor20.12.2.RowCallback20.12.3.RowMapper20.12.4.Queryforasingleobject20.12.5.QueryusingaCommandCreator

20.13.DataTableandDataSet20.13.1.DataTables20.13.2.DataSets

20.14.TableAdaptersandparticipationintransactionalcontext20.15.DatabaseoperationsasObjects

20.15.1.AdoQuery20.15.2.MappingAdoQuery20.15.3.AdoNonQuery20.15.4.StoredProcedure

Page 26: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

21.ObjectRelationalMapping(ORM)dataaccess21.1.Introduction21.2.NHibernate

21.2.1.Resourcemanagement21.2.2.TransactionManagement21.2.3.SessionFactorysetupinaSpringcontainer21.2.4.TheHibernateTemplate21.2.5.ImplementingSpring-basedDAOswithoutcallbacks21.2.6.ImplementingDAOsbasedonplainHibernate1.2/2.0API

21.2.6.1.ExceptionTranslation21.2.7.Programmatictransactiondemarcation21.2.8.Declarativetransactiondemarcation21.2.9.Transactionmanagementstrategies21.2.10.WebSessionManagement21.2.11.SessionScope

III.TheWeb

Page 27: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.Spring.NETWebFramework22.1.Introduction22.2.Background22.3.Automaticcontextloadingandhierarchicalcontexts

22.3.1.Configuration22.3.1.1.ConfigurationforIIS7

22.3.2.ContextHierarchy22.4.DependencyInjectionforASP.NETPages

22.4.1.InjectingDependenciesintoControls22.4.2.InjectingdependenciesintocustomHTTPmodules22.4.3.InjectingdependenciesintoHTTPhandlersandhandlerfactories22.4.4.Injectingdependenciesintocustomproviders22.4.5.Customizingcontroldependencyinjection

22.5.Webobjectscopes22.6.MasterPagesinASP.NET1.1

22.6.1.Linkingchildpagestotheirmaster22.7.BidirectionalDataBindingandModelManagement

22.7.1.DataBindingUndertheHood22.7.1.1.BindingDirection22.7.1.2.Formatters22.7.1.3.TypeConversion22.7.1.4.DataBindingEvents22.7.1.5.RenderingBindingErrors22.7.1.6.HttpRequestListBindingContainer

22.7.2.UsingDataBindingPanel22.7.3.CustomizingModelPersistence

22.8.LocalizationandMessageSources22.8.1.AutomaticLocalizationUsingLocalizers("Push"Localization)22.8.2.GlobalMessageSources22.8.3.WorkingwithLocalizers22.8.4.ApplyingResourcesManually("Pull"Localization)22.8.5.LocalizingImageswithinaWebApplication22.8.6.UserCultureManagement

22.8.6.1.DefaultWebCultureResolver22.8.6.2.RequestCultureResolver22.8.6.3.SessionCultureResolver22.8.6.4.CookieCultureResolver

22.8.7.ChangingCultures22.9.ResultMapping

22.9.1.Registeringuserdefinedtransfermodes22.10.Client-SideScripting

22.10.1.RegisteringScriptswithintheheadHTMLsection

Page 28: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.10.2.AddingCSSDefinitionstotheheadSection22.10.3.Well-KnownDirectories

22.11.SpringUserControls22.11.1.ValidationControls22.11.2.DatabindingControls22.11.3.CalendarControl22.11.4.PanelControl

Page 29: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

23.ASP.NETAJAX23.1.Introduction23.2.WebServices

23.2.1.ExposingWebServices23.2.2.CallingWebServicesbyusingJavaScript

IV.Services

Page 30: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

24.IntroductiontoSpringServices24.1.Introduction

Page 31: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25..NETRemoting25.1.Introduction25.2.PublishingSAOsontheServer

25.2.1.SAOSingleton25.2.2.SAOSingleCall25.2.3.IISApplicationConfiguration

25.3.AccessingaSAOontheClient25.4.CAObestpractices25.5.RegisteringaCAOobjectontheServer

25.5.1.ApplyingAOPadvicetoexportedCAOobjects25.6.AccessingaCAOontheClient

25.6.1.ApplyingAOPadvicetoclientsideCAOobjects.25.7.XMLSchemaforconfiguration25.8.AdditionalResources

Page 32: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

26..NETEnterpriseServices26.1.Introduction26.2.ServicedComponents26.3.ServerSide26.4.ClientSide

Page 33: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

27.WebServices27.1.Introduction27.2.Server-side

27.2.1.Removingtheneedfor.asmxfiles27.2.2.Injectingdependenciesintowebservices27.2.3.ExposingPONOsasWebServices27.2.4.ExportinganAOPProxyasaWebService

27.3.Client-side27.3.1.UsingVS.NETgeneratedproxy27.3.2.Generatingproxiesdynamically27.3.3.Configuringtheproxyinstance

Page 34: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

28.WindowsCommunicationFoundation(WCF)28.1.Introduction28.2.ConfiguringWCFservicesviaDependencyInjection

28.2.1.DependencyInjection28.3.ApplyAOPadvicetoWCFservices28.4.Creatingclientsideproxiesdeclaratively28.5.ExportingPONOsasWCFServices

V.Integration

Page 35: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

29.MessageOrientedMiddleware-ApacheActiveMQ29.1.Introduction

29.1.1.SeparationofConcerns29.1.2.Interoperabilityandproviderportability29.1.3.TheroleofMessagingAPIina'WCFworld'

29.2.UsingSpringMessaging29.2.1.MessagingTemplateoverview29.2.2.Connections29.2.3.CachingMessagingResources

29.2.3.1.SingleConnectionFactory29.2.3.2.CachingConnectionFactory

29.2.4.DestinationManagement29.2.5.MessageListenerContainers29.2.6.TransactionManagement

29.3.SendingaMessage29.3.1.UsingMessageConverters

29.4.SessionandProducerCallback29.5.Receivingamessage

29.5.1.SynchronousReception29.5.2.AsynchronousReception29.5.3.TheISessionAwareMessageListenerinterface29.5.4.MessageListenerAdapater29.5.5.Processingmessageswithinamessagingtransaction29.5.6.MessagingNamespacesupport

Page 36: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

30.MessageOrientedMiddleware-MSMQ30.1.Introduction30.2.Aquicktourfortheimpatient30.3.UsingSpringMSMQ

30.3.1.MessageQueueTemplate30.3.2.MessageQueueFactoryObject30.3.3.MessageQueueandIMessageConverterresourcemanagement30.3.4.MessageListenerContainers

30.3.4.1.NonTransactionalMessageListenerContainer30.3.4.2.TransactionalMessageListenerContainer30.3.4.3.DistributedTxMessageListenerContainer

30.4.MessageConverters30.4.1.UsingMessageConverters

30.5.Interfacebasedmessageprocessing30.5.1.

30.5.1.1.MessageListenerAdapater30.6.ComparisonwithusingWCF

Page 37: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

31.SchedulingandThreadPooling31.1.Introduction31.2.UsingtheQuartz.NETScheduler

31.2.1.UsingtheJobDetailObject31.2.2.UsingtheMethodInvokingJobDetailFactoryObject31.2.3.WiringupjobsusingtriggersandtheSchedulerFactoryObject

VI.VS.NETIntegration

Page 38: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

32.VisualStudio.NETIntegration32.1.XMLEditingandValidation32.2.VersionsofXMLSchema32.3.IntegratedAPIhelp

VII.Quickstartapplications

Page 39: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

33.IoCQuickstarts33.1.Introduction33.2.MovieFinder

33.2.1.GettingStarted-MovieFinder33.2.2.FirstObjectDefinition33.2.3.SetterInjection33.2.4.ConstructorInjection33.2.5.Summary33.2.6.Logging

33.3.ApplicationContextandIMessageSource33.3.1.Introduction

33.4.ApplicationContextandIEventRegistry33.4.1.Introduction

33.5.Poolingexample33.5.1.ImplementingSpring.Pool.IPoolableObjectFactory33.5.2.Beingsmartusingpooledobjects33.5.3.Usingtheexecutortodoaparallelgrep

33.6.AOP

Page 40: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

34.AOPGuide34.1.Introduction34.2.Thebasics

34.2.1.Applyingadvice34.2.2.UsingPointcuts-thebasics

34.3.Goingdeeper34.3.1.OthertypesofAdvice

34.3.1.1.Beforeadvice34.3.1.2.Afteradvice34.3.1.3.Throwsadvice34.3.1.4.Introductions(mixins)34.3.1.5.Layeringadvice34.3.1.6.Configuringadvice

34.3.2.UsingAttributestodefinePointcuts34.4.TheSpring.NETAOPCookbook

34.4.1.Caching34.4.2.PerformanceMonitoring34.4.3.RetryRules

34.5.Spring.NETAOPBestPractices

Page 41: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.PortableServiceAbstractionQuickStart35.1.Introduction35.2..NETRemotingExample35.3.Implementation35.4.Runningtheapplication35.5.RemotingSchema35.6..NETEnterpriseServicesExample35.7.WebServicesExample35.8.AdditionalResources

Page 42: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

36.WebQuickstarts36.1.Introduction

Page 43: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

37.SpringAir-ReferenceApplication37.1.Introduction37.2.GettingStarted37.3.Containerconfiguration37.4.Bi-directionaldatabinding37.5.DeclarativeValidation37.6.Internationalization37.7.WebServices

Page 44: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

38.DataAccessQuickStart38.1.Introduction

38.1.1.Databaseconfiguration38.1.1.1.AdoTemplateConfiguration

38.1.2.CommandCallback

Page 45: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

39.TransactionsQuickStart39.1.Introduction39.2.ApplicationOverview

39.2.1.Interfaces39.3.Implementation39.4.Configuration

39.4.1.RollbackRules39.5.AddingadditionalAspects

Page 46: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

40.NHibernateQuickStart40.1.Introduction

Page 47: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

41.QuartzQuickStart41.1.Introduction41.2.ApplicationOverview41.3.Standardjobscheduling41.4.Schedulingarbitrarymethodsasjobs

Page 48: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.NMSQuickStart42.1.Introduction42.2.MessageDestinations42.3.Gateways42.4.MessageData42.5.MessageHandlers42.6.MessageConverters42.7.MessagingInfrastructure42.8.Runningtheapplication

Page 49: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.MSMQQuickStart43.1.Introduction43.2.MessageDestinations43.3.Gateways43.4.MessageData43.5.MessageHandlers43.6.MessageConverters43.7.MessagingInfrastructure43.8.Runningtheapplication

Page 50: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

44.WCFQuickStart44.1.Introduction44.2.Theserverside

44.2.1.WCFDependencyInjectionandAOPinself-hostedapplication44.2.2.WCFDependencyInjectionandAOPinIISwebapplication

44.3.ClientaccessVIII.Spring.NETforJavadevelopers

Page 51: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

45.Spring.NETforJavaDevelopers45.1.Introduction45.2.BeanstoObjects45.3.PropertyEditorstoTypeConverters45.4.ResourceBundle-ResourceManager45.5.Exceptions45.6.ApplicationConfiguration45.7.AOPFramework

45.7.1. Cannot specify target name at the end of interceptorNames forProxyFactoryObject

A.XMLSchema-basedconfigurationA.1.IntroductionA.2.XMLSchema-basedconfiguration

A.2.1.ReferencingtheschemasA.2.2.Thetx(transaction)schemaA.2.3.TheaopschemaA.2.4.ThedbschemaA.2.5.TheremotingschemaA.2.6.ThenmsmessagingschemaA.2.7.ThevalidationschemaA.2.8.Theobjectsschema

A.3.SettingupyourIDEB.ExtensibleXMLauthoring

B.1.IntroductionB.2.AuthoringtheschemaB.3.CodingaINamespaceParserB.4.CodinganIObjectDefinitionParserB.5.Registeringthehandlerandtheschema

B.5.1.NamespaceParsersSectionHandlerB.6.UsingacustomextensioninyourSpringXMLconfigurationB.7.FurtherResources

C.Spring.NET'sspring-objects.xsd

Page 52: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter1.PrefaceDeveloping software applications is hard enough even with good tools andtechnologies. Spring provides a light-weight solution for building enterprise-ready applications. Spring provides a consistent and transparent means toconfigureyour application and integrateAOP intoyour software.HighlightsofSpring'sfunctionalityareprovidingdeclarativetransactionmanagementforyourmiddletieraswellasafull-featuredASP.NETframework.Spring could potentially be a one-stop-shop for many areas of enterpriseapplicationdevelopment;however,Spring ismodular,allowingyou touse justthosepartsofitthatyouneed,withouthavingtobringintherest.Youcanusejust the IoC container to configure your application and use traditionalADO.NET based data access code, but you could also choose to use just theHibernate integration code or the ADO.NET abstraction layer. Spring has been (andcontinues to be) designed to be non-intrusive, meaning dependencies on theframework itself are generally none (or absolutelyminimal, depending on theareaofuse).This document provides a reference guide to Spring's features. Since thisdocumentisstilltobeconsideredverymuchwork-in-progress,ifyouhaveanyrequestsorcomments,pleasepostthemontheusermailinglistoronthesupportforumsatforum.springframework.net.Beforewegoon, a fewwords of gratitude are due toChristianBauer (of theHibernate team),whopreparedandadaptedtheDocBook-XSLsoftwareinordertobeabletocreateHibernate'sreferenceguide, thusalsoallowingustocreatethis one. Also thanks to Russell Healy for doing an extensive and valuablereviewofsomeofthematerial.

Page 53: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter2.Introduction

Page 54: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

2.1.OverviewSpring.NET is an application framework that provides comprehensiveinfrastructuralsupportfordevelopingenterprise.NETapplications.Itallowsyoutoremoveincidentalcomplexitywhenusingthebaseclasslibrariesmakesbestpractices, such as test driven development, easy practices. Spring.NET iscreated,supportedandsustainedbySpringSource.The design of Spring.NET is based on the Java version of the SpringFramework,which has shown real-world benefits and is used in thousands ofenterprise applications world wide. Spring .NET is not a quick port from theJavaversion,butrathera'spiritualport'basedonfollowingprovenarchitecturalanddesignpatterns in thatarenot tied toaparticularplatform.ThebreadthoffunctionalityinSpring.NETspansapplicationtierswhichallowsyoutotreatitasa‘onestopshop’butthatisnotrequired.Spring.NETisnotanall-or-nothingsolution. You can use the functionality in its modules independently. Thesemodulesaredescribedbelow.Enterprise applications typically are composed of a number of a variety ofphysical tiers and within each tier functionality is often split into functionallayers.Thebusinessservicelayerforexampletypicallyusesaobjectsinthedataaccesslayertofulfillause-case.Nomatterhowyourapplicationisarchitected,at the end of the day there are a variety of objects that collaborate with oneanothertoformtheapplicationproper.Theobjectsinanapplicationcanthusbesaidtohavedependenciesbetweenthemselves.The .NET platform provides a wealth of functionality for architecting andbuildingapplications,rangingallthewayfromtheverybasicbuildingblocksofprimitive typesandclasses (and themeans todefinenewclasses), to rich full-featured application servers and web frameworks. One area that is decidedlyconspicuousbyitsabsenceisanymeansoftakingthebasicbuildingblocksandcomposing them intoacoherentwhole; this areahas typicallybeen left to thepurveyof thearchitectsanddevelopers taskedwithbuildinganapplication(orapplications).Nowtobefair, thereareanumberofdesignpatternsdevoted tothebusinessofcomposingthevariousclassesandobjectinstancesthatmakeupanall-singing,all-dancingapplication.DesignpatternssuchasFactory,AbstractFactory, Builder, Decorator, and Service Locator (to name but a few) havewidespread recognition and acceptance within the software developmentindustry(presumablythatiswhythesepatternshavebeenformalizedaspatterns

Page 55: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

in the first place). This is all very well, but these patterns are just that: bestpracticesgivenaname,typicallytogetherwithadescriptionofwhatthepatterndoes, where the pattern is typically best applied, the problems that theapplicationofthepatternaddresses,andsoforth.Noticethatthelastparagraphusedthephrase“...adescriptionofwhatthepatterndoes...”;patternbooksandwikisaretypicallylistingsofsuchformalizedbestpracticethatyoucancertainlytakeaway,mullover,andthenimplementyourselfinyourapplication.TheSpringFrameworktakesbestpracticesthathavebeenprovenovertheyearsinnumerousapplicationsandformalizedasdesignpatterns,andactuallycodifiesthese patterns as first class objects that you as an architect and developer cantakeawayandintegrateintoyourownapplication(s).ThisisaVeryGoodThingIndeed as attested to by the numerous organizations and institutions that haveused theSpringFramework to engineer robust,maintainable applications. Forexample,theIoCcomponentoftheSpringFrameworkaddressestheenterpriseconcern of taking the classes, objects, and services that are to compose anapplication, by providing a formalized means of composing these variousdisparatecomponentsintoafullyworkingapplicationreadyforuse

Page 56: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

2.2.BackgroundInearly2004,MartinFowlerasked the readersofhissite:when talking aboutInversion of Control: “the question is, what aspect of control are [they]inverting?”.Fowlerthensuggestedrenamingtheprinciple(oratleastgivingitamoreself-explanatoryname),andstartedtousethetermDependencyInjection.His article then continued to explain the ideas underpinning the Inversion ofControl (IoC) and Dependency Injection (DI) principle. If you need a decentinsight into IoC and DI, please do refer to the article :http://martinfowler.com/articles/injection.html.

Page 57: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

2.3.ModulesTheSpringFrameworkcontainsalotoffeatures,whicharewell-organized intomodules shown in the diagram below. The diagram below shows the variouscoremodulesofSpring.NET.

Clickonthemodulenameformoreinformation.Spring.Core is the most fundamental part of the framework allowing you toconfigure your application using Dependency Injection. Other supportingfunctionality,listedbelow,islocatedinSpring.CoreSpring.Aop -Use thismodule to performAspect-Oriented Programming (AOP).AOP centralizes common functionality that can then be declaratively appliedacross your application in a targeted manner. Spring's aspect library providespredefined easy to use aspects for transactions, logging, performancemonitoring,caching,methodretry,andexceptionhandling.Spring.Data - Use this module to achieve greater efficiency and consistency inwriting data access functionality in ADO.NET and to perform declarativetransactionmanagement.

Page 58: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Spring.Data.NHibernate - Use this module to integrate NHibernate with Spring’sdeclarative transaction management functionality allowing easy mixing ofADO.NETandNHibernateoperationswithin thesame transaction.NHibernate1.0userswillbenefitfromeaseofuseAPIstoperformdataaccessoperations.Spring.Web - Use this module to raise the level of abstraction when writingASP.NETweb applications allowing you to effectively address commonpain-points in ASP.NET such as data binding, validation, and ASP.NETpage/control/module/providerconfiguration.Spring.Web.Extensions - Use this module to raise the level of abstraction whenwritingASP.NETwebapplicationsallowingyoutoeffectivelyaddresscommonpain-points in ASP.NET such as data binding, validation, and ASP.NETpage/control/module/providerconfiguration.Spring.Services-Usethismoduletoadaptplain.NETobjectssotheycanbeusedwithaspecificdistributedcommunicationtechnology,suchas.NETRemoting,EnterpriseServices,andASMXWebServices.Theseservicescanbeconfiguredviadependencyinjectionand‘decorated’byapplyingAOP.Spring.Testing.NUnit-UsethismoduletoperformintegrationtestingwithNUnit.TheSpring.Coremodulealsoincludesthefollowingadditionalfeatures

Expression Language - provides efficient querying and manipulation of anobjectgraphsatruntime.

ValidationFramework - a robustUIagnostic framework for creatingcomplexvalidationrulesforbusinessobjectseitherprogramaticallyordeclaratively.

Data binding Framework - a UI agnostic framework for performing databinding.

DynamicReflection-providesahighperformancereflectionAPI

Threading - provides additional concurrency abstractions such as Latch,SemaphoreandThreadLocalStorage.

Resourceabstraction - provides a common interface to treat the InputStreamfrom a file and from a URL in a polymorphic and protocol-independentmanner.

Page 59: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

2.4.UsageScenariosWith the building blocks described above you can use Spring in all sorts ofscenarios, from simple stand alone console applications to fully-fledgedenterpriseapplicationsusingSpring'stransactionmanagementfunctionalityandwebframeworkintegration.It is important to note that the Spring Framework does not force you to useeverythingwithinit;itisnotanall-or-nothingsolution.Existingfront-endsbuiltusing standardASP.NET can be integrated perfectlywellwith a Spring-basedmiddle-tier,allowingyoutousethetransactionand/ordataaccess features thatSpring offers. The only things you need to do is wire up your business logicusing Spring's IoC container and integrate it into your web layer usingWebApplicationContext to locate middle tier services and/or configure yourstandardASP.NETpageswithdepdenencyinjection.While the Spring framework does not force any particular applicationarchitecureitencouragestheuseofawelllayeredapplicationarchitecturewithdistincttiersforthepresentation,service,dataaccess,anddatabase.

Page 60: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

2.5.QuickstartapplicationsThereareseveralsampleapplications thatshowcase individualfeatures. Ifyouare already familiarwith the concepts of dependency injection, AOP, or haveexperience using the Java version of the Spring framework you may findjumping into the examples a better way to bootstrap the learning processingprocess.Thefollowingquickstartapplicationsareavailableandcanbefoundinthe examples directory in the distribution. Click on the links for additionalinformation.

Movie Finder - A simple demonstration of Dependency Injection (DI)techniquesusingSpring'sInversionofControl(IoC)container.

ApplicationContext-DemonstratesIoCcontainerfeaturessuchaslocalization,accessing of ResourceSet objects, and applying resources to objectproperties.

AspectOrientedProgramming-DemonstratesuseoftheAOPframeworktoaddadditionalbehaviortoyourexistingobjects.ExamplesofprogrammaticanddeclarativeAOPconfigurationareshown.

DistributedComputing-Acalculatordemonstratingremoteserviceabstractionsthatletyou'export'aplain.NETobject(PONO)via.NETRemoting,WebServices,oranEnterpriseServiceServiceComponent.Correspondingclientsideproxiesarealsodemonstrated.

WCF -ShowsaWCFbasedcalculatorexample thatconfiguresyourWCFserviceviadependencyinjectionandapplyAOPadvice.

WebApplication-SpringAir-AticketbookingapplicationthatdemonstratestheASP.NETframeworkshowingfeaturessuchasDIforASP.NETpages,databinding,validation,andlocalization.

Web Development - Introductory examples showing use of dependencyinjectionandSpring'sbi-directionaldatabindinginASP.NET.

Data Access - Demonstrates the ADO.NET framework showing how tosimplifydevelopingADO.NETbaseddataaccesslayers.

Transaction Management : Demonstrates the use of declarative transactionmanagementforbothlocalanddistributedtransactioninboth.NET1.1and2.0.

Page 61: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AJAX:Demonstrateshowtoaccessaplain.NETobjectasawebserviceinclientsideJavaScript

NHibernateNorthwind:DemonstratesuseofSpring'sNHibernateintegrationtosimplifytheuseofNHibernate.Webtier isalsoincludedshowinghowtousetheOpen-SessionInViewapproachtosessionmanagementinthewebtier.

QuartzQuickstart-ApplicationthatshowstheuseofQuartz.NETintegrationforscheduling.

NMS-ApplicatoindemonstratingNMShelperclasses.

Page 62: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

2.6.LicenseInformationSpring.NET is licensedaccording to the termsof theApacheLicense,Version2.0. The full text of this license are available online athttp://www.apache.org/licenses/LICENSE-2.0 . You can also view the full text of thelicenseinthelicense.txtfilelocatedintherootinstallationdirectory.

Page 63: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

2.7.SupportTrainingandsupportareavailablethroughSpringSourceinadditiontothemailinglistsandforumsyoucanfindonthemainSpring.NETwebsite.

Page 64: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter3.Backgroundinformation

Page 65: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

3.1.InversionofControlInearly2004,MartinFowlerasked the readersofhissite:when talking aboutInversion of Control: "the question, is what aspect of control are theyinverting?".After talkingabout the term Inversion ofControlMartin suggestsrenaming the pattern, or at least giving it a more self-explanatory name, andstartstousethetermDependencyInjection.Hisarticlecontinuestoexplainsomeoftheideasbehindthisimportantsoftwareengineeringprinciple.Otherreferencesyoumayfindusefulare

WikipediaArticle-DependencyInjection

CodeProjectarticle-DependencyInjectionforLooseCoupling

Page 66: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter4.Migratingfrom1.1M2

Page 67: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

4.1.IntroductionSeveralAPIchangesweremadeafter1.1M2(before1.1RC1)dueprimarilybytheneedtorefactorthecodebasetoremovecirculardependencycycles,whicharenowallremoved.Classandschemanamechangeswerealsomadetoprovideamoreconsistentnamingconventionacross thecodebase.Asa resultof thesechanges, you can not simply drop in the new .dlls as youmay have done inpreviousrelease.Thisdocumentservesasahighlevelguidetothemost likelyareaswhereyouwillneedtomakechangestoeitheryourconfigurationoryourcode.The file, BreakingChanges-1.1.txt, in the root directory of the distributioncontainsthefulllistingofbreakingchangesmadeforRC1andhigher

Page 68: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

4.2.ImportantChangesThis sectioncovers thecommonareaswereyouwillneed tomakechanges incode/configurationwhenmigrationfromM2toRC1orhigher.

4.2.1.NamespacesNote: Ifyoupreviously installedSpring .xsd files toyourVS.NET installationdirectory,removethemmanually,andcopyoverthenewones,whichhave the-1.1.xsdsuffix.Thenamesofthesectionhandlerstoregistercustomschemashaschanged,fromConfigParsersSectionHandler toNamespaceParsersSectionHandler.The target namespaces have changed, the 'directory' named /schema/ has beenremoved. For example, the target schema changed fromhttp://www.springframework.net/schema/tx tohttp://www.springframework.net/tx.

Atypicaldeclarationtousecustomschemaswithinyourconfigurationfilelookslikethis

<objectsxmlns='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 toNamespaceParserRegistry.

Renamed Spring.Validation.ValidationConfigParser

toSpring.Validation.Config.ValidationNamespaceParser

Renamed from DatabaseConfigParser toDatabaseNamespaceParser

Renamed/Moved Remoting.RemotingConfigParser toRemoting.Config.RemotingNamespaceParser

Atypicalregistrationofcustomparserswithinyourconfigurationfilelookslike

Page 69: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

this

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Aop.Config.AopNamespaceParser,Spring.Aop"

<parsertype="Spring.Data.Config.DatabaseNamespaceParser,Spring.Data"

<parsertype="Spring.Transaction.Config.TxNamespaceParser,Spring.Data"

</parsers>

</spring>

Amanualregistrationwouldlooklikethis

NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));

NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));

NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));

4.2.2.CoreMovedSpring.Util.DynamicReflectiontoSpring.Reflection.DynamicMoved TypeRegistry and related classes from Spring.Context.Support toSpring.Core.TypeResolutionMovedSpring.Objects.TypeConverterstoSpring.Core.TypeConvesion

4.2.3.WebMovedSpring.Web.ValidationtoSpring.Web.UI.Validation

4.2.4.DataChangedschematouse'provider'insteadof'dbProvider'element,usageisnow<db:provider.../>andnot<db:dbProvider.../>Moved TransactionTemplate, TransactionDelegate and ITransactionCallback

Page 70: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

fromSpring.DatatoSpring.Data.SupportMoved AdoTemplate, AdoAccessor, AdoDaoSupport,RowMapperResultSetExtractorfromSpring.DatatoSpring.Data.CoreMoved AdoPlatformTransactionManager,ServiceDomainPlatformTransactionManager, and TxScopeTransactionManagerfromSpring.DatatoSpring.Data.Core

Page 71: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PartI.CoreTechnologiesThisinitialpartofthereferencedocumentationcoversallofthosetechnologiesthatareabsolutelyintegraltotheSpringFramework.Foremost amongst these is theSpringFramework's InversionofControl (IoC)container. A thorough treatment of the Spring Framework's IoC container isclosely followed by comprehensive coverage of Spring's Aspect-OrientedProgramming (AOP) technologies. The Spring Framework has its own AOPframework, which is conceptually easy to understand, andwhich successfullyaddressesthe80%sweetspotofAOPrequirementsinenterpriseprogramming.The core functionality also includes an expression language for lightweightscriptingandaui-agnosticvalidationframework.Finally,theadoptionofthetest-driven-development(TDD)approachtosoftwaredevelopment is certainly advocated by the Spring team, and so coverage ofSpring's support for integration testing is covered (alongside best practices forunit testing).TheSpring teamhave found that thecorrectuseof IoCcertainlydoes make both unit and integration testing easier (in that the presence ofproperties and appropriate constructors on classes makes them easier to wiretogether on a test without having to set up service locator registries andsuchlike)...thechapterdedicatedsolelytotestingwillhopefullyconvinceyouofthisaswell.

Chapter5,TheIoCcontainer

Chapter6,TheIObjectWrapperandTypeconversion

Chapter7,Resources

Chapter8,ThreadingandConcurrencySupport

Chapter9,ObjectPooling

Chapter11,ExpressionEvaluation

Chapter10,Spring.NETmiscellanea

Chapter12,ValidationFramework

Chapter13,AspectOrientedProgrammingwithSpring.NET

Chapter14,AspectLibrary

Chapter15,CommonLogging

Page 72: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter16,Testing

Page 73: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter5.TheIoCcontainer

Page 74: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.1.IntroductionThischaptercoverstheSpringFramework'simplementationoftheInversionofControl(IoC)[1]principleThe Spring.Core assembly provides the basis for the Spring.NETInversionofControlcontainer.TheIObjectFactoryinterfaceprovidesanadvancedconfiguration mechanism capable of managing objects of any nature. TheIApplicationContext interface builds on top of theIObjectFactory (it is asub-interface) and adds other functionality such as easier integration withSpring.NET'sAspectOrientedProgramming(AOP)features,messageresourcehandling (for use in internationalization), event propagation and applicationlayer-specificcontextsuchasWebApplicationContextforuseinwebapplications.Inshort,theIObjectFactoryprovidestheconfigurationframeworkandbasic functionality, while the IApplicationContext adds moreenterprise-centric functionality to it. TheIApplicationContext is acomplete superset of the IObjectFactory, and any description ofIObjectFactorycapabilitiesandbehaviorshouldbeconsideredtoapplytoIApplicationContextsaswell.This chapter is divided into two parts, with the first part covering the basicprinciples that apply to both the IObjectFactory andIApplicationContext,withthesecondpartcoveringthosefeaturesthatapplyonlytotheIApplicationContextinterface.If you are new to Spring.NET or IoC containers in general, youmaywant toconsider starting with Chapter 33, IoC Quickstarts, which contains a number ofintroductorylevelexamplesthatactuallydemonstratealotofwhatisdescribedin detail below. Don't worry if you don't absorb everything at once... thoseexamples serve only to paint a picture of how Spring.NET hangs together inreallybroadbrushstrokes.Onceyouhavefinishedwiththoseexamples,youcancomebacktothissectionwhichwillfillinallthefinedetail.

Page 75: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.2.Basics-containersandobjects

5.2.1.ThecontainerThe IObjectFactory is the actual representation of the Spring IoCcontainer that is responsible for instantiating, configuring, and managing anumberofobjects.TheIObjectFactory interface is the central IoC container interface inSpring. Its responsibilities include instantiatingor sourcingapplicationobjects,configuring such objects, and assembling the dependencies between theseobjects.ThereareanumberofimplementationsoftheIObjectFactory interfacethat come supplied straight out-of-the-box with Spring. The most commonlyusedIObjectFactory implementation is theXmlObjectFactoryclass.Thisimplementationallowsyoutoexpresstheobjectsthatcomposeyourapplication, and the doubtless rich interdependencies between such objects, interms ofXML. TheXmlObjectFactory takes this XML configurationmetadata and uses it to create a fully configured system or application.InteractionwiththeIObjectFactoryinterfaceisdiscussedinSection5.2.6,“Using the container”. Additional features offered by another implementation ofIObjectFactory, theIApplicationContext, are discussed insectionSection5.10,“TheIApplicationContext”.

Page 76: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.2.1.1.ConfigurationmetadataAs can be seen in the above image, the Spring IoC container consumessomeformofconfigurationmetadata;thisconfigurationmetadataisnothingmorethanhowyou(asanapplicationdeveloper)informtheSpringcontainerastohowto“instantiate, configure, and assemble [the objects in your application]”. Thisconfiguration metadata is typically supplied in a simple and intuitive XMLformat. When using XML-based configuration metadata, you write objectdefinitions for thoseobject thatyouwant theSpring IoCcontainer tomanage,andthenletthecontainerdoit'sstuff.

Note

XML-basedmetadataisbyfarthemostcommonlyusedformofconfigurationmetadata.Itisnothowevertheonlyformofconfigurationmetadatathatisallowed.TheSpringIoCcontaineritselfistotallydecoupledfromtheformatinwhichthisconfigurationmetadataisactuallywritten.AttributebasedmetadatawillbepartofanupcomingreleaseanditisalreadypartoftheSpringJava

Page 77: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

framework.

Springconfigurationconsistsofatleastoneobjectdefinitionthatthecontainermustmanage,buttypicallytherewillbemorethanoneobjectdefinition.Whenusing XML-based configuration metadata, these object are configured as<object/>elementsinsideatop-level<objects/>element.These object definitions correspond to the actual objects that make up yourapplication. Typically you will have object definitions for your service layerobjects,yourdataaccessobjects(DAOs),presentationobjectssuchasASP.NETpageinstances,infrastructureobjectssuchasNHibernateSessionFactories,andso forth. Typically one does not configure fine-grained domain objects in thecontainer,becauseitisusuallytheresponsibilityofDAOsandbusinesslogictocreate/loaddomainobjects.Find below an example of the basic structure of XML-based configurationmetadata.

<objectsxmlns="http://www.springframework.net">

<objectid="..."type="...">

<!--collaboratorsandconfigurationforthisobjectgohere-->

</object>

<objectid="...."type="...">

<!--collaboratorsandconfigurationforthisobjectgohere-->

</object>

<!--moreobjectdefinitionsgohere-->

</objects>

5.2.2.InstantiatingacontainerInstantiatingaSpringIoCcontainerisstraightforward.

IApplicationContextcontext=newXmlApplicationContext(

"file://services.xml",

"assembly://MyAssembly/MyDataAccess/data-access.xml"

//anIApplicationContextisalsoanIObjectFactory(viainheritance)

Page 78: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

IObjectFactoryfactory=context;

Youcanalsocreateancontainerbyusingacustomconfigurationsectioninthestandard .NET application (orweb) configuration file.Once the container hasbeencreatedyoumayneverneedtoexplicitlyinteractwithitagaininyourcode,forexamplewhenconfiguringASP.NETpages.YoumaybewonderingwhattheassemblyURLisallabout.TheaboveexampleusesSpring.NET'sIResourceabstraction.TheIResourceinterfaceprovidesasimpleanduniforminterfacetoawidearrayofIOresourcesthatcanrepresentthemselvesasSystem.IO.Stream.Anexampleforafilebasedresource,notusingtheURLsyntaxbutanimplementationof theIResourceinterfaceforfileisshownbelow.

[C#]

IResourceinput=newFileSystemResource("objects.xml");

IObjectFactoryfactory=newXmlObjectFactory(input);

TheseresourcesaremostfrequentlyfilesorURLsbutcanalsoberesourcesthathavebeenembedded insidea .NETassembly.AsimpleURI syntax isused todescribethelocationoftheresource,whichfollowsthestandardconventionsforfiles, i.e.file://object.xml andotherwellknownprotocols suchashttp.The following snippet shows the use of the URI syntax for referring to aresource that has been embedded inside a .NET assembly,assembly://<AssemblyName>/<NameSpace>/<ResourceName>

TheIResourceabstractionisexplainedfurtherinSection7.1,“Introduction”.

Note

TocreateanembeddedresourceusingVisualStudioyoumustsettheBuildActionofthe.xmlconfigurationfiletoEmbeddedResourceinthefilepropertyeditor.Also,youwillneedtoexplicitlyrebuildtheprojectcontainingtheconfigurationfileifitistheonlychangeyoumakebetweensuccessivebuilds.IfusingNAnttobuild,adda<resources>sectiontothecsctask.Forexampleusage,lookattheSpring.Core.Tests.buildfileincludedthedistribution.

The preferred way to create an IApplicationContext or

Page 79: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

IObjectFactoryistouseacustomconfigurationsectioninthestandard.NET application configuration file (one of App.config orWeb.config). A custom configuration section that creates the sameIApplicationContextasthepreviousexampleis

<spring>

<contexttype="Spring.Context.Support.XmlApplicationContext,Spring.Core"

<resourceuri="file://services.xml"/>

<resourceuri="assembly://MyAssembly/MyDataAccess/data-access.xml"

</context>

</spring>

The context type (specified as the value of the type attribute of thecontext element) is wholly optional, and defaults to theSpring.Context.Support.XmlApplicationContext

class,sothefollowingXMLsnippetisfunctionallyequivalenttothefirst.

<spring>

<context>

<resourceuri="file://services.xml"/>

<resourceuri="assembly://MyAssembly/MyDataAccess/data-access.xml"

</context>

</spring>

To acquire a reference to anIApplicationContext using a customconfigurationsection,onesimplyusesthefollowingcode;

IApplicationContextctx=ContextRegistry.GetContext();

TheContextRegistryisusedtobothinstantiatetheapplicationcontextand to perform service locator style access to other objects. (See Section 5.15,“ServiceLocatoraccess”formoreinformation).Thegluethatmakesthispossibleisan implementation of the Base Class Library (BCL) providedIConfigurationSectionHandler interface, namely theSpring.Context.Support.ContextHandler class. ThehandlerclassneedstoberegisteredintheconfigSectionssectionofthe.NETconfigurationfileasshownbelow.

Page 80: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

</sectionGroup>

</configSections>

Thisdeclarationnowenablestheuseofacustomcontextsectionstartingatthespringrootelement.In some usage scenarios, user code will not have to explicitly instantiate anappropriate implementation of the IObjectFactory interface, sinceSpring.NET code will do it. For example, the ASP.NET web layer providessupport code to load a Spring.NET IApplicationContext

automatically as part of the normal startup process of an ASP.NET webapplication.SimilarsupportforWinFormsapplicationsisbeinginvestigated.WhileprogrammaticmanipulationofIObjectFactory instanceswill bedescribed later, the following sections will concentrate on describing theconfigurationofobjectsmanagedbyIObjectFactoryinstances.Spring.NET comes with an XSD schema tomake the validation of the XMLobject definitions a whole lot easier. The XSD document is thoroughlydocumentedsofeelfreetotakeapeekinside(seeAppendixC,Spring.NET's spring-objects.xsd).TheXSDiscurrentlyusedintheimplementationcodetovalidatetheXMLdocument.TheXSDschemaservesadualpurposeinthatitalsofacilitatesthe editing of XML object definitions inside an XSD aware editor (typicallyVisual Studio) by providing validation (and Intellisense support in the case ofVisualStudio).YoumaywishtorefertoChapter32,VisualStudio.NETIntegrationformoreinformationregardingsuchintegration.Your XML object definitions can also be defined within the standard .NETapplication configuration file by registering theSpring.Context.Support.DefaultSectionHandler

class as the configuration section handler for inline object definitions. Thisallows you to completely configure one or moreIApplicationContext instances within a single standard .NETapplicationconfigurationfileasshowninthefollowingexample.

<configuration>

Page 81: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<context>

<resourceuri="config://spring/objects"/>

</context>

<objectsxmlns="http://www.springframework.net">

...

</objects>

</spring>

</configuration>

Other options available to structure the configuration files are described inSection5.12.1,“ContextHierarchies”andSection5.2.2.1,“ComposingXML-basedconfigurationmetadata”.The IApplicationContext can be configured to register otherresource handlers, custom parsers to integrate user-contributed XML schemaintotheobjectdefinitionssection,typeconverters,anddefinetypealiases.ThesefeaturesarediscussedinsectionSection5.11,“ConfigurationofIApplicationContext”

5.2.2.1.ComposingXML-basedconfigurationmetadataIt isoftenuseful tosplitupcontainerdefinitions intomultipleXMLfiles.OnewaytothenloadanapplicationcontextwhichisconfiguredfromalltheseXMLfragments is to use the application context constructor which takes multipleresource locations.With an object factory, an object definition reader can beusedmultipletimestoreaddefinitionsfromeachfileinturn.Generally, the Spring.NET team prefers the above approach, assemblingindividualfilesbecauseitkeepscontainerconfigurationfilesunawareofthefactthattheyarebeingcombinedwithothers.However,analternateapproachis tocomposeoneXMLobjectdefinition fileusingoneormoreoccurrencesof the

Page 82: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

importelementtoloaddefinitionsfromotherfiles.Anyimportelementsmustbeplacedbeforeobjectelementsinthefiledoingtheimporting.Let'slookatasample:

<objectsxmlns="http://www.springframework.net">

<importresource="services.xml"/>

<importresource="resources/messageSource.xml"/>

<importresource="/resources/themeSource.xml"/>

<objectid="object1"type="..."/>

<objectid="object2"type="..."/>

</objects>

In this example, external object definitions are being loaded from 3 files,services.xml, messageSource.xml, andthemeSource.xml. All location paths are considered relative to thedefinitionfiledoingtheimporting,soservices.xmlinthiscasemustbein the same directory as the file doing the importing, whilemessageSource.xml and themeSource.xml must be in aresourceslocationbelowthelocationoftheimportingfile.Asyoucansee,a leadingslash isactually ignored,butgiven that theseare considered relativepaths, it isprobablybetter formnot touse theslashatall.Thecontentsof thefilesbeingimportedmustbefullyvalidXMLobjectdefinitionfilesaccordingtotheXSD,includingthetoplevelobjectselement.

5.2.3.TheObjectsASpringIoCcontainermanagesoneormoreobjects. theseobjectsarecreatedusing the configuration metadata that has been supplied to the container(typicallyintheformofXML<object/>definitions).Within the container itself, these object definitions are represented asIObjectDefinition objects, which contain (among other information) thefollowingmetadata:

Atypename:typicallythisistheactualimplementationclassoftheobjectbeingdefined..

Page 83: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Object behavioral configuration elements, which state how the objectshouldbehaveintheSpring.NETIoCcontainer(i.e.prototypeorsingleton,lifecyclecallbacks,andsoforth)

referencestootherobjectswhichareneededfortheobjecttodo itswork:thesereferencesarealsocalledcollaboratorsordependencies.

otherconfigurationsettingstosetinthenewlycreatedobject.Anexamplewouldbethenumberofthreadstouseinanobjectthatmanagesaworkerthreadpool,orthesizelimitofthepool.

The concepts listed above directly translate to a set of elements the objectdefinition consists of. These elements are listed below, along with a link tofurtherdocumentationabouteachofthem.

Table5.1.ObjectdefinitionexplanationFeature Moreinfo

type Section5.2.4,“Objectcreation”

idandname Section5.2.3.1,“Namingobjects”

singletonorprototype Section5.4,“ObjectScopes”

objectproperties Section5.3.1,“Injectingdependencies”

constructorarguments Section5.3.1,“Injectingdependencies”

autowiringmode Section5.3.6,“Autowiringcollaborators”

dependencycheckingmode Section5.3.7,“Checkingfordependencies”

initializationmethod Section5.6.1,“Lifecycleinterfaces”

destructionmethod Section5.6.1,“Lifecycleinterfaces”

Besidesobjectdefinitionswhichcontaininformationonhowtocreateaspecificobject, certain IObjectFactory implementations also permit theregistrationofexistingobjectsthathavebeencreatedoutsidethefactory(byusercode). The DefaultListableObjectFactory class supports thisthrough theRegisterSingleton(..) method. (Typical applicationssolelyworkwithobjectsdefinedthroughmetadataobjectdefinitionsthough.)

Page 84: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.2.3.1.NamingobjectsEveryobjecthasoneormoreids(alsocalledidentifiers,ornames;thesetermsrefer to the same thing). Theseidsmust be unique within the container theobject is hosted in. An object will almost always have only one id, but if anobjecthasmorethanoneid,theextraonescanessentiallybeconsideredaliases.When using XML-based configuration metadata, you use the 'id' or'name'attributes to specify the object identifier(s). The 'id' attributeallows you to specify exactly one id, and as it is a real XML element IDattribute, the XML parser is able to do some extra validation when otherelementsreferencetheid;assuch,itisthepreferredwaytospecifyanobjectid.However, the XML specification does limit the characters which are legal inXMLIDs.Thisisusuallynotaconstraint,butifyouhaveaneedtouseoneofthesespecialXMLcharacters, orwant to introduceother aliases to theobject,youmayalsoorinsteadspecifyoneormoreobjectids,separatedbyacomma(,),semicolon(;),orwhitespaceinthe'name'attribute.Pleasenotethatyouarenotrequiredtosupplyanameforaobject.Ifnonameissuppliedexplicitly,thecontainerwillgenerateauniquenameforthatobject.Themotivationsfornotsupplyinganameforaobjectwillbediscussedlater(oneusecaseisinnerobjects).

5.2.3.1.1.Aliasingobjects

Inanobjectdefinitionitself,youmaysupplymorethanonenamefortheobject,by using a combination of the id and name attributes as discussed inSection 5.2.3.1, “Naming objects”. This approach to aliasing objects has somelimitationswhenyouwouldliketoassemblethemainapplicationconfigurationfilefrommultiplefiles.Thisusagepatterniscommonwheneachconfigurationfile representsa logical layerorcomponentwithin theapplication. In thiscaseyoumaywant to refer to a common object dependency using a name that isspecific to each file. If the commonobject dependency is defined in themainapplication configuration file itself, then one can use the name element as analiasmechanism.However,ifthemainapplicationconfigurationfileshouldnotbe responsible for defining the common object dependency, since it logically'belongs' to one of the other layers or components, you can not use the name

Page 85: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

attributetoachievethisgoal.

Inthiscase,youcandefineanaliasusinganexplicitaliaselementcontainedinthemainapplicationconfigurationfile.<aliasname="fromName"alias="toName"/>

ThisallowsanobjectnamedfromNametobereferredtoastoNameacrossallapplicationconfigurationfiles.As a concrete example, consider the case where the configuration file 'a.xml'(representing component A) defines a connection object called componentA-connection. In another file, 'b.xml' (representing component B) would like torefer to the connection as componentB-connection. And themain application,MyApp, defines its own XML fragment to assembles the final applicationconfigurationfromallthreefragmentsandwouldliketorefertotheconnectionas myApp-connection. This scenario can be easily handled by adding to theMyAppXMLfragmentthefollowingstandalonealiases:<alias name="componentA-connection"

alias="componentB-connection"/>

<alias name="componentA-connection"

alias="myApp-connection"/>

Noweachcomponentandthemainappcanrefertotheconnectionviaanamethatisuniqueandguaranteednottoclashwithanyotherdefinition(effectivelythereisanamespace),yettheyrefertothesameobject.

5.2.4.ObjectcreationAnobjectdefinitionessentiallyisarecipeforcreatingoneormoreobjects.Thecontainer looks at the recipe for a named object when asked, and uses theconfiguration metadata encapsulated by that object definition to create (oracquire)anactualobject.IfyouareusingXML-basedconfigurationmetadata,youcanspecifythetypeofobject that is to be instantiated using the 'type' attribute of the<object/> element. This'type' attribute (which internally eventuallyboils down to being a Type property on a IObjectDefinitioninstance) is normally mandatory (see XXX “Instantiation using an instancefactory method” and XXX “Object definition inheritance” for the twoexceptions)andisusedforoneoftwopurposes.Thetypepropertyspecifiesthe

Page 86: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

typeofoftheobjecttobeconstructedinthecommoncasewherethecontaineritselfdirectlycreatestheobjectbycallingitsconstructorreflectively(somewhatequivalenttoC#codeusingthe'new'operator).Inthelesscommoncasewherethecontainerinvokesastatic,factorymethodonaclasstocreatetheobject,the type property specifies the actual class containing the static factorymethodthatistobeinvokedtocreatetheobject(thetypeoftheobjectreturnedfromthe invocationof thestatic factorymethodmaybe the same typeoranothertypeentirely,itdoesn'tmatter).

5.2.4.1.ObjectcreationviaconstructorinvocationWhencreatinganobjectusing theconstructorapproach,allnormalclassesareusablebyandcompatiblewithSpring.That is, thetypebeingcreateddoesnotneedtoimplementanyspecificinterfacesorbecodedinaspecificfashion.Justspecifyingtheobjecttypeshouldbeenough.However,dependingonwhattypeof IoCyouaregoing touse for that specificobject, youmayneed to create adefaultconstructor(i.e.aconstructorthathasnoparameters)inthesourcecodedefinitionofyourclass.TheXmlObjectFactory implementation of theIObjectFactoryinterface can consume object definitions that have been defined in XML, forexample...

<objectid="exampleObject"type="Examples.ExampleObject,ExamplesLibrary"

The mechanism for supplying arguments to the constructor (if required), orsettingpropertiesoftheobjectinstanceafterithasbeenconstructed,isdescribedshortly.ThisXMLfragmentdescribesanobjectdefinitionthatwillbeidentifiedbytheexampleObject name, instances of which will be of theExamples.ExampleObject type that has been compiled into theExamplesLibrary assembly. Take special note of the structure of thetypeattribute'svalue...thenamespace-qualifiednameoftheclassisspecified,followed by a comma, followed by (at a bare minimum) the name of theassembly that contains the class. In the preceding example, theExampleObject class is defined in theExamples namespace, and ithasbeencompiledintotheExamplesLibraryassembly.

Page 87: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Thenameoftheassemblythatcontainsthetypemustbespecifiedinthetypeattribute. Furthermore, it is recommended that you specify the fully qualifiedassemblyname [2] in order to guarantee that the type thatSpring.NETuses toinstantiateyourobject(s)isindeedtheonethatyouexpect.Usuallythisisonlyan issue if you are using classes from (strongly named) assemblies that havebeeninstalledintotheGlobalAssemblyCache(GAC).Ifyouhavedefinednestedclassesuse theadditionsymbol,+, to reference thenestedclass.Forexample,iftheclassExamples.ExampleObjecthadanestedclassPersontheXMLdeclarationwouldbe

<objectid="exampleObject"type="Examples.ExampleObject+Person,ExamplesLibrary"

If you are defining classes that have been compiled into assemblies that areavailabletoyourapplication(suchasthebindirectoryinthecaseofASP.NETapplications) via the standard assembly probing mechanisms, then you canspecify simply the name of the assembly (e.g.ExamplesLibrary.Data)...thisway,when(orif)theassembliesusedbyyour application are updated, youwon't have to change the value of every<object/>definition'stypeattributetoreflectthenewversionnumber(iftheversionnumberhaschanged)...Spring.NETwillautomaticallylocateandusethe newer versions of your assemblies (and their attendant classes) from thatpointforward.

5.2.4.2.ObjectcreationviaastaticfactorymethodWhendefining anobjectwhich is to be createdusing a static factorymethod,along with the type attribute which specifies the type containing the staticfactorymethod,anotherattributenamedfactory-methodisneededtospecifythename of the factorymethod itself. Spring.NET expects to be able to call thismethod(withanoptionallistofargumentsasdescribedlater)andgetbackaliveobject,whichfromthatpointonistreatedasifithadbeencreatednormallyviaaconstructor.Oneuseforsuchanobjectdefinition is tocallstatic factories inlegacycode.Followingisanexampleofanobjectdefinitionwhichspecifiesthattheobjectisto be created by calling a factory-method. Note that the definition does notspecify the type (class) of the returned object, only the type containing the

Page 88: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

factory method. In this example, CreateInstance must be a staticmethod.

<objectid="exampleObject"

type="Examples.ExampleObjectFactory,ExamplesLibrary"

factory-method="CreateInstance"/>

The mechanism for supplying (optional) arguments to the factory method, orsetting properties of the object instance after it has been returned from thefactory,willbedescribedshortly.

5.2.4.3.ObjectcreationviaaninstancefactorymethodIna fashion similar to instantiationusinga static factorymethod, instantiationusing an instance factorymethod iswhere a non-staticmethod of an existingobject from the container is invoked to create the new object. To use thismechanism,the'type'attributemustbeleftempty,andthe'factory-object' attribute must specify the name of an object in the current (orparent/ancestor)containerthatcontainstheinstancemethodthatistobeinvokedtocreatetheobject.Thenameofthefactorymethoditselfshouldstillbesetviathe'factory-method'attribute.

<!--thefactoryobject,whichcontainsaninstancemethodcalled'CreateInstance'-->

<objectid="exampleFactory"type="...">

<!--injectanydependenciesrequiredbythisobject-->

</object>

<!--theobjectthatistobecreatedbythefactoryobject-->

<objectid="exampleObject"

factory-method="CreateInstance"

factory-object="exampleFactory"/>

Althoughthemechanismsforsettingobjectpropertiesarestill tobediscussed,oneimplicationofthisapproachisthatthefactoryobjectitselfcanbemanagedandconfiguredviaDependencyInjection,bythecontainer.

Note

WhentheSpringdocumentationmakesmentionofa'factoryobject',thiswillbeareferencetoanobjectthatisconfiguredintheSpring

Page 89: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

containerthatwillcreateobjectsviaaninstanceorstaticfactorymethod.WhenthedocumentationmentionsaIFactoryObject(noticethecapitalization)thisisareferencetoaSpring-specificIFactoryObject.

5.2.5.ObjectcreationofgenerictypesGeneric types can also be created in much the same manner an non-generictypes.

5.2.5.1. Object creation of generic types via constructorinvocationThefollowingexamplesshows thedefinitionofsimplegeneric types andhowtheycanbecreatedinSpring'sXMLbasedconfigurationfile.

namespaceGenericsPlay

{

publicclassFilterableList<T>

{

privateList<T>list;

privateStringname;

publicList<T>Contents

{

get{returnlist;}

set{list=value;}

}

publicStringName

{

get{returnname;}

set{name=value;}

}

publicList<T>ApplyFilter(stringfilterExpression)

{

///shouldreallyapplyfiltertolist;)

returnnewList<T>();

}

Page 90: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

}

TheXMLconfigurationtocreateandconfigurethisobjectisshownbelow

<objectid="myFilteredIntList"type="GenericsPlay.FilterableList&lt;int>,GenericsPlay"

<propertyname="Name"value="MyIntegerList"/>

</object>

Thereareafewitemstonoteintermshowtospecifyageneric type.First, theleftbracketthatspecifiesthegenerictype,i.e.<,isreplacedwiththestring&lt;due toXMLescapesyntax for the less thansymbol.Yes,weall realize this isless than ideal from the readability point of view. Second, the generic typeargumentscannotbefullyassemblyqualifiedasthecommaisusedtoseparategenerictypearguments.Alternativecharactersusedtoovercomethetwoquirkscan be implemented in the future but so far, all proposals don't seem to helpclarify the text. The suggested solution to improve readability is to use typealiasesasshownbelow

<typeAliases>

<aliasname="GenericDictionary"type="System.Collections.Generic.Dictionary&lt;,>"

<aliasname="myDictionary"type="System.Collections.Generic.Dictionary&lt;int,string>"

</typeAliases>

Sothatinsteadofsomethinglikethis

<objectid="myGenericObject"

type="GenericsPlay.ExampleGenericObject&lt;System.Collections.Generic.Dictionary&lt;int,string>>,GenericsPlay"

Itcanbeshortenedto

<objectid="myOtherGenericObject"

type="GenericsPlay.ExampleGenericObject&lt;GenericDictionary&lt;int,string>>,GenericsPlay"

orevenshorter

<objectid="myOtherOtherGenericObject"

type="GenericsPlay.ExampleGenericObject&lt;MyIntStringDictionary>,GenericsPlay"

Page 91: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

RefertoSection5.11,“ConfigurationofIApplicationContext”foradditionalinformationonusingtypealiases.

5.2.5.2.Object creation of generic types via static factorymethodThefollowingclassesareusedtodemonstrate theabilitytocreate instancesofgenerictypesthatthemselvesarecreatedviaastaticgenericfactorymethod.

publicclassTestGenericObject<T,U>

{

publicTestGenericObject()

{

}

privateIList<T>someGenericList=newList<T>();

privateIDictionary<string,U>someStringKeyedDictionary=

newDictionary<string,U>();

publicIList<T>SomeGenericList

{

get{returnsomeGenericList;}

set{someGenericList=value;}

}

publicIDictionary<string,U>SomeStringKeyedDictionary

{

get{returnsomeStringKeyedDictionary;}

set{someStringKeyedDictionary=value;}

}

}

Theaccompanyingfactoryclassis

publicclassTestGenericObjectFactory

{

publicstaticTestGenericObject<V,W>StaticCreateInstance<V,W>()

{

returnnewTestGenericObject<V,W>();

Page 92: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

publicTestGenericObject<V,W>CreateInstance<V,W>()

{

returnnewTestGenericObject<V,W>();

}

}

TheXMLsnippettocreateaninstanceofTestGenericObjectwhereVisaListofintegersandWisanintegerisshownbelow

<objectid="myTestGenericObject"

type="GenericsPlay.TestGenericObjectFactory,GenericsPlay"

factory-method="StaticCreateInstance&lt;System.Collections.Generic.List&lt;int>,int>"

/>

TheStaticCreateInstancemethod is responsible for instantiating theobject thatwillbeassociatedwiththeid'myTestGenericObject'.

5.2.5.3. Object creation of generic types via instancefactorymethodUsingtheclassfromthepreviousexampletheXMLsnippettocreateaninstanceofagenerictypeviaaninstancefactorymethodisshownbelow

<objectid="exampleFactory"type="GenericsPlay.TestGenericObject&lt;int,string>,GenericsPlay"

<objectid="anotherTestGenericObject"

factory-object="exampleFactory"

factory-method="CreateInstance&lt;System.Collections.Generic.List&lt;int>,int>"

This creates an instance ofTestGenericObject<List<int>,int>

5.2.6.UsingthecontainerAn IApplicationContext is essentially nothing more than theinterfaceforanadvancedfactorycapableofmaintaininga registryofdifferentobjects and their dependencies. The IApplicationContext enablesyoutoreadobjectdefinitionsandaccessthem.Youcreateoneandreadinsome

Page 93: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

objectdefinitionintheXMLformatasfollows:

IApplicationContextcontext=newXmlApplicationContext("file://objects.xml"

Basically that is all there is to it. Using GetObject(string) or theindexer[string],youcanretrieveinstancesofyourobject; theclient-sideview of the IApplicationContext is simple. TheIApplicationContext interfacehas just a fewothermethods relatedtofindingobjectsinthecontianer,butideallyyourapplicationcodeshouldneveruse them... indeed, your application code should have no calls to theGetObject(string)methodatall, and thusnodependencyonSpringAPIsatall.

Page 94: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.3.DependenciesYour typicalenterpriseapplication isnotmadeupofa singleobject.Even thesimplestofapplicationswillnodoubthaveatleastahandfulofobjectsthatworktogether topresentwhat theend-user seesasacoherentapplication.Thisnextsectionexplainshowyougofromdefininganumberofobjectdefinitions thatstand-alone, each to themselves, to a fully realized application where objectswork(orcollaborate)togethertoachievesomegoal(usuallyanapplicationthatdoeswhattheend-userwants).

5.3.1.InjectingdependenciesThebasicprinciplebehindDependencyInjection(DI)isthatobjectsdefinetheirdependencies (that is to say the other objects they work with) only throughconstructor arguments, arguments to a factorymethod,orpropertieswhicharesetontheobjectinstanceafterithasbeenconstructedorreturnedfromafactorymethod.Then,itisthejobofthecontainertoactuallyinjectthosedependencieswhen it creates the object. This is fundamentally the inverse, hence the nameInversionofControl(IoC),oftheobjectitselfbeingincontrolofinstantiatingorlocating its dependencies on its own using direct construction of classes, orsomethingliketheServiceLocatorpattern.It becomes evident upon usage that code gets much cleaner when the DIprinciple is applied, and reaching ahighergradeof decoupling ismucheasierwhenobjectsdonotlookuptheirdependencies,butareprovidedwiththem(andadditionallydonotevenknowwherethedependenciesarelocatedandofwhatconcrete class they are). DI exists in twomajor variants, namely ConstructorInjectionandSetterInjection.

5.3.1.1.ConstructorInjectionConstructor-based DI is effected by invoking a constructor with a number ofarguments,eachrepresentingadependency.Additionally,callingastaticfactorymethodwithspecificargumentstoconstructtheobject,canbeconsideredalmostequivalent,andtherestofthistextwillconsiderargumentstoaconstructorandargumentstoastaticfactorymethodsimilarly.Findbelowanexampleofaclassthatcouldonlybedependency injectedusingconstructor injection.Notice thatthereisnothingspecialaboutthisclass.

Page 95: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassSimpleMovieLister

{

//theSimpleMovieListerhasadependencyonaMovieFinder

privateIMovieFindermovieFinder;

//aconstructorsothattheSpringcontainercan'inject'aMovieFinder

publicMovieLister(IMovieFindermovieFinder)

{

this.movieFinder=movieFinder;

}

//businesslogicthatactually'uses'theinjectedIMovieFinderisomitted...

}

5.3.1.1.1.ConstructorArgumentResolution

Constructor argument resolutionmatchingoccursusing the argument's type. Ifthere is no potential for ambiguity in the constructor arguments of a objectdefinition, then the order inwhich the constructor arguments are defined in aobjectdefinition is theorder inwhich those argumentswill be supplied to theappropriate constructor when it is being instantiated. Consider the followingclass:

namespaceX.Y

{

publicclassFoo

{

publicFoo(Barbar,Bazbaz)

{

//...

}

}

}

There isnopotential forambiguityhere (assumingofcourse thatBarandBazclasses are not related in an inheritance hierarchy). Thus the followingconfigurationwillworkjustfine,andyoudonotneedtospecifytheconstructor

Page 96: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

argumentindexesand/ortypesexplicitly.

<objectname="Foo"type="X.Y.Foo,Example">

<constructor-arg>

<objecttype="X.Y.Bar,Example"/>

</constructor-arg>

<constructor-arg>

<objecttype="X.Y.Baz,Example"/>

</constructor-arg>

</object>

Whenanotherobject is referenced, the type isknown,andmatchingcanoccur(aswasthecasewiththeprecedingexample).Whenasimpletypeisused,suchas<value>true<value>,Springcannotdeterminethetypeofthevalue,andsocannotmatchbytypewithouthelp.Considerthefollowingclass:

usingSystem;

namespaceSimpleApp

{

publicclassExampleObject

{

privateintyears;//No.ofyearstothecalculatetheUltimateAnswer

privatestringultimateAnswer;//TheAnswertoLife,theUniverse,andEverything

publicExampleObject(intyears,stringultimateAnswer)

{

this.years=years;

this.ultimateAnswer=ultimateAnswer;

}

}

5.3.1.1.1.1.ConstructorArgumentTypeMatchingThe above scenario can use type matching with simple types by explicitlyspecifying the typeof theconstructorargumentusing thetypeattribute. Forexample:

Page 97: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectname="exampleObject"type="SimpleApp.ExampleObject,SimpleApp"

<constructor-argtype="int"value="7500000"/>

<constructor-argtype="string"value="42"/>

</object>

ThetypeattributespecifiestheSystem.Typeof theconstructorargument,suchasSystem.Int32.Alias'areavailabletoforcommonsimpletypes(andtheirarrayequivalents).Thesealias'are...

Table5.2.TypealiasesType Alias' ArrayAlias'

System.Char char,Char char[],Char()

System.Int16 short,Short short[],Short()

System.Int32 int,Integer int[],Integer()

System.Int64 long,Long long[],Long()

System.UInt16 ushort ushort[]

System.UInt32 uint uint[]

System.UInt64 ulong ulong[]

System.Float float,Single float[],Single()

System.Double double,Double double[],Double()

System.Date date,Date date[],Date()

System.Decimal decimal,Decimal decimal[],Decimal()

System.Bool bool,Boolean bool[],Boolean()

System.String string,String string[],String()

5.3.1.1.1.2.ConstructorArgumentIndexConstructor arguments can have their index specified explicitly by use of theindexattribute.Forexample:

<objectname="exampleObject"type="SimpleApp.ExampleObject,SimpleApp"

<constructor-argindex="0"value="7500000"/>

Page 98: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<constructor-argindex="1"value="42"/>

</object>

Aswellassolvingtheambiguityproblemofmultiplesimplevalues,specifyinganindexalsosolvestheproblemofambiguitywhereaconstructormayhavetwoargumentsofthesametype.Notethattheindexis0based.

5.3.1.1.1.3.ConstructorArgumentsbyNameConstructor arguments can also be specified by name by using the nameattributeofthe<constructor-arg>element.

<objectname="exampleObject"type="SimpleApp.ExampleObject,SimpleApp"

<constructor-argname="years"value="7500000"/>

<constructor-argname="ultimateAnswer"value="42"/>

</object>

5.3.1.2.SetterInjectionSetter-based DI is realized by calling setter methods on your objects afterinvoking a no-argument constructor or no-argument static factory method toinstantiateyourobject.Find below an example of a class that can only be dependency injected usingpuresetterinjection.

publicclassMovieLister

{

privateIMovieFindermovieFinder;

publicIMovieFinderMovieFinder

{

set

{

movieFinder=value;

}

}

//businesslogicthatactually'uses'theinjectedIMovieFinderisomitted...

}

Page 99: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Constructor- or Setter-basedDI?The Spring team generallyadvocates the usage of setterinjection, since a large number ofconstructor arguments can getunwieldy, especially when someproperties are optional. Thepresence of setter methods alsomakes objects of that classamenable to being re-configured(or re-injected) at some later time(formanagementpurposes).Constructor-injectionisfavoredbysomepuriststhoughandwithgoodreason.Supplyingallofanobject'sdependencies means that thatobject is never returned to client(calling)codeinalessthantotallyinitializedstate.Theflipsideisthatthe object becomes less amenableto re-configuration (or re-injection).Thereisnohardandfastrulehere.UsewhatevertypeofDImakesthemost sense for a particular class;sometimes,whendealingwiththirdparty classes towhich you do nothave the source, the choice willalreadyhavebeenmadeforyou-alegacy class may not expose anysettermethods, and so constructorinjection will be the only type ofDIavailabletoyou.Since you can mix both,Constructor-andSetter-basedDI,itis a good rule of thumb to useconstructor arguments formandatory dependencies andsettersforoptionaldependencies.

The IObjectFactory supports bothof these variants for injecting dependenciesinto objects it manages. (It in fact alsosupports injecting setter-baseddependenciesafter some dependencies have already beensupplied via the constructor approach.) TheconfigurationforthedependenciescomesintheformoftheIObjectDefinitionclass, which is used together withTypeConverters to know how toconvert properties from one format toanother.However,mostusersofSpring.NETwillnotbedealingwiththeseclassesdirectly(that is programatically), but ratherwith anXMLdefinitionfilewhichwillbeconvertedinternallyintoinstancesoftheseclasses,andused to load an entire Spring IoC containerinstance.Object dependency resolution generallyhappensasfollows:

1. TheIObjectFactory is createdand initialized with a configurationwhich describes all the objects. MostSpring.NET users use anIObjectFactory orIApplicationContextvariantthatsupportsXMLformatconfigurationfiles.

2. Eachobjecthasdependenciesexpressedin the form of properties, constructorarguments, or arguments to the static-factory method when that is usedinsteadofanormalconstructor.Thesedependencieswillbeprovidedtotheobject,whentheobjectisactuallycreated.

3. Eachpropertyorconstructorargument iseitheranactualdefinitionof the

Page 100: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

CircularDependenciesIf you are using predominantlyconstructor injection it is possibletowriteandconfigureyourclassesand objects such that anunresolvable circular dependencyscenarioiscreated.Consider the scenario where youhave class A, which requires aninstanceof classB tobeprovidedviaconstructor injection,andclassB, which requires an instance ofclass A to be provided viaconstructor injection. If youconfigure object for classesA andBtobeinjectedintoeachother,theSpring IoC container will detectthis circular reference at runtime,and throw a

valuetoset,orareferencetoanotherobjectinthecontainer.

4. Eachpropertyorconstructorargumentwhichisavaluemustbeabletobeconverted from whatever format it was specified in, to the actualSystem.Type of that property or constructor argument. By defaultSpring.NET can convert a value supplied in string format to all built-intypes, such as int, long, string, bool, etc. Spring.NET usesTypeConverter definitions to be able to convert string values toother, arbitrary types. Refer to Section 6.3, “Type conversion” for moreinformation regarding type conversion, and how you can design yourclassestobeconvertiblebySpring.NET.

TheSpringcontainervalidatestheconfigurationofeachobjectasthecontaineriscreated,includingthevalidationthatpropertieswhichareobjectreferencesareactuallyreferringtovalidobject.However,theobjectpropertiesthemselvesarenot set until the object is actually created. For those object that defined assingletons and set to be pre-instantiated (such as singleton object in anIApplicationContext),creationhappensatthetimethatthecontaineris created, but otherwise this is only when the object is requested. When anobject actually has to be created, this will potentially cause a graph of otherobjects to be created, as its dependencies and its dependencies' dependencies(andsoon)arecreatedandassigned.YoucangenerallytrustSpring.NETtodotheright thing. It will detect configurationissues, such as references to non-existentobjectdefinitionsandcirculardependencies,at container load-time. It will actually setproperties and resolve dependencies as lateas possible, which is when the object isactually created. This means that a Springcontainer which has loaded correctly canlatergenerateanexceptionwhenyourequestanobject if there is aproblemcreating thatobjectoroneofitsdependencies.Thiscouldhappeniftheobjectthrowsanexceptionasaresult of a missing or invalid property, forexample. This potentially delayed visibilityof some configuration issues is why

Page 101: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ObjectCurrentlyInCreationException

Onepossible solution to this issueis to edit the source codeof someofyourclassestobeconfiguredviasetters instead of via constructors.Another solution is not to useconstructor injection and stick tosetter injection only. In otherwords,whileitshouldgenerallybeavoided in all but the rarest ofcircumstances, it is possible toconfigure circular dependencieswithsetterinjection.Unlike the typical case (with nocircular dependencies), a circulardependency between objectA andobject B will force one of theobjectstobeinjectedintotheotherpriortobeingfullyinitializeditself(aclassicchicken/eggscenario).

IApplicationContext by defaultpre-instantiatessingletonobjects.Atthecostofsomeupfront timeandmemory to createtheseobjectsbeforetheyareactuallyneeded,youfindoutaboutconfigurationissueswhenthe IApplicationContext iscreated, not later. If youwish, you can stilloverridethisdefaultbehaviorandsetanyofthese singleton objects to lazy-load (not bepreinstantiated)Ifnocirculardependenciesareinvolved(seesidebar for a discussion of circulardependencies), when one or morecollaboratingobjects are being injected intoadependentobject,eachcollaboratingobjectis totally configured prior to being passed(viaoneof theDIflavors) to thedependentobject.ThismeansthatifobjectAhasadependencyonobjectB,theSpringIoCcontainerwilltotallyconfigureobjectBpriortoinvokingthesettermethodonobject A; you can read 'totally configure' to mean that the object will beinstantiated(ifnot a pre-instantiated singleton), all of its dependencieswill beset,andtherelevantlifecyclemethods(suchasaconfiguredinitmethodortheIIntializingObjectcallbackmethod)willallbeinvoked.

5.3.1.3.SomeexamplesFirst, anexampleofusingXML-basedconfigurationmetadata for setter-basedDI.FindbelowasmallpartofaSpringXMLconfigurationfilespecifyingsomeobjectdefinitions.

<objectid="exampleObject"type="Examples.ExampleObject,ExamplesLibrary"

<!--setterinjectionusingtherefattribute-->

<propertyname="objectOne"ref="anotherExampleObject"/>

<propertyname="objectTwo"ref="yetAnotherObject"/>

<propertyname="IntegerProperty"value="1"/>

</object>

Page 102: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="anotherExampleObject"type="Examples.AnotherObject,ExamplesLibrary"

<objectid="yetAnotherObject"type="Examples.YetAnotherObject,ExamplesLibrary"

[C#]

publicclassExampleObject

{

privateAnotherObjectobjectOne;

privateYetAnotherObjectobjectTwo;

privateinti;

publicAnotherObjectObjectOne

{

set{this.objectOne=value;}

}

publicYetAnotherObjectObjectTwo

{

set{this.objectTwo=value;}

}

publicintIntegerProperty

{

set{this.i=value;}

}

}

As you can see, setters have been declared to match against the propertiesspecifiedintheXMLfile.Findbelowanexampleofusingconstructor-basedDI.

<objectid="exampleObject"type="Examples.ExampleObject,ExamplesLibrary"

<constructor-argname="objectOne"ref="anotherExampleObject"

<constructor-argname="objectTwo"ref="yetAnotherObject"

<constructor-argname="IntegerProperty"value="1"/>

</object>

<objectid="anotherExampleObject"type="Examples.AnotherObject,ExamplesLibrary"

<objectid="yetAnotherObject"type="Examples.YetAnotherObject,ExamplesLibrary"

[VisualBasic.NET]

PublicClassExampleObject

Page 103: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PrivatemyObjectOneAsAnotherObject

PrivatemyObjectTwoAsYetAnotherObject

PrivateiAsInteger

PublicSubNew(

anotherObjectasAnotherObject,

yetAnotherObjectasYetAnotherObject,

iasInteger)

myObjectOne=anotherObject

myObjectTwo=yetAnotherObject

Me.i=i

EndSub

EndClass

Asyoucansee,theconstructorargumentsspecifiedintheobjectdefinitionwillbeusedtopassinasargumentstotheconstructoroftheExampleObject.Nowconsider a variant of thiswhere insteadof using a constructor,Spring istoldtocallastaticfactorymethodtoreturnaninstanceoftheobject

<objectid="exampleObject"type="Examples.ExampleFactoryMethodObject,ExamplesLibrary"

factory-method="CreateInstance">

<constructor-argname="objectOne"ref="anotherExampleObject"

<constructor-argname="objectTwo"ref="yetAnotherObject"

<constructor-argname="intProp"value="1"/>

</object>

<objectid="anotherExampleObject"type="Examples.AnotherObject,ExamplesLibrary"

<objectid="yetAnotherObject"type="Examples.YetAnotherObject,ExamplesLibrary"

[C#]

publicclassExampleFactoryMethodObject

{

privateAnotherObjectobjectOne;

privateYetAnotherObjectobjectTwo;

privateinti;

//aprivateconstructor

privateExampleFactoryMethodObject()

{

}

Page 104: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicstaticExampleFactoryMethodObjectCreateInstance(AnotherObjectobjectOne,

YetAnotherObjectobjectTwo,

intintProp)

{

ExampleFactoryMethodObjectfmo=newExampleFactoryMethodObject();

fmo.AnotherObject=objectOne;

fmo.YetAnotherObject=objectTwo;

fmo.IntegerProperty=intProp;

returnfmo;

}

//Propertydefinitions

}

Notethatargumentstothestaticfactorymethodaresuppliedviaconstructor-argelements, exactly the same as if a constructor had actually been used. Theseargumentsareoptional.Also,itisimportanttorealizethatthetypeoftheclassbeingreturnedbythefactorymethoddoesnothavetobeofthesametypeastheclasswhichcontainsthestaticfactorymethod,althoughinthisexampleitis.Aninstance(non-static)factorymethod,mentionedpreviously,wouldbeusedinanessentially identical fashion (aside from the use of the factory-object attributeinsteadofthetypeattribute),sowillnotbedetailedhere.NotethatSetterInjectionandConstructorInjectionarenotmutuallyexclusive.Itisperfectlyreasonabletousebothforasingleobjectdefinition,ascanbeseeninthefollowingexample:

<objectid="exampleObject"type="Examples.MixedIocObject,ExamplesLibrary"

<constructor-argname="objectOne"ref="anotherExampleObject"

<propertyname="objectTwo"ref="yetAnotherObject"/>

<propertyname="IntegerProperty"value="1"/>

</object>

<objectid="anotherExampleObject"type="Examples.AnotherObject,ExamplesLibrary"

<objectid="yetAnotherObject"type="Examples.YetAnotherObject,ExamplesLibrary"

[C#]

publicclassMixedIocObject

{

Page 105: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

privateAnotherObjectobjectOne;

privateYetAnotherObjectobjectTwo;

privateinti;

publicMixedIocObject(AnotherObjectobj)

{

this.objectOne=obj;

}

publicYetAnotherObjectObjectTwo

{

set{this.objectTwo=value;}

}

publicintIntegerProperty

{

set{this.i=value;}

}

}

5.3.2.DependenciesandconfigurationindetailAs mentioned in the previous section, object properties and constructorarguments can be defined as either references to other managed objects(collaborators), or values defined inline. Spring's XML-based configurationmetadatasupportsanumberofsub-element typeswithinits<property/>and<constructor-arg/>elementsforthispurpose.a

5.3.2.1.Straightvalues(primitives,strings,etc.)The<value/> element specifies a property or constructor argument as ahuman-readable string representation. As mentioned previously,TypeConverter instances areused to convert these string values from aSystem.String to the actual property or argument type. CustomTypeConverter implementations in theSpring.Objects.TypeConverters namespace are used toaugment the functionality offered by the .NET BCL's defaultTypeConverterimplementations.

In the following example, we use a SqlConnection from the

Page 106: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

System.Data.SqlClient namespace of the BCL. This class (likemanyotherexistingclasses)caneasilybeusedinaSpring.NETobjectfactory,as it offers a convenient public property for configuration of itsConnectionStringproperty.

<objectsxmlns="http://www.springframework.net">

<objectid="myConnection"type="System.Data.SqlClient.SqlConnection"

<!--resultsinacalltothesetteroftheConnectionStringproperty-->

<property

name="ConnectionString"

value="IntegratedSecurity=SSPI;database=northwind;server=mySQLServer"

</object>

</objects>

5.3.2.1.1.Theidrefelement

Anidrefelementissimplyashorthandanderror-proofwaytosetapropertytotheStringidornameofanotherobjectinthecontainer.

<objectid="theTargetObject"type="...">

...

</object>

<objectid="theClientObject"type="...">

<propertyname="targetName">

<idrefobject="theTargetObject"/>

</property>

</object>

Thisisexactlyequivalentatruntimetothefollowingfragment:

<objectid="theTargetObject"type="...">

...

</object>

<objectid="theClientObject"type="...">

<propertyname="targetName"value="theTargetObject"/>

</object>

Page 107: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The main reason the first form is preferable to the second is that using theidreftagwillallowSpring.NETtovalidateatdeploymenttimethattheotherobject actually exists. In the second variation, the class that is having itstargetName property injected is forced to do its own validation, and that willonly happenwhen that class is actually instantiated by the container, possiblylongafterthecontainerisactuallyupandrunning.Additionally,iftheobjectbeingreferredtoisinthesameactualXMLfile,andtheobjectnameistheobjectid,thelocalattributemaybeused,whichwillallow theXML parser itself to validate the object name even earlier, at parsetime.

<propertyname="targetName">

<idreflocal="theTargetObject"/>

</property>

5.3.2.1.2.WhitespaceHandling

Usually all leading and trailing whitespaces are trimmed from a <value />element'stext.Insomecasesit isnecessarytomaintainwhitespacesexactlyastheyarewrittenintothexmlelement.Theparserdoesunderstandthexml:spaceattributeinthiscase:

<propertyname="myProp">

<valuexml:space="preserve">&#x000a;&#x000d;&#x0009;</value>

</property>

The above configurationwill result in the string " \n\r\t".Note, that you don'thavetoexplicitelyspecifiythe'xml'namespaceontopofyourconfiguration.

5.3.2.2.ReferringtocollaboratingobjectsTherefelementisthefinalelementallowedinsideapropertydefinitionelement.Itisusedtosetthevalueofthespecifiedpropertytobeareferencetoanotherobjectmanagedbythecontainer,acollaborator,sotospeak.Asyousawin the previous example to set collection properties, we used theSqlConnection instance from the initial example as a collaborator and

Page 108: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

specified itusinga<refobject/>element.Asmentioned inaprevious section,the referred-to object is considered to be a dependency of the object who'sproperty is being set, and will be initialized on demand as needed (if it is asingletonobjectitmayhavealreadybeeninitializedbythecontainer)beforetheproperty is set.All referencesareultimately justa reference toanother object,but there are 3 variations on how the id/name of the other object may bespecified,whichdetermineshowscopingandvalidationishandled.Specifyingthetargetobjectbyusingtheobjectattributeofthereftagisthemostgeneral form,andwillallowcreatinga reference toanyobject in thesameIObjectFactory/IApplicationContext(whetherornotin the same XML file), or parent IObjectFactory /IApplicationContext. The value of theobject attributemay bethesameaseithertheidattributeofthetargetobject,oroneofthevaluesinthenameattributeofthetargetobject.

<refobject="someObject"/>

SpecifyingthetargetobjectbyusingthelocalattributeleveragestheabilityoftheXMLparsertovalidateXMLidreferenceswithinthesamefile.Thevalueof thelocal attribute must be the same as theid attribute of the targetobject.TheXMLparserwill issueanerror ifnomatchingelement is found inthesamefile.Assuch,usingthelocalvariantisthebestchoice(inordertoknowabouterrorsareearlyaspossible)ifthetargetobjectisinthesameXMLfile.

<reflocal="someObject"/>

Specifyingthetargetobjectbyusingtheparentattributeallowsareferenceto be created to an object that is in a parent IObjectFactory(orIApplicationContext) of the currentIObjectFactory (orIApplicationContext).Thevalueof theparent attributemaybethesameaseithertheidattributeofthetargetobject,oroneofthevaluesinthename attribute of the target object, and the target objectmust be in a parentIObjectFactory orIApplicationContext of the current one.Themainuseofthisobjectreferencevariantiswhenthereisaneedtowrapanexistingobjectinaparentcontextwithsomesortofproxy(whichmayhavethe

Page 109: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

samenameastheparent),andneedstheoriginalobjectsoitmaywrapit.

<refparent="someObject"/>

5.3.2.3.InlineobjectsAnobject element inside theproperty element is used to define anobject value inline, instead of referring to an object defined elsewhere in thecontainer. The inline object definition does not need to have any id or namedefined(indeed,ifanyaredefined,theywillbeignored).

<objectid="outer"type="...">

<!--Insteadofusingareferencetotarget,justuseaninnerobject-->

<propertyname="target">

<objecttype="ExampleApp.Person,ExampleApp">

<propertyname="name"value="Tony"/>

<propertyname="age"value="51"/>

</object>

</property>

</object>

5.3.2.4.SettingcollectionvaluesThe list, set, name-values and dictionary elements allowproperties and arguments of the type IList, ISet,NameValueCollection and IDictionary, respectively, to bedefinedandset.

<objectsxmlns="http://www.springframework.net">

<objectid="moreComplexObject"type="Example.ComplexObject"

<!--

resultsinacalltothesetteroftheSomeList(System.Collections.IList)property

-->

<propertyname="SomeList">

<list>

<value>alistelementfollowedbyareference</value>

<refobject="myConnection"/>

Page 110: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</list>

</property>

<!--

resultsinacalltothesetteroftheSomeDictionary(System.Collections.IDictionary)property

-->

<propertyname="SomeDictionary">

<dictionary>

<entrykey="astring=>stringentry"value="justsomestring"

<entrykey-ref="myKeyObject"value-ref="myConnection"

</dictionary>

</property>

<!--

resultsinacalltothesetteroftheSomeNameValue(System.Collections.NameValueCollection)property

-->

<propertyname="SomeNameValue">

<name-values>

<addkey="HarryPotter"value="Themagicproperty"

<addkey="JerrySeinfeld"value="Thefunny(toAmericans)property"

</name-values>

</property>

<!--

resultsinacalltothesetteroftheSomeSet(Spring.Collections.ISet)property

-->

<propertyname="someSet">

<set>

<value>justsomestring</value>

<refobject="myConnection"/>

</set>

</property>

</object>

</objects>

ManyclassesintheBCLexposeonlyread-onlypropertiesforcollectionclasses.When Spring.NET encounters a read-only collection, it will configure thecollection by using the getter property to obtain a reference to the collectionclassandthenproceedtoaddtheadditionalelementstotheexistingcollection.Thisresultsinanadditivebehaviorforcollectionpropertiesthatareexposedinthismanner.NotethatthevalueofaDictionaryentry,orasetvalue,canalsoagainbeanyoftheelements:

Page 111: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

(object|ref|idref|expression|list|set|dictionary|

name-values|value|null)

TheshortcutformsforvalueandreferencesareusefultoreduceXMLverbositywhensettingcollectionproperties.SeeSection5.3.2.8,“Valueandrefshortcutforms”formoreinformation.

5.3.2.5.SettinggenericcollectionvaluesSpring supports setting values for classes that expose properties based on thegeneric collection interfaces IList<T> and IDictionary<TKey,TValue>.The typeparameter for thesecollections is specifiedbyusing theXML attributeelement-type forIList<T> and the XML attributeskey-type and value-type for IDictionary<TKey,

TValue>. The values of the collection are automaticaly converted from astringtotheappropriatetype.Ifyouareusingyourownuser-definedtypeasagenerictypeparameteryouwilllikelyneedtoregisteracustomtypeconverter.RefertoSection5.5,“Typeconversion”formoreinformation.TheimplementationsofIList<T>andIDictionary<TKey,TValue> that iscreatedareSystem.Collections.Generic.List andSystem.Collections.Generic.Dictionary.Thefollowingclass representsa lottery ticketanddemonstrateshowtoset thevaluesofagenericIList.

publicclassLotteryTicket{

List<int>list;

DateTimedate;

publicList<int>Numbers{

set{list=value;}

get{returnlist;}

}

publicDateTimeDate{

get{returndate;}

set{date=value;}

Page 112: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

}

TheXMLfragmentthatcanbeusedtoconfigurethisclassisshownbelow

<objectid="MyLotteryTicket"type="GenericsPlay.Lottery.LotteryTicket,GenericsPlay"

<propertyname="Numbers">

<listelement-type="int">

<value>11</value>

<value>21</value>

<value>23</value>

<value>34</value>

<value>36</value>

<value>38</value>

</list>

</property>

<propertyname="Date"value="4/16/2006"/>

</object>

The followingshows thedefinitionofamorecomplexclass thatdemonstratestheuseofgenericsusingtheSpring.Expressions.IExpressioninterfaceasthegenerictypeparameterfortheIListelement-typeandthevalue-typefor IDictionary.Spring.Expressions.IExpression has anassociated type converter,Spring.Objects.TypeConverters.ExpressionConverter

thatisalreadypre-registeredwithSpring.

publicclassGenericExpressionHolder

{

privateSystem.Collections.Generic.IList<IExpression>expressionsList;

privateSystem.Collections.Generic.IDictionary<string

publicSystem.Collections.Generic.IList<IExpression>ExpressionsList

{

set{this.expressionsList=value;}

}

publicSystem.Collections.Generic.IDictionary<string

{

Page 113: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

set{this.expressionsDictionary=value;}

}

publicIExpressionthis[intindex]

{

get

{

returnthis.expressionsList[index];

}

}

publicIExpressionthis[stringkey]

{

get{returnthis.expressionsDictionary[key];}

}

}

AnexampleXMLconfigurationofthisclassisshownbelow

<objectid="genericExpressionHolder"

type="Spring.Objects.Factory.Xml.GenericExpressionHolder,

Spring.Core.Tests">

<propertyname="ExpressionsList">

<listelement-type="Spring.Expressions.IExpression,Spring.Core"

<value>1+1</value>

<value>date('1856-7-9').Month</value>

<value>'NikolaTesla'.ToUpper()</value>

<value>DateTime.Today>date('1856-7-9')</value>

</list>

</property>

<propertyname="ExpressionsDictionary">

<dictionarykey-type="string"value-type="Spring.Expressions.IExpression,Spring.Core"

<entrykey="zero">

<value>1+1</value>

</entry>

<entrykey="one">

<value>date('1856-7-9').Month</value>

</entry>

<entrykey="two">

<value>'NikolaTesla'.ToUpper()</value>

</entry>

<entrykey="three">

Page 114: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<value>DateTime.Today>date('1856-7-9')</value>

</entry>

</dictionary>

</property>

</object>

5.3.2.6.SettingnullvaluesThe <null> element is used to handle null values. Spring.NET treatsemptyargumentsforpropertiesandconstructorargumentsasemptystringinstances.Thefollowingconfigurationdemonstratesthisbehaviour...

<objecttype="Examples.ExampleObject,ExamplesLibrary">

<propertyname="email"><value></value></property>

<!--equivalent,usingvalueattributeasopposedtonested<value/>element...

<propertyname="email"value=""/>

</object>

This results in theemailpropertybeing set to theempty stringvalue(""), inmuchthesamewayascanbeseeninthefollowingsnippetofC#code...

exampleObject.Email="";

Thespecial<null/>elementmaybeusedtoindicateanullvalue;towit...

<objecttype="Examples.ExampleObject,ExamplesLibrary">

<propertyname="email"><null/></property>

</object>

This results in theemailpropertybeingset tonull, again inmuch the samewayascanbeseeninthefollowingsnippetofC#code...

exampleObject.Email=null;

5.3.2.7.SettingindexerpropertiesAnindexerletsyousetandgetvaluesfromacollectionusingafamiliarbracket

Page 115: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

[] notation. Spring's XML configuration supports the setting of indexerproperties. Overloaded indexers as well as multiparameter indexers are alsosupported. The property expression parser described in Chapter 11, ExpressionEvaluation isused toperformthe typeconversionof the indexernameargumentfromastringintheXMLfiletoamatchingtargettype.Asanexampleconsiderthefollowingclass

publicclassPerson

{

privateIListfavoriteNames=newArrayList();

privateIDictionaryproperties=newHashtable();

publicPerson()

{

favoriteNames.Add("p1");

favoriteNames.Add("p2");

}

publicstringthis[intindex]

{

get{return(string)favoriteNames[index];}

set{favoriteNames[index]=value;}

}

publicstringthis[stringkeyName]

{

get{return(string)properties[keyName];}

set{properties.Add(keyName,value);}

}

}

TheXMLconfigurationsnippettopopulatethisobjectwithdataisshownbelow

<objectid="person"type="Test.Objects.Person,Test.Objects"

<propertyname="[0]"value="MasterShake"/>

<propertyname="['one']"value="uno"/>

</object>

Note

Page 116: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheuseofthepropertyexpressionparserinRelease1.0.2changedhowyouconfigureindexerproperties.Thefollowingsectiondescribesthisusage.Theolderstyleconfigurationusesthefollowingsyntax

<objectid="objectWithIndexer"type="Spring.Objects.TestObject,Spring.Core.Tests"

<propertyname="Item[0]"value="mystringvalue"/>

</object>

Youcanalsochangethenameusedtoidentifytheindexerbyadorningyourindexermethoddeclarationwiththeattribute[IndexerName("MyItemName")].Youwouldthenusethestringtoconfigurethefirstelementofthatindexer.Therearesomelimitationstobeawareintheolderindexerconfiguration.Theindexercanonlybeofasingleparameterthatisconvertiblefromastringtotheindexerparametertype.Also,multipleindexersarenotsupported.YoucangetaroundthatlastlimitationcurrentlyifyouusetheIndexerNameattribute.

5.3.2.8.ValueandrefshortcutformsThere are also some shortcut forms that are less verbose than using the fullvalueandrefelements.Theproperty,constructor-arg,andentryelementsallsupportavalueattributewhichmaybeusedinsteadofembeddingafullvalueelement.Therefore,thefollowing:

<propertyname="myProperty">

<value>hello</value>

</property>

<constructor-arg>

<value>hello</value>

</constructor-arg>

<entrykey="myKey">

<value>hello</value>

</entry>

areequivalentto:

<propertyname="myProperty"value="hello"/>

<constructor-argvalue="hello"/>

Page 117: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<entrykey="myKey"value="hello"/>

Ingeneral,whentypingdefinitionsbyhand,youwillprobablyprefertousethelessverboseshortcutform.The property and constructor-arg elements support a similarshortcutrefattributewhichmaybeusedinsteadofafullnestedrefelement.Therefore,thefollowing...

<propertyname="myProperty">

<refobject="anotherObject"/>

</property>

<constructor-argindex="0">

<refobject="anotherObject"/>

</constructor-arg>

isequivalentto...

<propertyname="myProperty"ref="anotherObject"/>

<constructor-argindex="0"ref="anotherObject"/>

Note

Theshortcutformisequivalenttoa<refobject="xxx">element;thereisnoshortcutforeitherthe<reflocal="xxx">or<refparent="xxx">elements.Foralocalorparentref,youmuststillusethelongform.

Finally,theentryelementallowsashortcutformthespecifythekeyand/orvalueof a dictionary, in the form of key/key-ref and value/value-ref attributes.Therefore,thefollowing

<entry>

<key>

<refobject="MyKeyObject"/>

</key>

<refobject="MyValueObject"/>

</entry>

Page 118: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Isequivalentto:

<entrykey-ref="MyKeyObject"value-ref="MyValueObject"/>

Asmentioned previously, the equivalence is to<refobject="xxx">andnotthelocalorparentformsofobjectreferences.

5.3.2.9.CompoundpropertynamesandSpringexpressionreferencesNote thatcompoundornestedpropertynamesareperfectly legalwhensettingobject properties. Property names are interpreted using the Spring ExpressionLanguage (SpEL) and therefore can leverage its many features to set propertynames.Forexample, in thisobjectdefinitionasimplenestedpropertyname isconfigured

<objectid="foo"type="Spring.Foo,Spring.Foo">

<propertyname="bar.baz.name"value="Bingo"/>

</object>

Asanexampleofsomealternativewaystodeclarethepropertyname,youcanuseSpEL'ssupportfor indexers toconfigureaDictionarykeyvaluepairasanalternative to the nested<dictionary> element. More importantly, youcanuse the 'expression'element torefer toaSpringexpressionas thevalueoftheproperty.Simpleexamplesofthisareshownbelow

<propertyname=“minValue”expression=“int.MinValue”/>

<propertyname=“weekFromToday”expression="DateTime.Today+7"

UsingSpEL'ssupport formethodevaluation,youcaneasilycall staticmethodonvarioushelperclassesinyourXMLconfiguraiton.

5.3.3.DeclarativeEventListenerRegistrationInC#events arebuilt right into the language thanks to theevent keyword.Underthescenes,eventsareessentiallyashorthandnotationfordelegateswithsomeadditionalguidelinesastowhattheparameterstoaneventhandlermethodshould be (i.e. a sender System.Object and an

Page 119: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

System.EventArgsobject).

publicclassEventSource

publiceventEventHandlerClick;

Inuse,.NETeventsarecombinedwithoneormoreeventhandlermethods.Eachhandler method is programmatically added, or removed, from the event andcorrespondstoanobject'smethodthatshouldbeinvokedwhenaparticulareventoccurs.Whenmorethanonehandlermethodisaddedtoanevent,theneachoftheregisteredmethodswillbeinvokedinturnwhenaneventoccurs.

TestObjectsource=newTestObject();

TestEventHandlereventListener1=newTestEventHandler();

TestEventHandlereventListener2=newTestEventHandler();

source.Click+=eventListener1.HandleEvent;//Addingthefirsteventhandlermethodtotheevent

source.Click+=eventListener2.HandleEvent;//Addingasecondeventhandlermethodtotheevent

source.OnClick();//FirsteventListener1.HandleEventisinvoked,theneventListener2.HandleEvent

WhenOnClick()isinvoked,theeventisfired.

publicvoidOnClick()

{

if(Click!=null)

{

Click(this,EventArgs.Empty);//Firetheeventofftotheregisteredhandlermethods

}

}

Oneofthenotsonicethingsaboutusingeventsisthat,withoutemployinglatebinding, you declare the objects that are registered with a particular eventprogrammatically. Spring .NET offers a way to declaratively register yourhandler methods with particular events using the <listener> elementinsideyour<object>elements.

5.3.3.1.DeclarativeeventhandlersRather than having to specifically declare in your code that you are adding a

Page 120: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

methodtobeinvokedonanevent,usingthe<listener>elementyoucanregister a plain object'smethodswith the corresponding event declaratively inyourapplicationconfiguration.Usingthelistenerelementyoucan:

Configureamethodtobeinvokedwhenaneventisfired.

Registeracollectionofhandlermethodsbasedonaregularexpression.

Registerahandlermethodagainstaneventnamethatcontainsaregularexpression.

5.3.3.2.ConfiguringamethodtobeinvokedwhenaneventisfiredThe same event registration in the example above can be achieved usingconfigurationusingthe<listener>element.

<objectid="eventListener1"type="SpringdotNETEventsExample.TestEventHandler,SpringdotNETEventsExample"

<!--wireduptoaneventexposedonaninstance-->

<listenerevent="Click"method="HandleEvent">

<refobject="source"/>

</listener>

</object>

<objectid="eventListener2"type="SpringdotNETEventsExample.TestEventHandler,SpringdotNETEventsExample"

<!--wireduptoaneventexposedonaninstance-->

<listenerevent="Click"method="HandleEvent">

<refobject="source"/>

</listener>

</object>

InthiscasethetwodifferentobjectswillhavetheirHandleEventmethodinvoked,as indicatedexplicitlyusing themethod attribute,whenaClickevent,asspecifiedbytheeventattribute,istriggeredontheobjectreferredtobytherefelement.

5.3.3.3.RegisteringacollectionofhandlermethodsbasedonaregularexpressionRegularexpressionscanbeemployedtowireupmorethanonehandlermethodtoanobjectthatcontainsoneormoreevents.

Page 121: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="eventListener"type="SpringdotNETEventsExample.TestEventHandler,SpringdotNETEventsExample"

<listenermethod="Handle.+">

<refobject="source"/>

</listener>

</object>

Hereall theeventListener's handlermethods that beginwith 'Handle',andthathavethecorrespondingtwoparametersofaSystem.ObjectandaSystem.EventArgs, will be registered against all events exposed bythesourceobject.You can also use the name of the event in regular expression to filter yourhandlermethodsbasedonthetypeofeventtriggered.

<objectid="eventListener"type="SpringdotNETEventsExample.TestEventHandler,SpringdotNETEventsExample"

<!--FortheClickevent,theHandleClickhandlermethodwillbeinvoked.-->

<listenermethod="Handle${event}">

<refobject="source"/>

</listener>

</object>

5.3.3.4. Registering a handler method against an eventnamethatcontainsaregularexpressionFinally, you can register an object's handler methods against a selection ofevents,filteringbasedontheirnameusingaregularexpression.

<objectid="eventListener"type="SpringdotNETEventsExample.TestEventHandler,SpringdotNETEventsExample"

<listenermethod="HandleEvent"event="Cl.+">

<refobject="source"/>

</listener>

</object>

In thisexample theeventListener'sHandleEventhandlermethodwillbeinvokedforanyeventthatbeginswith'Cl'.

5.3.4.Usingdepends-onFor most situations, the fact that an object is a dependency of another is

Page 122: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

expressed by the fact that one object is set as a property of another. This istypically accomploished with the <ref/> element in XML-basedconfiguration metadata. For the relatively infrequent situations wheredependencies between objects are less direct (for example, when a staticinitializerinaclassneedstobetriggered)the'depends-on'attributemaybeused to explicitly force one ormore objects to be initialized before the objectusing this element is initialized. Find below an example of using the'depends-on'attributetoexpressadependencyonasingleobject..

<objectid="objectOne"type="Examples.ExampleObject,ExamplesLibrary"

<propertyname="manager"ref="manager"/>

</object>

<objectid="manager"type="Examples.ManagerObject,ExamplesLibrary"

Ifyouneedtoexpressadependencyonmultipleobjects,youcansupplyalistofobject names as the value of the 'depends-on' attribute, with commas,whitespaceandsemicolonsallvaliddelimiters,likeso:

<objectid="objectOne"type="Examples.ExampleObject,ExamplesLibrary"

<propertyname="manager"ref="manager"/>

</object>

<objectid="manager"type="Examples.ManagerObject,ExamplesLibrary"

<objectid="accountDao"type="Examples.AdoAccountDao,ExamplesLibrary"

Note

The'depends-on'attributeandpropertyisusednotonlytospecifyaninitializationtimedependency,butalsotospecifythecorrespondingdestroytimedependency(inthecaseofsingletonobjectsonly).Dependentobjectsthataredefinedinthe'depends-on'attributewillbedestroyedaftertherelevantobjectitselfisdestroyed.Thisthusallowsyoutocontrolshutdownordertoo

5.3.5.Lazily-instantiatedobjectsThedefaultbehaviorforIApplicationContextimplementationsistoeagerly pre-instantiate all singleton objects at startup. Pre-instantiation means

Page 123: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

thatanIApplicationContextwilleagerlycreateandconfigureallofitssingletonobjectsaspartofitsinitializationprocess.Generallythisisagoodthing,becauseitmeansthatanyerrorsintheconfigurationorinthesurroundingenvironmentwill be discovered immediately (as opposed to possibly hours orevendaysdowntheline).However,therearetimeswhenthisbehaviorisnotwhatiswanted.Ifyoudonotwant a singleton object to be pre-instantiated when using anIApplicationContext,youcanselectivelycontrolthisbymarkinganobject definition as lazy-initialized. A lazily-initialized object indicates to theIoCcontainerwhetherornotanobject instanceshouldbecreatedatstartuporwhenitisfirstrequested.When configuring objects via XML, this lazy loading is controlled by the'lazy-init'attributeonthe<object/>element;forexample:

<objectid="lazy"type="MyCompany.ExpensiveToCreateObject,MyApp"

<objectname="not.lazy"type="MyCompany.AnotherObject,MyApp"

When the above configuration is consumed by anIApplicationContext, the object named 'lazy' will not beeagerlypre-instantiatedwhentheIApplicationContextisstartingup,whereasthe'not.lazy'objectwillbeeagerlypre-instantiated.One thing tounderstand about lazy-initialization is that even though anobjectdefinition may be marked up as being lazy-initialized, if the lazy-initializedobject is thedependencyofasingletonobject that isnot lazy-initialized,whentheIApplicationContext iseagerlypre-instantiatingthesingleton, itwillhavetosatisfyallofthesingletonsdependencies,oneofwhichwillbethelazy-initializedobject!Sodon'tbeconfusedif theIoCcontainercreatesoneoftheobjects thatyouhaveexplicitlyconfiguredas lazy-initializedat startup;allthatmeans is that the lazy-initialized object is being injected into a non-lazy-initializedsingletonobjectelsewhere.Itisalsopossibletocontrollazy-initializationatthecontainerlevelbyusingthe'default-lazy-init'attribute on the <objects/> element; forexample:

<objectsdefault-lazy-init="true">

Page 124: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--noobjectswillbepre-instantiated...-->

</objects>

5.3.6.AutowiringcollaboratorsThe Spring container is able to autowire relationships between collaboratingobjects. This means that it is possible to automatically let Spring resolvecollaborators(otherobjects)foryourobjectbyinspectingthecontentsoftheIoCcontainer..Theautowiringfunctionalityhasfivemodes.Autowiringisspecifiedperobjectandcanthusbeenabledforsomeobject,whileotherobjectswillnotbeautowired.Usingautowiring,itispossibletoreduceoreliminatetheneedtospecifypropertiesorconstructorarguments,thussavingasignificantamountoftyping.WhenusingXML-basedconfigurationmetadata, theautowiremodeforanobjectdefinitionisspecifiedbyusingtheautowireattributeofthe<object/>element.Thefollowingvaluesareallowed:

Table5.3.AutowiringmodesMode Explanation

no

Noautowiringatall.Thisisthedefaultvalueandyouareencouragednottochangethisforlargeapplications,sincespecifyingyourcollaboratorsexplicitlygivesyouafeelingforwhatyou'reactuallydoing(alwaysabonus)andisagreatwayofsomewhatdocumentingthestructureofyoursystem.

byName

Thisoptionwillinspecttheobjectswithinthecontainer,andlookforanobjectnamedexactlythesameasthepropertywhichneedstobeautowired.Forexample,ifyouhaveanobjectdefinitionthatissettoautowirebyname,anditcontainsaMasterproperty,Spring.NETwilllookforanobjectdefinitionnamed

Master,anduseitasthevalueoftheMasterpropertyonyourobjectdefinition.

byType

Thisoptiongivesyoutheabilitytoresolvecollaboratorsbytypeinsteadofbyname.SupposingyouhaveanIObjectDefinitionwithacollaborator

typedSqlConnection,Spring.NETwillsearchtheentireobjectfactoryfor

anobjectdefinitionoftypeSqlConnectionanduseitasthecollaborator.If0(zero)ormorethan1(one)objectdefinitionsofthedesiredtypeexistinthecontainer,afailurewillbereportedandyouwon'tbeabletouseautowiringforthatspecificobject.

constructorThisisanalogoustobyType,butappliestoconstructorarguments.Ifthereisn'texactlyoneobjectoftheconstructorargumenttypeintheobjectfactory,afatalerrorisraised.

autodetect ChoosesconstructororbyTypethroughintrospectionoftheobjectclass.Ifadefaultconstructorisfound,byTypegetsapplied.

Page 125: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Note thatexplicitdependencies inpropertyandconstructor-argsettingsalwaysoverrideautowiring.Pleasealsonotethatitisnotcurrentlypossibletoautowireso-calledsimplepropertiessuchasprimitives,Strings,andTypes(andarraysofsuchsimpleproperties).(Thisisby-designandshouldbeconsideredafeature.)Whenusingeither thebyTypeorconstructorautowiringmode, it ispossibletowirearraysand typed-collections. In suchcases all autowire candidateswithinthe container that match the expected type will be provided to satisfy thedependency.Strongly-typedIDictionariescanevenbeautowirediftheexpectedkey type is string. An autowired IDictionary values will consist of all objectinstances thatmatch theexpected type,and the IDictionary'skeyswill containthecorrespondingobjectnames.Autowirebehaviorcanbecombinedwithdependencychecking,whichwill beperformedafterallautowiringhasbeencompleted.Itisimportanttounderstandthe various advantages and disadvantages of autowiring. Some advantages ofautowiringinclude:

Autowiringcansignificantly reduce thevolumeofconfigurationrequired.However, mechanisms such as the use of a object template (discussedelsewhereinthischapter)arealsovaluableinthisregard.

Autowiringcancauseconfigurationtokeepitselfuptodateasyourobjectsevolve. For example, if you need to add an additional dependency to aclass, that dependency can be satisfied automaticallywithout the need tomodify configuration. Thus there may be a strong case for autowiringduringdevelopment,withoutrulingout theoptionofswitching toexplicitwiringwhenthecodebasebecomesmorestable.

Somedisadvantagesofautowiring:

Autowiringismoremagicalthanexplicitwiring.Although,asnotedintheabovetable,Springiscarefultoavoidguessingincaseofambiguitywhichmight have unexpected results, the relationships between your Spring-managedobjectsarenolongerdocumentedexplicitly.

Wiring information may not be available to tools that may generatedocumentationfromaSpringcontainer.

Another issue to consider when autowiring by type is that multiple object

Page 126: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

definitions within the container may match the type specified by the settermethod or constructor argument to be autowired. For arrays, collections, orIDictionary, this is not necessarily a problem. However for dependencies thatexpectasinglevalue,thisambiguitywillnotbearbitrarilyresolved.Instead,ifnouniqueobjectdefinitionisavailable,anExceptionwillbethrown.Whendecidingwhethertouseautowiring,thereisnowrongorrightanswerinallcases.Adegreeofconsistencyacrossaprojectisbestthough;forexample,ifautowiringisnotusedingeneral, itmightbeconfusing todevelopers touse itjusttowireoneortwoobjectdefinitions.

5.3.7.CheckingfordependenciesSpring.NET has the ability to try to check for the existence of unresolveddependenciesof anobject deployed into the container.These are properties oftheobject,whichdonothaveactualvaluessetforthemintheobjectdefinition,oralternatelyprovidedautomaticallybytheautowiringfeature.Thisfeatureissometimesusefulwhenyouwanttoensurethatallproperties(orallpropertiesofacertaintype)aresetonanobject.Ofcourse,inmanycasesanobjectclasswillhavedefaultvaluesformanyproperties,orsomepropertiesdonot apply to all usage scenarios, so this feature is of limited use.Dependencycheckingcanalsobeenabledanddisabledperobject,justaswiththeautowiringfunctionality. The default dependency checking mode is to not checkdependencies.Dependencycheckingcanbehandledinseveraldifferentmodes.InXML-basedconfiguration,thisisspecifiedviathedependency-checkattributeinanobjectdefinition,whichmayhavethefollowingvalues.

Table5.4.DependencycheckingmodesMode Explanationnone Nodependencychecking.Propertiesoftheobjectwhichhavenovaluespecifiedfor

themaresimplynotset.

simple Dependencycheckingisdoneforprimitivetypesandcollections(thismeanseverythingexceptcollaborators).

object Dependencycheckingisdoneforcollaboratorsonly.

all Dependencycheckingisdoneforcollaborators,primitivetypesandcollections.

Page 127: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.3.8.MethodInjectionFormostusers, themajorityof theobjects in the containerwill be singletons.Whenasingletonobjectneedstocollaboratewith(use)anothersingletonobject,oranon-singletonobjectneedstocollaboratewithanothernon-singletonobject,thetypicalandcommonapproachofhandlingthisdependency(bydefiningoneobject to be a property of the other) is quite adequate. There is however aproblemwhentheobject lifecyclesaredifferent.ConsiderasingletonobjectAwhich needs to use a non-singleton (prototype) object B, perhaps on eachmethod invocationonA.Thecontainerwillonlycreate thesingletonobjectAonce, and thus only get the opportunity to set its properties once.There is noopportunityforthecontainertoprovideobjectAwithanewinstanceofobjectBeverytimeoneisneeded.Onesolutiontothisproblemistoforegosomeinversionofcontrol.ObjectAcanbe made aware of the container by implementing theIObjectFactoryAware interface,anduseprogrammaticmeans to ask thecontainerviaaGetObject("B")callfor(atypicallynew)objectBeverytimeitneedsit.Findbelowanadmittedlysomewhatcontrivedexampleof thisapproach

usingSystem.Collections;

usingSpring.Objects.Factory;

namespaceFiona.Apple

{

publicclassCommandManager:IObjectFactoryAware

{

privateIObjectFactoryobjectFactory;

publicobjectProcess(IDictionarycommandState)

{

//grabanewinstanceoftheappropriateCommand

Commandcommand=CreateCommand();

//setthestateonthe(hopefullybrandnew)Commandinstance

command.State=commandState;

returncommand.Execute();

}

Page 128: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

//theCommandreturnedherecouldbeanimplementationthatexecutesasynchronously,orwhatever

protectedCommandCreateCommand()

{

return(Command)objectFactory.GetObject("command"

}

publicIObjectFactoryObjectFactory

{

set{objectFactory=value;}

}

}

}

Theaboveexampleisgenerallynotadesirablesolutionsincethebusinesscodeis then aware of and coupled to the Spring Framework. Method Injection, asomewhatadvancedfeatureoftheSpringIoCcontainer,allowsthisusecasetobehandledinacleanfashion.

5.3.8.1.LookupMethodInjectionLookup method injection refers to the ability of the container to overrideabstractorconcretemethodsoncontainermanagedobjects, to return theresult of looking up another named object in the container. The lookup willtypicallybeofaprototypeobjectasinthescenariodescribedabove.TheSpringframework implements this method injection by a dynamically generating asubclass overriding the method using the classes in theSystem.Reflection.Emitnamespace.Youcanreadmoreabout themotivationforMethodInjectioninthisblogentry.So if you look at the code from the previous code snipped (theCommandManager class), the Spring container is going to dynamicallyoverride the implementation of the CreateCommand() method. YourCommandManagerclassisnotgoingtohaveanySpringdependencies,ascanbeseeninthisreworkedexamplebelow:

usingSystem.Collections;

namespaceFiona.Apple

{

publicabstractclassCommandManager

Page 129: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

{

publicobjectProcess(IDictionarycommandState)

{

Commandcommand=CreateCommand();

command.State=commandState;

returncommand.Execute();

}

//okay...butwhereistheimplementationofthismethod?

protectedabstractCommandCreateCommand();

}

}

Intheclientclasscontainingthemethodtobeinjected(theCommandManagerinthiscase)themethoddefinitionmustobservethefollowingform:

<public|protected>[abstract]<return-type>TheMethodName(no-arguments);

If the method is abstract, the dynamically-generated subclass willimplement the method. Otherwise, the dynamically-generated subclass willoverride the concrete method defined in the original class. Let's look at anexample:

<!--astatefulobjectdeployedasaprototype(non-singleton)-->

<objectid="command"class="Fiona.Apple.AsyncCommand,Fiona"

<!--injectdependencieshereasrequired-->

</object>

<!--commandProcessorusesastatefulCommandHelpder-->

<objectid="commandManager"type="Fiona.Apple.CommandManager,Fiona"

<lookup-methodname="CreateCommand"object="command"/>

</object>

The object identified as commandManager will call its own methodCreateCommand whenever it needs a new instance of the commandobject. It is important to note that the person deploying the objects must becarefultodeploythecommandobjectasprototype(ifthatisactuallywhatisneeded). If it is deployed as a singleton the same instance of

Page 130: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

singleShotHelperwillbereturnedeachtime!Note that lookupmethodinjectioncanbecombinedwithConstructor Injection(supplyingoptionalconstructorargumentstotheobjectbeingconstructed),andalsowithSetterInjection(settingspropertiesontheobjectbeingconstructed).

5.3.8.2.ArbitrarymethodreplacementAlesscommonlyusefulformofmethodinjectionthanLookupMethodInjectionis the ability to replace arbitrary methods in a managed object with anothermethod implementation.Usersmay safely skip the rest of this section (whichdescribes this somewhat advanced feature), until this functionality is actuallyneeded.InanXmlObjectFactory,thereplaced-methodelementmaybeused to replace an existingmethod implementationwith another.Consider thefollowingclass,withamethodComputeValue,whichwewanttooverride:

publicclassMyValueCalculator{

publicvirtualstringComputeValue(stringinput){

//...somerealcode

}

//...someothermethods

}

A class implementing theSpring.Objects.Factory.Support.IMethodReplacer

interfaceisneededtoprovidethenew(injected)methoddefinition.

///<summary>

///MeanttobeusedtooverridetheexistingComputeValue(string)

///implementationinMyValueCalculator.

///</summary>

publicclassReplacementComputeValue:IMethodReplacer

{

publicobjectImplement(objecttarget,MethodInfomethod,

{

//gettheinputvalue,workwithit,andreturnacomputedresult...

stringvalue=(string)arguments[0];

Page 131: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

//compute...

returnresult;

}

}

The object definition to deploy the original class and specify the methodoverridewouldlooklikethis:

<objectid="myValueCalculator"type="Examples.MyValueCalculator,ExampleAssembly"

<!--arbitrarymethodreplacement-->

<replaced-methodname="ComputeValue"replacer="replacementComputeValue"

<arg-typematch="String"/>

</replaced-method>

</object>

<objectid="replacementComputeValue"type="Examples.ReplacementComputeValue,ExampleAssembly"

One or more contained arg-type elements within the replaced-methodelementmaybeusedtoindicatethemethodsignatureofthemethodbeing overridden. Note that the signature for the arguments is actually onlyneededinthecasethatthemethodisactuallyoverloadedandtherearemultiplevariantswithintheclass.Forconvenience,thetypestringforanargumentmaybea substringof the fullyqualified typename.Forexample,all the followingwouldmatchSystem.String.

System.String

String

Str

Since the number of arguments is often enough to distinguish between eachpossiblechoice,thisshortcutcansavealotoftyping,byjustusingtheshorteststringwhichwillmatchanargument.

5.3.9. Setting a reference using the members of otherobjectsandclasses.This section details those configuration scenarios that involve the setting ofproperties and constructor arguments using the members of other objects andclasses. This kind of scenario is quite common, especially when dealing with

Page 132: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

legacy classes that you cannot (or won't) change to accommodate some ofSpring.NET's conventions... consider the case of a class that has a constructorargument that can only be calculated by going to say, a database. TheMethodInvokingFactoryObjecthandlesexactlythisscenario...itwill allow you to inject the result of an arbitrary method invocation into aconstructor (as an argument) or as the value of a property setter. Similarly,PropertyRetrievingFactoryObject andFieldRetrievingFactoryObject allow you to retrieve valuesfrom another object's property or field value. These classes implement theIFactoryObjectinterfacewhichindicatestoSpring.NETthatthisobjectisitselfafactoryandthefactoriesproduct,notthefactoryitself,iswhatwillbeassociatedwiththeobjectid.FactoryobjectsarediscussedfurtherinSection5.9.3,“CustomizinginstantiationlogicusingIFactoryObjects”

5.3.9.1.Settingareferencetothevalueofproperty.The PropertyRetrievingFactoryObject is anIFactoryObject that addresses the scenario of setting one of thepropertiesand/orconstructorargumentsofanobjecttothevalueofapropertyexposedonanotherobjectorclass.Onecanuseittogetthevalueofanypublicproperty exposed on either an instance or a class (in the case of a propertyexposedonaclass,thepropertymustobviouslybestatic).In the case of a property exposed on an instance, the target object that aPropertyRetrievingFactoryObjectwillevaluatecanbeeitheran object instance specified directly inline or a reference to another arbitraryobject.Inthecaseofastaticpropertyexposedonaclass,thetargetobjectwillbetheclass(the.NETSystem.Type)exposingtheproperty.Theresultofevaluatingthepropertylookupmaythenbeusedinanotherobjectdefinition as a property value or constructor argument. Note that nestedproperties are supported for both instance and class property lookups. TheIFactoryObject is discussedmore generally inSection 5.9.3, “CustomizinginstantiationlogicusingIFactoryObjects”.Here'sanexamplewhereapropertypathisusedagainstanotherobjectinstance.Inthiscase,aninnerobjectdefinitionisusedandthepropertypathisnested,i.e.spouse.age.

Page 133: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectname="person"type="Spring.Objects.TestObject,Spring.Core.Tests"

<propertyname="age"value="20"/>

<propertyname="spouse">

<objecttype="Spring.Objects.TestObject,Spring.Core.Tests"

<propertyname="age"value="21"/>

</object>

</property>

</object>

//willresultin21,whichisthevalueofproperty'spouse.age'ofobject'person'

<objectname="theAge"type="Spring.Objects.Factory.Config.PropertyRetrievingFactoryObject,Spring.Core"

<propertyname="TargetObject"ref="person"/>

<propertyname="TargetProperty"value="spouse.age"/>

</object>

Anexample of using aPropertyRetrievingFactoryObject toevaluateastaticpropertyisshownbelow.

<objectid="cultureAware"

type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject,Spring.Core.Tests"

<propertyname="culture"ref="cultureFactory"/>

</object>

<objectid="cultureFactory"

type="Spring.Objects.Factory.Config.PropertyRetrievingFactoryObject,Spring.Core"

<propertyname="StaticProperty">

<value>System.Globalization.CultureInfo.CurrentUICulture,Mscorlib

</property>

</object>

Similarly,anexampleshowingtheuseofaninstancepropertyisshownbelow.

<objectid="instancePropertyCultureAware"

type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject,Spring.Core.Tests"

<propertyname="Culture"ref="instancePropertyCultureFactory"

</object>

<objectid="instancePropertyCultureFactory"

type="Spring.Objects.Factory.Config.PropertyRetrievingFactoryObject,Spring.Core"

<propertyname="TargetObject"ref="instancePropertyCultureAwareSource"

<propertyname="TargetProperty"value="MyDefaultCulture"/>

Page 134: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</object>

<objectid="instancePropertyCultureAwareSource"

type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject,Spring.Core.Tests"

5.3.9.2.Settingareferencetothevalueoffield.TheFieldRetrievingFactoryObject class addresses much thesame area of concern as thePropertyRetrievingFactoryObject described in the previoussection. However, as its name might suggest, theFieldRetrievingFactoryObjectclassisconcernedwithlookingup the value of a public field exposed on either an instance or a class (andsimilarly,inthecaseofafieldexposedonaclass, thefieldmustobviouslybestatic).The following example demonstrates using aFieldRetrievingFactoryObject to look up the value of a(public,static)fieldexposedonaclass

<objectid="withTypesField"

type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject,Spring.Core.Tests"

<propertyname="Types"ref="emptyTypesFactory"/>

</object>

<objectid="emptyTypesFactory"

type="Spring.Objects.Factory.Config.FieldRetrievingFactoryObject,Spring.Core"

<propertyname="TargetType"value="System.Type,Mscorlib"/>

<propertyname="TargetField"value="EmPTytypeS"/>

</object>

The example in the next section demonstrates the look up of a (public) fieldexposedonanobjectinstance.

<objectid="instanceCultureAware"

type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject,Spring.Core.Tests"

<propertyname="Culture"ref="instanceCultureFactory"/>

</object>

Page 135: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="instanceCultureFactory"

type="Spring.Objects.Factory.Config.FieldRetrievingFactoryObject,Spring.Core"

<propertyname="TargetObject"ref="instanceCultureAwareSource"

<propertyname="TargetField"value="Default"/>

</object>

<objectid="instanceCultureAwareSource"

type="Spring.Objects.Factory.Xml.XmlObjectFactoryTests+MyTestObject,Spring.Core.Tests"

5.3.9.3.Settingapropertyor constructor argument to thereturnvalueofamethodinvocation.TheMethodInvokingFactoryObjectroundsoutthetrioofclassesthat permit the setting of properties and constructor arguments using themembers of other objects and classes. Whereas thePropertyRetrievingFactoryObject andFieldRetrievingFactoryObject classes dealt with simplylookingupandreturningthevalueofpropertyorfieldonanobjectorclass,theMethodInvokingFactoryObjectallowsonetosetaconstructororpropertytothereturnvalueofanarbitrarymethodinvocation,TheMethodInvokingFactoryObjectclasshandlesboththecaseofinvokingan(instance)methodonanotherobjectinthecontainer,andthecaseofastaticmethodcallonanarbitraryclass.Additionally,itissometimesnecessaryto invoke a method just to perform some sort of initialization.... while themechanisms for handling object initialization have yet to be introduced (seeSection 5.6.1.1, “IInitializingObject / init-method”), thesemechanismsdonot permit anyarguments to be passed to any initialization method, and are confined toinvokinganinitializationmethodontheobjectthathasjustbeeninstantiatedbythe container.TheMethodInvokingFactoryObject allows one toinvokeprettymuchanymethodonanyobject (or class in the caseof a staticmethod).The following example (in anXML basedIObjectFactory definition)usestheMethodInvokingFactoryObjectclass toforceacall toastaticfactorymethodpriortotheinstantiationoftheobject...

Page 136: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="force-init"

type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject,Spring.Core"

<propertyname="StaticMethod">

<value>ExampleNamespace.ExampleInitializerClass.Initialize

</property>

</object>

<objectid="myService"depends-on="force-init"/>

NotethatthedefinitionforthemyServiceobjecthasusedthedepends-on attribute to refer to the force-init object, which will force theinitialization of the force-init object first (and thus the calling of itsconfiguredStaticMethod static initializermethod,whenmyServiceis first initialized. Please note that in order to effect this initialization, theMethodInvokingFactoryObject object must be operating insingletonmode(thedefault..seethenextparagraph).Notethatsincethisclassisexpectedtobeusedprimarilyforaccessingfactorymethods,thisfactorydefaultstooperatinginsingletonmode.Assuch,assoonasallofthepropertiesforaMethodInvokingFactoryObjectobject have been set, and if theMethodInvokingFactoryObjectobjectisstillinsingletonmode,themethodwillbeinvokedimmediatelyandthereturnvaluecachedforlateraccess.Thefirstrequestbythecontainerforthefactorytoproduceanobjectwillcausethefactorytoreturnthecachedreturnvalue for the current request (and all subsequent requests). TheIsSingletonpropertymaybeset tofalse, tocausethisfactorytoinvokethe target method each time it is asked for an object (in this case there isobviouslynocachingofthereturnvalue).A static target method may be specified by setting the targetMethodpropertytoastringrepresentingthestaticmethodname,withTargetTypespecifyingtheTypethatthestaticmethodisdefinedon.Alternatively,atargetinstancemethodmaybespecified,bysetting theTargetObjectpropertytothenameofanotherSpring.NETmanagedobjectdefinition(thetargetobject),andtheTargetMethodpropertytothenameofthemethodtocallonthattargetobject.Argumentsforthemethodinvocationmaybespecifiedintwoways(orevenamixtureofboth)... the first involves setting theArguments property to the

Page 137: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

listofargumentsforthemethodthatistobeinvoked.Notethattheorderingofthese arguments is significant... the order of the values passed to theArgumentspropertymustbethesameastheorderoftheargumentsdefinedon themethod signature, including the argumentType. This is shown in theexamplebelow

<objectid="myObject"type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject,Spring.Core"

<propertyname="TargetType"value="Whatever.MyClassFactory,MyAssembly"

<propertyname="TargetMethod"value="GetInstance"/>

<!--theorderingofargumentsissignificant-->

<propertyname="Arguments">

<list>

<value>1st</value>

<value>2nd</value>

<value>and3rdarguments</value>

<!--automaticType-conversionwillbeperformedpriortoinvokingthemethod-->

</list>

</property>

</object>

The second way involves passing an arguments dictionary to theNamedArguments property... this dictionary maps argument names(Strings)toargumentvalues(anyobject).Theargumentnamesarenotcase-sensitive, and order is (obviously) not significant (since dictionaries bydefinitiondonothaveanorder).Thisisshownintheexamplebelow

<objectid="myObject"type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject,Spring.Core"

<propertyname="TargetObject">

<objecttype="Whatever.MyClassFactory,MyAssembly"/>

</property>

<propertyname="TargetMethod"value="Execute"/>

<!--theorderingofnamedargumentsisnotsignificant-->

<propertyname="NamedArguments">

<dictionary>

<entrykey="argumentName"><value>1st</value></entry>

<entrykey="finalArgumentName"><value>and3rdarguments

<entrykey="anotherArgumentName"><value>2nd</value></entry>

</dictionary>

Page 138: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</property>

</object>

The following example shows how useMethodInvokingFactoryObjecttocallaninstancemethod.

<objectid="myMethodObject"type="Whatever.MyClassFactory,MyAssembly"

<objectid="myObject"type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject,Spring.Core"

<propertyname="TargetObject"ref="myMethodObject"/>

<propertyname="TargetMethod"value="Execute"/>

</object>

The above example could also have been written using an anonymous innerobject definition... if the object on which the method is to be invoked is notgoingtobeusedoutsideofthefactoryobjectdefinition,thenthisisthepreferredidiom because it limits the scope of the object onwhich themethod is to beinvokedtothesurroundingfactoryobject.Finally, if you want to use MethodInvokingFactoryObject inconjunctionwithamethodthathasavariable lengthargument list, thenpleasenotethatthevariableargumentsneedtobepassed(andconfigured)asalist.Letusconsiderthefollowingmethoddefinitionthatusestheparamskeyword(inC#),anditsattendant(XML)configuration...

[C#]

publicclassMyClassFactory

{

publicobjectCreateObject(TypeobjectType,paramsstring

{

return...//implementationelidedforclarity...

}

}

<objectid="myMethodObject"type="Whatever.MyClassFactory,MyAssembly"

<objectid="paramsMethodObject"type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject,Spring.Core"

<propertyname="TargetObject"ref="myMethodObject"/>

<propertyname="TargetMethod"value="CreateObject"/>

<propertyname="Arguments">

Page 139: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<list>

<value>System.String</value>

<!--hereisthe'paramsstring[]arguments'-->

<list>

<value>1st</value>

<value>2nd</value>

</list>

</list>

</object>

5.3.10.ProvidedIFactoryObjectimplementationsIn addition to PropertyRetrievingFactoryObject,MethodInvokingFactoryObject, andFieldRetrievingFactoryObjectSpring.NET comeswith otheruseful implementations of the IFactoryObject interface. These arediscussedbelow.

5.3.10.1.CommonloggingThe LogFactoryObject is useful when you would like to share aCommon.Logging log object across a number of classes instead of creating alogging instance per class or class hierarchy. Information on theCommon.Logging project can be found here. In the example shownbelow thesamelogginginstance,withaloggingcategorynameof"DAOLogger",isusedinboththeSimpleAccountDaoandSimpleProductDaodataaccessobjects.

<objectsxmlns="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"

<objectname="daoLogger"type="Spring.Objects.Factory.Config.LogFactoryObject,Spring.Core"

<propertyname="logName"value="DAOLogger"/>

</object>

<objectname="productDao"type="PropPlayApp.SimpleProductDao,PropPlayApp"

<propertyname="maxResults"value="100"/>

<propertyname="dbConnection"ref="myConnection"/>

<propertyname="log"ref="daoLogger"/>

Page 140: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</object>

<objectname="accountDao"type="PropPlayApp.SimpleAccountDao,PropPlayApp"

<propertyname="maxResults"value="100"/>

<propertyname="dbConnection"ref="myConnection"/>

<propertyname="log"ref="daoLogger"/>

</object>

<objectname="myConnection"type="System.Data.Odbc.OdbcConnection,System.Data"

<propertyname="connectionstring"value="dsn=MyDSN;uid=sa;pwd=myPassword;"

</object>

</objects>

Page 141: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.4.ObjectScopesWhenyoucreateaobjectdefinitionwhatyouareactuallycreatingisarecipeforcreatingactualinstancesoftheclassdefinedbythatobjectdefinition.Theideathataobjectdefinitionisarecipeisimportant,becauseitmeansthat,justlikeaclass, you can potentially have many object instances created from a singlerecipe.Youcancontrolnotonlythevariousdependenciesandconfigurationvaluesthataretobepluggedintoanobjectthatiscreatedfromaparticularobjectdefinition,butalsothescopeoftheobjectscreatedfromaparticularobjectdefinition.Thisapproach isverypowerfulandgivesyou the flexibility tochoose thescopeofthe objects you create through configuration instead of having to 'bake in' thescopeofanobjectatthe.NETclasslevel.Objectscanbedefinedtobedeployedinoneof a numberof scopes: out of thebox, theSpringFramework supportsexactly five scopes (ofwhich three are availableonly if you areusing aweb-awareApplicationContext).Thescopessupportedoutoftheboxarelistedbelow:

Table5.5.ObjectScopesScope Descriptionsingleton ScopesasingleobjectdefinitiontoasingleobjectinstanceperSpringIoC

container.

prototype Scopesasingleobjectdefinitiontoanynumberofobjectinstances.

request

ScopesasingleobjectdefinitiontothelifecycleofasingleHTTPrequest;thatiseachandeveryHTTPrequestwillhaveitsowninstanceofanobjectcreatedoffthebackofasingleobjectdefinition.Onlyvalidinthecontextofaweb-awareSpringApplicationContext.

session ScopesasingleobjectdefinitiontothelifecycleofaHTTPSession.Onlyvalidinthecontextofaweb-awareSpringApplicationContext.

application Scopesasingleobjectdefinitiontothelifecycleofawebapplication.Onlyvalidinthecontextofaweb-awareSpringApplicationContext.

5.4.1.Thesingletonscope

Page 142: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

When an object is a singleton, only one shared instance of the objectwill bemanaged, and all requests for objects with an id or ids matching that objectdefinitionwill result in that one specific object instancebeing returnedby theSpringcontainer.Toputitanotherway,whenyoudefineanobjectdefinitionanditisscopedasasingleton, thentheSpringIoCcontainerwillcreateexactlyone instanceof theobjectdefinedbythatobjectdefinition.Thissingleinstancewillbestoredinacache of such singleton object, and all subsequent requests and references forthatnamedobjectwillresultinthecachedobjectbeingreturned.PleasebeawarethatSpring'sconceptofasingletonobjectisquitedifferentfromthe Singleton pattern as defined in the seminal Gang of Four (GoF) patternsbook.TheGoFSingletonhardcodes the scopeofanobject such thatoneandonly one instance of a particular class will ever be created perApplicationDomain.Thescopeof theSpringsingleton isbestdescribedaspercontainerandperobject.ThismeansthatifyoudefineoneobjectforaparticularclassinasingleSpringcontainer,thentheSpringcontainerwillcreateoneandonlyone instance of the class defined by that object definition. The singletonscopeisthedefaultscopeinSpring.TodefineanobjectasasingletoninXML,youwouldwriteconfigurationlikeso:

<objectid="accountService"type="MyApp.DefaultAccountService,MyApp"

<!--thefollowingisequivalent,thoughredundant(singletonscopeisthedefault)-->

<objectid="accountService"type="MyApp.DefaultAccountService,MyApp"

5.4.2.TheprototypescopeThenon-singleton,prototypescopeofobjectdeploymentresultsinthecreationof a newobject instance every time a request for that specific object ismade(that is, it is injected into anotherobject or it is requestedvia aprogrammaticGetObject()methodcallonthecontainer).Asa ruleof thumb,youshouldusethe prototype scope for all objects that are stateful, while the singleton scopeshouldbeusedforstatelessobjects.TodefineanobjectasaprototypeinXML,youwouldwriteconfigurationlikeso:

Page 143: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="exampleObject"type="Examples.ExampleObject,ExamplesLibrary"

There isonequite important thing tobeawareofwhendeployinganobject intheprototype scope, in that the lifecycleof theobject changes slightly.Springdoes not manage the complete lifecycle of a prototype object: the containerinstantiates, configures, decorates and otherwise assembles a prototype object,hands it to the client and then has no further knowledge of that prototypeinstance.Thismeansthatwhileinitializationlifecyclecallbackmethodswillbecalled on all objects regardless of scope, in the case of prototypes, anyconfigured destruction lifecycle callbacks will not be called. It is theresponsibilityoftheclientcodetocleanupprototypescopedobjectsandreleaseany expensive resources that the prototype object(s) are holding onto. (OnepossiblewaytogettheSpringcontainertoreleaseresourcesusedbysingleton-scopedobjectsisthroughtheuseofacustomobjectpostprocessorwhichwouldholdareferencetotheobjectsthatneedtobecleanedup.)Insomerespects,youcanthinkoftheSpringcontainersrolewhentalkingabouta prototype-scoped object as somewhat of a replacement for the C# 'new'operator.All lifecycleaspectspast thatpointhave tobehandledby theclient.(The lifecycle of a object in the Spring container is further described in thesectionentitled“Lifecyclecallbacks”.)

5.4.3. Singleton objecgts with prototype-objectdependenciesWhenusingsingleton-scopedobjectsthathavedependenciesonobjectsthatarescoped as prototypes, please be aware that dependencies are resolved atinstantiationtime.Thismeansthatifyoudependencyinjectaprototype-scopedobject into a singleton-scoped object, a brand new prototype object will beinstantiatedandthendependencyinjectedintothesingletonobject...but that isall. That exact same prototype instance will be the sole instance that is eversuppliedtothesingleton-scopedobject,whichisfineifthatiswhatyouwant.However,sometimeswhatyouactuallywantisforthesingleton-scopedobjecttobeabletoacquireabrandnewinstanceoftheprototype-scopedobjectagainandagainandagainatruntime.Inthatcaseitisnousejustdependencyinjectingaprototype-scopedobjectintoyoursingletonobject,becauseasexplainedabove,thatonlyhappensoncewhentheSpringcontainer is instantiating thesingletonobject and resolving and injecting its dependencies. If you are in the scenario

Page 144: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

whereyouneed toget abrandnew instanceof a (prototype)object again andagain and again at runtime, you are referred to the section entitled “MethodInjection”.

5.4.4.TheotherscopesTheother scopes, namely request, session, and application are for use only inweb-based applications. Please refer to theweb documentation on object scopes formoreinformation.

Page 145: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.5.TypeconversionTypeconvertersareresponsibleforconvertingobjectsfromonetypetoanother.When using the XML based file to configure the IoC container, string basedpropertyvaluesareconvertedtothetargetpropertytype.Springwillrelyonthestandard .NET support for type conversion unless an alternativeTypeConverter is registered for a given type. How to register customTypeConverterswillbedescribedshortly.Asareminder,thestandard.NETtypeconverter support works by associating aTypeConverter attribute withtheclassdefinitionbypassingthetypeoftheconverterasanattributeargument.[3] For example, an abbreviated class definition for the BCL typeFont isshownbelow.

[Serializable,TypeConverter(typeof(FontConverter)),...]

publicsealedclassFont:MarshalByRefObject,ICloneable,ISerializable,IDisposable

{

//Methods

...etc..

}

5.5.1.TypeConversionforEnumerationsThe default type converter for enumerations is theSystem.ComponentModel.EnumConverterclass.Tospecifythevalue for an enumerated property, simply use the name of the property. Forexample the TestObject class has a property of the enumerated typeFileMode.OneofthevaluesforthisenumerationisnamedCreate.ThefollowingXMLfragmentshowshowtoconfigurethisproperty

<objectid="rod"type="Spring.Objects.TestObject,Spring.Core.Tests"

<propertyname="name"value="Rod"/>

<propertyname="FileMode"value="Create"/>

</object>

5.5.2.Built-inTypeConvertersSpring.NET pre-registers a number of customTypeConverter instances

Page 146: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

(for example, to convert a type expressed as a string into a realSystem.Typeobject).Eachofthoseislistedbelowandtheyarealllocatedin the Spring.Objects.TypeConverters namespace of theSpring.Corelibrary.

Table5.6.Built-inTypeConverters

Type Explanation

RuntimeTypeConverterParsesstringsrepresentingSystem.Typestoactual

System.Typesandtheotherwayaround.

FileInfoConverterCapableofresolvingstringstoaSystem.IO.FileInfoobject.

StringArrayConverter Capableofresolvingacomma-delimitedlistofstringstoastring-arrayandviceversa.

UriConverterCapableofresolvingastringrepresentationofaUritoanactualUri-object.

CredentialConverterCapableofresolvingastringrepresentationofacredentialforWebclientauthenticationintoaninstanceofSystem.Net.ICredentials

StreamConverterCapableofresolvingSpringIResourceUri(string)toitscorrespondingInputStream-object.

ResourceConverterCapableofresolvingSpringIResourceUri(string)toanIResourceobject.

ResourceManagerConverter

Capableofresolvingatwopartstring(resourcename,assemblyname)toaSystem.Resources.ResourceManagerobject.

RgbColorConverterCapableofresolvingacommaseparatedlistofRed,Green,BlueintegervaluestoaSystem.Drawing.Colorstructure.

ExpressionConverterCapableofresolvingastringintoaninstanceofanobjectthatimplementstheIExpressioninterface.

NameValueConverterCapableofresolvinganXMLformattedstringtoaSpecialized.NameValueCollection

RegexConverter CapableofresolvingastringintoaninstanceofRegex

RegistryKeyConverterCapableofresolvingastringintoaMicrosoft.Win32.RegistryKeyobject.

Page 147: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Spring.NET uses the standard .NET mechanisms for the resolution ofSystem.Types, including, but not limited to checking any configurationfiles associated with your application, checking the Global Assembly Cache(GAC),andassemblyprobing.

5.5.3.CustomTypeConversionThere are a few ways to register custom type converters. The fundamentalstorage area in Spring for custom type converters is theTypeConverterRegistryclass.Themostconvenientway ifusinganXML based implementation of IObjectFactory orIApplicationContext is to use the custom configuration sectionhandlerTypeConverterSectionHandler This is demonstrated insectionSection5.11,“ConfigurationofIApplicationContext”Analternateapproach,presentforlegacyreasonsintheportofSpring.NETfromthe Java code base, is to use the object factory post-processorSpring.Objects.Factory.Config.CustomConverterConfigurer

Thisisdescribedinthenextsection.IfyouareconstructingyourIoCcontainerProgramaticallythenyoushouldusethe RegisterCustomConverter(Type requiredType,

TypeConverter converter) method of theConfigurableObjectFactoryinterface.

5.5.3.1.UsingCustomConverterConfigurerThissectionshowsindetailhowtodefineacustomtypeconverterthatdoesnotuse the .NET TypeConverter attribute. The type converter class isstandaloneandinheritsfromtheTypeConverterclass.Itusesthelegacyfactorypost-processorapproach.Consider a user class ExoticType, and another class DependsOnExoticTypewhichneedsExoticTypesetasaproperty:

publicclassExoticType

{

Page 148: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

privatestringname;

publicExoticType(stringname)

{

this.name=name;

}

publicstringName

{

get{returnthis.name;}

}

}

and

publicclassDependsOnExoticType

{

publicDependsOnExoticType(){}

privateExoticTypeexoticType;

publicExoticTypeExoticType

{

get{returnthis.exoticType;}

set{this.exoticType=value;}

}

publicoverridestringToString()

{

returnexoticType.Name;

}

}

Whenthingsareproperlysetup,wewanttobeabletoassignthetypepropertyas a string,which a TypeConverterwill convert into a real ExoticType objectbehindthescenes:

<objectname="sample"type="SimpleApp.DependsOnExoticType,SimpleApp"

<propertyname="exoticType"value="aNameForExoticType"/>

</object>

Page 149: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheTypeConverterlookslikethis:

publicclassExoticTypeConverter:TypeConverter

{

publicExoticTypeConverter()

{

}

publicoverrideboolCanConvertFrom(

ITypeDescriptorContextcontext,

TypesourceType)

{

if(sourceType==typeof(string))

{

returntrue;

}

returnbase.CanConvertFrom(context,sourceType);

}

publicoverrideobjectConvertFrom(

ITypeDescriptorContextcontext,

CultureInfoculture,objectvalue)

{

strings=valueasstring;

if(s!=null)

{

returnnewExoticType(s.ToUpper());

}

returnbase.ConvertFrom(context,culture,value

}

}

Finally, we use the CustomConverterConfigurer to register thenewTypeConverterwiththeIApplicationContext,whichwillthenbeabletouseitasneeded:

<objectid="customConverterConfigurer"

type="Spring.Objects.Factory.Config.CustomConverterConfigurer,Spring.Core"

<propertyname="CustomConverters">

<dictionary>

<entrykey="SimpleApp.ExoticType">

Page 150: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objecttype="SimpleApp.ExoticTypeConverter"/>

</entry>

</dictionary>

</property>

</object>

Page 151: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.6.Customizingthenatureofanobject

5.6.1.LifecycleinterfacesSpring.NET uses several marker interfaces to change the behaviour of yourobject in the container, namely the Spring.NET specificIInitializingObject interface and the standardSystem.IDisposable interfaces. Implementing either of theaforementioned interfaces will result in the container calling theAfterPropertiesSet() method for the former and theDispose()method for the latter, thus allowingyou to do thingsupon theinitializationanddestructionofyourobjects.Internally, Spring.NET uses implementations of theIObjectPostProcessor interface to process anymarker interfaces itcanfindandcalltheappropriatemethods.IfyouneedcustomfeaturesorotherlifecyclebehaviorSpring.NETdoesn'tofferout-of-the-box,youcan implementanIObjectPostProcessoryourself.MoreinformationaboutthiscanbefoundinSection5.9.1,“CustomizingobjectswithIObjectPostProcessors”.Allthedifferentlifecyclemarkerinterfacesaredescribedbelow.

5.6.1.1.IInitializingObject/init-methodThe Spring.Objects.Factory.IInitializingObject

interface gives you the ability to perform initialization work after all thenecessary properties on an object are set by the container. TheIInitializingObjectinterfacespecifiesexactlyonemethod:

voidAfterPropertiesSet():calledafterallpropertieshavebeensetbythecontainer.Thismethodenablesyoutodocheckingtoseeifall necessary properties have been set correctly, or to perform furtherinitialization work. You can throw any Exception to indicatemisconfiguration,initializationfailures,etc.

Note

Generally,theuseoftheIInitializingObjectcanbeavoided.TheSpring.Corelibraryprovidessupportforagenericinit-method,giventotheobjectdefinitionintheobject

Page 152: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

configurationstore(beitXML,oradatabase,etc).

<objectid="exampleInitObject"type="Examples.ExampleObject"

[C#]

publicclassExampleObject

{

publicvoidInit()

{

//dosomeinitializationwork

}

}

Isexactlythesameas...

<objectid="exampleInitObject"type="Examples.AnotherExampleObject"

[C#]

publicclassAnotherExampleObject:IInitializingObject

{

publicvoidAfterPropertiesSet()

{

//dosomeinitializationwork

}

}

butdoesnotcouplethecodetoSpring.NET.

Note

Whendeployinganobjectinprototypemode,thelifecycleoftheobjectchangesslightly.Bydefinition,Spring.NETcannotmanagethecompletelifecycleofanon-singleton/prototypeobject,sinceafteritiscreated,itisgiventotheclientandthecontainernolongerkeepsareferencetotheobject.YoucanthinkofSpring.NET'srolewhentalkingaboutanon-singleton(prototype)objectasareplacementforthenewoperator.Anylifecycleaspectspastthatpointhavetobehandledbytheclient.

5.6.1.2.IDisposable/destroy-methodTheSystem.IDisposableinterfaceprovidesyouwiththeabilitytoget

Page 153: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

acallbackwhenanIObjectFactoryisdestroyed.TheIDisposableinterfacespecifiesexactlyonemethod:

voidDispose():andiscalledondestructionofthecontainer.Thisallowsyoutoreleaseanyresourcesyouarekeepinginthisobject(suchasdatabaseconnections).YoucanthrowanyExceptionhere...however,anysuchExceptionwillnotstop thedestructionof thecontainer - itwillonlygetlogged.

Note

Note:IfyouchooseyoucanavoidhavingyourclassimplementIDisposablesincetheSpring.Corelibraryprovidessupportforagenericdestroy-method,giventotheobjectdefinitionintheobjectconfigurationstore(beitXML,oradatabase,etc).

<objectid="exampleInitObject"type="Examples.ExampleObject"

[C#]

publicclassExampleObject

{

publicvoidcleanup()

{

//dosomedestructionwork(suchasclosinganyopenconnection(s))

}

}

isexactlythesameas:

<objectid="exampleInitObject"type="Examples.AnotherExampleObject"

[C#]

publicclassAnotherExampleObject:IDisposable

{

publicvoidDispose()

{

//dosomedestructionwork

}

}

5.6.2.Knowingwhoyouare

Page 154: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.6.2.1.IObjectFactoryAwareA class which implements theSpring.Objects.Factory.IObjectFactoryAware

interfaceisprovidedwithareferencetotheIObjectFactorythatcreatedit.Theinterfacespecifiesone(write-only)property:

IObjectFactoryObjectFactory: the property that will besetafter the initializationmethods (AfterPropertiesSetand theinit-method).

ThisallowsobjectstomanipulatetheIObjectFactorythatcreatedthemProgramatically,throughtheIObjectFactoryinterface,orbycastingthereference to a known subclass of this which exposes additional functionality.Primarily thiswould consist of programmatic retrieval of other objects.Whilethere are caseswhen this capability is useful, it should generally be avoided,since it couples the code toSpring.NET, anddoes not follow the Inversion ofControlstyle,wherecollaboratorsareprovidedtoobjectsasproperties.

5.6.2.2.IObjectNameAwareTheSpring.Objects.Factory.IObjectNameAwareinterfacegivesyoutheabilitytoletthecontainersetthenameoftheobjectdefinitionontheobjectinstanceitself.Inthosecaseswhereyourobjectneedstoknowwhatitsnameis,implementthisinterface.

stringObjectName:thepropertythatwillbesettolettheobjectknowwhatitsnameis.

Page 155: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.7.ObjectdefinitioninheritanceAn object definition potentially contains a large amount of configurationinformation,includingcontainerspecificinformation(i.e. initializationmethod,staticfactorymethodname,etc.)andconstructorargumentsandpropertyvalues.Achildobjectdefinition is anobjectdefinition that inherits configurationdatafromaparentdefinition.Itisthenabletooverridesomevalues,oraddothers,asneeded.Usingparent and child object definitions can potentially save a lot oftyping.Effectively,thisisaformoftemplating.When working with an IObjectFactory Programatically, child objectdefinitions are represented by the ChildObjectDefinition class.Mostuserswillneverworkwith themon this level, insteadconfiguringobjectdefinitionsdeclarativelyinsomethingliketheXmlObjectFactory.InanXmlObjectFactory object definition, a child object definition isindicated simply by using the parent attribute, specifying the parent objectdefinitionasthevalueofthisattribute.

<objectid="inheritedTestObject"type="Spring.Objects.TestObject,Spring.Core.Tests"

<propertyname="name"value="parent"/>

<propertyname="age"value="1"/>

</object>

<objectid="inheritsWithDifferentClass"type="Spring.Objects.DerivedTestObject,Spring.Core.Tests"

parent="inheritedTestObject"init-method="Initialize">

<propertyname="name"value="override"/>

<!--agewillinheritvalueof1fromparent-->

</object>

Achildobject definitionwill use theobject class from theparentdefinition ifnoneisspecified,butcanalsooverrideit.Inthelattercase,thechildobjectclassmust be compatible with the parent, i.e. it must accept the parent's propertyvalues.A child object definition will inherit constructor argument values, propertyvaluesandmethodoverridesfromtheparent,withtheoptiontoaddnewvalues.If initmethod,destroymethodand/or static factorymethodare specified, theywilloverridethecorrespondingparentsettings.The remaining settings will always be taken from the child definition:depends on, autowire mode, dependency check,

Page 156: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

singleton,lazyinit.Inthecasewheretheparentdefinitiondoesnotspecifyaclass...

<objectid="inheritedTestObjectWithoutClass"abstract="true"

<propertyname="name"value="parent"/>

<propertyname="age"value="1"/>

</object>

<objectid="inheritsWithClass"type="Spring.Objects.DerivedTestObject,Spring.Core.Tests"

parent="inheritedTestObjectWithoutClass"init-method="Initialize"

<propertyname="name"value="override"/>

<!--agewillinheritvalueof1fromparent-->

</object>

...theparentobjectcannotbeinstantiatedonitsownsinceitincomplete,anditisalsoexplicitlymarkedasabstract.Whenadefinitionisdefinedtobeabstractlikethis,itisusableonlyasapuretemplateobjectdefinitionthatwillserveasaparent definition for child definitions. Trying to use such an abstract parentobjectonitsown(byreferringtoitasarefpropertyofanotherobject,ordoinganexplicitGetObject()withtheparentobject id),willresult inanerror.The container's internal PreInstantiateSingletons method willcompletelyignoreobjectdefinitionsthatareconsideredabstract.

Note

Applicationcontexts(butnotsimpleobjectfactories)willbydefaultpre-instantiateallsingletons.Thereforeitisimportant(atleastforsingletonobjects)thatifyouhavea(parent)objectdefinitionwhichyouintendtouseonlyasatemplate,andthisdefinitionspecifiesaclass,youmustmakesuretosettheabstractattributetotrue,otherwisetheapplicationcontextwillactually(attemptto)pre-instantiatetheabstractobject.

Page 157: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.8.InteractingwiththecontainerThe Spring container is essentially nothing more than an advanced factorycapableofmaintainingaregistryofdifferentobjectsandtheirdependencies.TheIObjectFactoryenablesyoutoreadobjectdefinitionsandaccess themusingtheobjectfactory.WhenusingjusttheIObjectFactoryyouwouldcreatean instanceofoneand thenread insomeobjectdefinitions in theXMLformatasfollows:

[C#]

IResourceinput=newFileSystemResource("objects.xml");

XmlObjectFactoryfactory=newXmlObjectFactory(input);

Thatisprettymuchit.UsingGetObject(string)(orthemoreconciseindexer methodfactory["string"]) you can retrieve instances ofyourobjects...

[C#]

objectfoo=factory.GetObject("foo");//getstheobjectdefinedas'foo'

objectbar=factory["bar"];//samething,justusingtheindexer

You'll get a reference to the same object if you defined it as a singleton (thedefault) or you'll get a new instance each time if you set thesingletonpropertyofyourobjectdefinitiontofalse.

<objectid="exampleObject"type="Examples.ExampleObject,ExamplesLibrary"

<objectid="anotherObject"type="Examples.ExampleObject,ExamplesLibrary"

[C#]

objectone=factory["exampleObject"];//getstheobjectdefinedas'exampleObject'

objecttwo=factory["exampleObject"];

Console.WriteLine(one==two)//prints'true'

objectthree=factory["anotherObject"];//getstheobjectdefinedas'anotherObject'

objectfour=factory["anotherObject"];

Console.WriteLine(three==four);//prints'false'

Theclient-sideviewof theIObjectFactory issurprisingly simple.TheIObjectFactory interface has only seven methods (and the

Page 158: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

aforementionedindexer)forclientstocall:

bool ContainsObject(string): returns true if theIObjectFactorycontainsanobjectdefinitionthatmatchesthegivenname.

objectGetObject(string): returnsan instanceof theobjectregistered under the given name. Depending on how the object wasconfiguredbytheIObjectFactoryconfiguration,eitherasingleton(and thus shared) instanceor a newly createdobjectwill be returned.AnObjectsExceptionwillbethrownwheneithertheobjectcouldnotbe found (in which case it'll be aNoSuchObjectDefinitionException), or an exceptionoccurredwhileinstantiatedandpreparingtheobject.

Object this [string]: this is the indexer for theIObjectFactory interface. It functions in all other respects inexactlythesamewayastheGetObject(string)method.TherestofthisdocumentationwillalwaysrefertotheGetObject(string)method,butbeawarethatyoucanuse the indexeranywhere thatyoucanusetheGetObject(string)method.

Object GetObject(string, Type): returns an object,registered under the given name. The object returned will be cast to thegivenType.Iftheobjectcouldnotbecast,correspondingexceptionswillbe thrown (ObjectNotOfRequiredTypeException).Furthermore, all rules of the GetObject(string) method apply(seeabove).

boolIsSingleton(string): determines whether or not theobject definition registered under the given name is a singleton or aprototype. If the object definition corresponding to the given name couldnot be found, an exception will be thrown(NoSuchObjectDefinitionException)

string[]GetAliases(string): returns the aliases for thegivenobjectname,ifanyweredefinedintheIObjectDefinition.

void ConfigureObject(object target): Injects

Page 159: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

dependencies into the supplied target instance. The name of the abstractobject definition is the System.Type.FullName of the targetinstance. This method is typically used when objects are instantiatedoutsidethecontrolofadeveloper,forexamplewhenASP.NETinstantiateswebcontrolsandwhenaWinFormsapplicationcreatesUserControls.

void ConfigureObject(object target, string

name):OffersthesamefunctionalityasthepreviouslylistedConfiguremethodbutusesanamedobjectdefinition insteadofusing the type's fullname.

A sub-interface of IObjectFactory,IConfigurableObjectFactory adds some convenient methodssuchas

void RegisterSingleton(string name, object

objectInstance) :Register thegivenexistingobject as singletonintheobjectfactoryunderthegivenobjectname.

void RegisterAlias(string name, string

theAlias);Givenanobjectname,createanalias.Check the SDK docs for additional details on IConfigurableObjectFactorymethodsandpropertiesandthefullIObjectFactoryclasshierarchy.

5.8.1.ObtaininganIFactoryObject,notitsproductSometimes there is a need to ask an IObjectFactory for an actualIFactoryObject instance itself,not theobject itproduces.Thismaybedone by prepending the object id with & when calling the GetObjectmethod of the IObjectFactory and IApplicationContextinterfaces. So for a given IFactoryObject with an id myObject,invoking GetObject("myObject") on the IObjectFactorywill return the product of the IFactoryObject, but invokingGetObject("&myObject") will return the IFactoryObjectinstanceitself.

Page 160: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.9.ContainerextensionpointsTheIoCcomponentoftheSpringFrameworkhasbeendesignedforextension.There is typically no need for an application developer to subclass any of thevarious IObjectFactory or IApplicationContext

implementationclasses.TheSpringIoCcontainercanbeinfinitelyextendedbyplugging in implementations of special integration interfaces. The next fewsectionsaredevotedtodetailingallofthesevariousintegrationinterfaces.

5.9.1. Customizing objects withIObjectPostProcessors

The first extension point that we will look at is theSpring.Objects.Factory.Config.IObjectPostProcessor

interface. This interface defines a number of callbackmethods that you as anapplicationdevelopercanimplementinordertoprovideyourown(oroverridethe containers default) instantiation logic, dependency-resolution logic, and soforth. If you want to do some custom logic after the Spring container hasfinished instantiating,configuringandotherwise initializinganobject,youcanpluginoneormoreIObjectPostProcessorimplementations.

You can configure multiple IObjectPostProcessors if you wish.You can control the order in which these IObjectPostProcessorexecute by setting the 'Order' property (you can only set this property if theIObjectPostProcessor implements the IOrdered interface; ifyou write your own IObjectPostProcessor you should considerimplementing theIOrdered interface too); consult the SDK docs for theIObjectPostProcessorandIOrderedinterfacesformoredetails.

Note

IObjectPostProcessoroperateonobjectinstances;thatistosay,theSpringIoCcontainerwillhaveinstantiatedaobjectinstanceforyou,andthenIObjectPostProcessorsgetachancetodotheirstuff.Ifyouwanttochangetheactualobjectdefinition(thatistherecipethatdefinestheobject),thenyouratherneedtouseaIObjectFactoryPostProcessor(describedbelowinthesectionentitledCustomizingconfigurationmetadatawithIObjectFactoryPostProcessors.

Page 161: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Also,IObjectPostProcessorsarescopedper-container.Thisisonlyrelevantifyouareusingcontainerhierarchies.IfyoudefineaIObjectPostProcessorinonecontainer,itwillonlydoitsstuffontheobjectsinthatcontainer.Objectsthataredefinedinanothercontainerwillnotbepost-processedbyIObjectPostProcessorsinanothercontainer,evenifbothcontainersarepartofthesamehierarchy.

TheSpring.Objects.Factory.Config.IObjectPostProcessor

interface,whichconsistsoftwocallbackmethodsshownbelow.

objectPostProcessBeforeInitialization(objectinstance,string

objectPostProcessAfterInitialization(objectinstance,string

Whensuchaclassisregisteredasapost-processorwiththecontainer,foreachobject instance that is created by the container,(see below for how thisregistrationiseffected),foreachobjectinstancethatiscreatedbythecontainer,the post-processor will get a callback from the container both before anyinitializationmethods(suchastheAfterPropertiesSetmethodoftheIInitializingObject interface and any declared init method) arecalled,andalsoafterwards.Thepost-processorisfreetodowhatitwisheswiththeobject,includingignoringthecallbackcompletely.Anobjectpost-processorwill typically check for marker interfaces, or do something such as wrap anobject with a proxy. Some Spring.NET AOP infrastructure classes areimplementedasobjectpost-processorsastheydothisproxy-wrappinglogic.Other extensions to the IObjectPostProcessors interface areIInstantiationAwareObjectPostProcessor andIDestructionAwareObjectPostProcessordefinedbelow

publicinterfaceIInstantiationAwareObjectPostProcessor:IObjectPostProcessor

{

objectPostProcessBeforeInstantiation(TypeobjectType,

boolPostProcessAfterInstantiation(objectobjectInstance,

IPropertyValuesPostProcessPropertyValues(IPropertyValuespvs,PropertyInfo[]pis,

Page 162: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

publicinterfaceIDestructionAwareObjectPostProcessor:IObjectPostProcessor

{

voidPostProcessBeforeDestruction(objectinstance,string

}

The PostProcessBeforeInstantiation callback method iscalledrightbeforethecontainercreatestheobject.Iftheobjectreturnedbythismethodisnotnullthenthedefaultinstantiationbehaviorofthecontainerisshortcircuited. The returned object is the one registered with the container and nootherIObjectPostProcessor callbacks will be invoked on it. Thismechanismisusefulifyouwouldliketoexposeaproxytotheobjectinsteadofthe actual target object. The PostProcessAfterInstantiationcallbackmethodiscalledaftertheobjecthasbeeninstantiatedbutbeforeSpringperforms property population based on explicit properties or autowiring. Areturn value of false would short circuit the standard Spring based propertypopulation. The callback methodPostProcessPropertyValues iscalled after Spring collects all the property values to apply to the object, butbefore they are applied. This gives you the opportunity to perform additionalprocessingsuchasmakingsurethatapropertyisset toavalueif itcontainsa[Required] attribute or to perform attribute basedwiring, i.e. adding theattribute [Inject("objectName")] on a property. Both of thesefeaturesarescheduledtobeincludedinSpring.12.The IDestructionAwareObjectPostProcessor callbackcontains a single method, PostProcessBeforeDestruction,whichiscalledbeforeasingleton'sdestroymethodisinvoked.It is important to know that the IObjectFactory treats object post-processors slightly differently than the IApplicationContext. AnIApplicationContextwillautomaticallydetectanyobjectswhicharedeployedintoitthatimplementtheIObjectPostProcessorinterface,and register them as post-processors, to be then called appropriately by thefactoryonobjectcreation.Nothingelseneeds tobedoneother thandeployingthepost-processor in a similar fashion to anyother object.On theother hand,when using plain IObjectFactories, object post-processors have tomanuallybeexplicitlyregistered,withacodesequencesuchas...

Page 163: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ConfigurableObjectFactoryfactory=new.....;//createanIObjectFactory

...//nowregistersomeobjects

//nowregisteranyneededIObjectPostProcessors

MyObjectPostProcessorpp=newMyObjectPostProcessor();

factory.AddObjectPostProcessor(pp);

//nowstartusingthefactory

...

This explicit registration step is not convenient, and this is one of the reasonswhythevariousIApplicationContextimplementationsarepreferredabove plain IObjectFactory implementations in the vast majority ofSpring-backedapplications,especiallywhenusingIObjectPostProcessors.

Note

IObjectPostProcessorsandAOPauto-proxyingClassesthatimplementtheIObjectPostProcessorinterfacearespecial,andsotheyaretreateddifferentlybythecontainer.AllIObjectPostProcessorsandtheirdirectlyreferencedobjectwillbeinstantiatedonstartup,aspartofthespecialstartupphaseoftheIApplicationContext,thenallthoseIObjectPostProcessorswillberegisteredinasortedfashion-andappliedtoallfurtherobjects.SinceAOPauto-proxyingisimplementedasaIObjectPostProcessoritself,noIObjectPostProcessorsordirectlyreferencedobjectsareeligibleforauto-proxying(andthuswillnothaveaspects'woven'intothem).Foranysuchobject,youshouldseeaninfologmessage:“Object'foo'isnoteligibleforgettingprocessedbyallIObjectPostProcessors(forexample:noteligibleforauto-proxying)”.

5.9.1.1.Example:HelloWorld,IObjectPostProcessor-styleThisfirstexampleishardlycompelling,butservestoillustratebasicusage.AllwearegoingtodoiscodeacustomIObjectPostProcessorimplementationthatsimply invokes the ToString() method of each object as it is created by thecontainer and prints the resulting string to the system console. Yes, it is nothugelyuseful,butserves toget thebasicconceptsacrossbeforewemove intothe second examplewhich is actually useful. The basis of the example is theMovieFinderquickstartthatisincludedwiththeSpring.NETdistribution.

Page 164: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

FindbelowthecustomIObjectPostProcessorimplementationclassdefinition

usingSystem;

usingSpring.Objects.Factory.Config;

namespaceSpring.IocQuickStart.MovieFinder

{

publicclassTracingObjectPostProcessor:IObjectPostProcessor

{

publicobjectPostProcessBeforeInitialization(object

{

returninstance;

}

publicobjectPostProcessAfterInitialization(objectinstance,

{

Console.WriteLine("Object'"+name+"'created:"

returninstance;

}

}

}

Andthefollowingconfiguration

<?xmlversion="1.0"encoding="utf-8"?>

<objectsxmlns="http://www.springframework.net">

<description>AnexamplethatdemonstratessimpleIoCfeatures.

<objectid="MyMovieLister"

type="Spring.IocQuickStart.MovieFinder.MovieLister,Spring.IocQuickStart.MovieFinder"

<propertyname="movieFinder"ref="MyMovieFinder"/>

</object>

<objectid="MyMovieFinder"

type="Spring.IocQuickStart.MovieFinder.SimpleMovieFinder,Spring.IocQuickStart.MovieFinder"

<!--whentheaboveobjectsareinstantiated,thiscustomIObjectPostProcessorimplementation

willoutputthefacttothesystemconsole-->

<objecttype="Spring.IocQuickStart.MovieFinder.TracingObjectPostProcessor,Spring.IocQuickStart.MovieFinder"

</objects>

Page 165: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Notice how the TracingObjectPostProcessor is simply defined; it doesn't evenhaveaname,andbecause it isaobject itcanbedependency injected just likeanyotherobject.Findbelowasmalldriverscripttoexercisetheabovecodeandconfiguration;

IApplicationContextctx=

newXmlApplicationContext(

"assembly://Spring.IocQuickStart.MovieFinder/Spring.IocQuickStart.MovieFinder/AppContext.xml"

MovieListerlister=(MovieLister)ctx.GetObject("MyMovieLister"

Movie[]movies=lister.MoviesDirectedBy("RobertoBenigni");

LOG.Debug("Searchingformovie...");

foreach(Moviemovieinmovies)

{

LOG.Debug(string.Format("MovieTitle='{0}',Director='{1}'."

}

LOG.Debug("MovieAppDone.");

Theoutputofexecutingtheaboveprogramwillbe:

INFO-Object'Spring.IocQuickStart.MovieFinder.TracingObjectPostProcessor'isnoteligibleforbeingprocessedbyallIObjectPostProcessors

(forexample:noteligibleforauto-proxying).

Object'MyMovieFinder'created:Spring.IocQuickStart.MovieFinder.SimpleMovieFinder

Object'MyMovieLister'created:Spring.IocQuickStart.MovieFinder.MovieLister

DEBUG-Searchingformovie...

DEBUG-MovieTitle='Lavitaebella',Director='RobertoBenigni'.

DEBUG-MovieAppDone.

5.9.1.2. Example: theRequiredAttributeObjectPostProcessorUsing callback interfaces or annotations in conjunction with a customIObjectPostProcessor implementation is a common means of extending theSpring IoC container. The [Required] attribute in theSpring.Objects.Factory.Attributesnamespacecanbeusedtomarkapropertyasbeing 'required-to-be-set'(i.e.ansetterpropertywiththisattribute appliedmust be configured to be dependency injectedwith a value),elseanObjectInitializationExceptionwillbe thrownby thecontaineratruntime.

Page 166: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Thebestwaytoillustratetheusageofthisattributeiswithanexample.

publicclassMovieLister

{

//theMovieListerhasadependencyontheMovieFinder

privateIMovieFinder_movieFinder;

//asetterpropertysothattheSpringcontainercan'inject'aMovieFinder

[Required]

publicIMovieFinderMovieFinder

{

set{_movieFinder=value;}

}

//businesslogicthatactually'uses'theinjectedMovieFinderisomitted...

}

Hopefully the above class definition reads easy on the eye. Any and allIObjectDefinitions for the MovieLister class must beprovidedwithavalue.Let's look at an example of some XML configuraiton that will not passvalidation.

<objectid="MyMovieLister"

type="Spring.IocQuickStart.MovieFinder.MovieLister,Spring.IocQuickStart.MovieFinder"

<!--whoops,noMovieFinderisset(andthispropertyis[Required])-->

</object>

AtruntimethefollowingmessagewillbegeneratedbytheSpringcontainer

Errorcreatingcontext'spring.root':Property'MovieFinder'requiredforobject'MyMovieLister'

Thereisonelast littlepieceofSpringconfigurationthatisrequired toactually'switchon'thisbehavior.Simplyannotatingthe'setter'propertiesofyourclassesisnotenoughtogetthisbehavior.Youneedtoenableacomponentthatisawareofthe[Required]attributeandthatcanprocessitappropriately.This component is theRequiredAttributeObjectPostProcessor class. This is a

Page 167: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

special IObjectPostProcessor implementation that is[Required]-aware and actually provides the 'blow up if this requiredproperty has not been set' logic. It is very easy to configure; simply drop thefollowingobjectdefinitionintoyourSpringXMLconfiguration.

<objecttype="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor,Spring.Core"

Finally, one can configure an instance of theRequiredAttributeObjectPostProcessor class to look foranother Attribute type. This is great if you already have your own[Required]-style attribute. Simply plug it into the definition of aRequiredAttributeObjectPostProcessor andyou are goodto go.Byway of an example, let's suppose you (or your organization / team)have defined an attribute called [Mandatory]. You can make aRequiredAttributeObjectPostProcessor instance[Mandatory]-awarelikeso:

<objecttype="Spring.Objects.Factory.Attributes.RequiredAttributeObjectPostProcessor,Spring.Core"

<propertyname="RequiredAttributeType"value="MyApp.Attributes.MandatoryAttribute,MyApp"

</object>

5.9.2. Customizing configuration metadata withObjectFactoryPostProcessorsThe next extension point that we will look at is theSpring.Objects.Factory.Config.IObjectFactoryPostProcessor

The semantics of this interface are similar to theIObjectPostProcessor, with one major difference.IObjectFactoryPostProcessors operate on; that is to say, theSpringIoCcontainerwillallowIObjectFactoryPostProcessorstoreadtheconfigurationmetadataandpotentiallychangeitbeforethecontainerhasactuallyinstantiatedanyotherobjects.Byimplementingthis interface,youwillreceiveacallbackafterthealltheobjectdefinitionshavebeenloadedintothe IoC container but before they have been instantiated. The signature of theinterfaceisshownbelow

Page 168: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicinterfaceIObjectFactoryPostProcessor

{

voidPostProcessObjectFactory(IConfigurableListableObjectFactoryfactory);

}

You can configure multiple IObjectFactoryPostProcessors ifyou wish. You can control the order in which theseIObjectFactoryPostProcessors execute by setting the 'Order'property (you can only set this property if theIObjectFactoryPostProcessors implements the IOrderedinterface;ifyouwriteyourownIObjectFactoryPostProcessorsyoushouldconsider implementing theIOrdered interface too);consult theSDK docs for the IObjectFactoryPostProcessors andIOrderedinterfacesformoredetails.

Note

Ifyouwanttochangetheactualobjectinstances(theobjectsthatarecreatedfromtheconfigurationmetadata),thenyouratherneedtouseaIObjectObjectPostProcessor(describedaboveinthesectionentitledCustomizingobjectswithIObjectPostProcessors.Also,IObjectFactoryPostProcessorsarescopedper-container.Thisisonlyrelevantifyouareusingcontainerhierarchies.IfyoudefineaIObjectFactoryPostProcessorsinonecontainer,itwillonlydoitsstuffontheobjectdefinitionsinthatcontainer.Objectdefinitionsinanothercontainerwillnotbepost-processedbyIObjectFactoryPostProcessorsinanothercontainer,evenifbothcontainersarepartofthesamehierarchy.

An object factory post-processor is executed manually (in the case of aIObjectFactory) or automatically (in the case of an IApplicationContext) toapply changes of some sort to the configuration metadata that defines acontainer. Spring.NET includes a number of pre-existing object factory post-processors, such as PropertyResourceConfigurer andPropertyPlaceHolderConfigurer, both described below andObjectNameAutoProxyCreator,whichisveryusefulforwrappingotherobjectstransactionallyorwithanyotherkindofproxy,asdescribedlaterinthismanual.

Page 169: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

In an IObjectFactory, the process of applying anIObjectFactoryPostProcessor ismanual,andwillbe similar tothis:

XmlObjectFactoryfactory=newXmlObjectFactory(newFileSystemResource(

//createplaceholderconfigurertobringinsomeproperty

//valuesfromaPropertiesfile

PropertyPlaceholderConfigurercfg=newPropertyPlaceholderConfigurer();

cfg.setLocation(newFileSystemResource("ado.properties"));

//nowactuallydothereplacement

cfg.PostProcessObjectFactory(factory);

Thisexplicit registration step is not convenient, and this is one of the reasonswhythevariousIApplicationContextimplementationsarepreferredabove plain IObjectFactory implementations in the vast majority ofSpring-backed applications, especially when usingIObjectFactoryPostProcessors.

AnIApplicationContextwilldetectanyobjectswhicharedeployedintoitthatimplementtheObjectFactoryPostProcessorinterface,andautomaticallyusethemasobjectfactorypost-processors,attheappropriatetime.Nothingelseneedstobedoneotherthandeployingthesepost-processorinasimilarfashiontoanyotherobject.

Note

JustasinthecaseofIObjectPostProcessors,youtypicallydon'twanttohaveIObjectFactoryPostProcessorsmarkedasbeinglazily-initialized.Iftheyaremarkedassuch,thentheSpringcontainerwillneverinstantiatethem,andthustheywon'tgetachancetoapplytheircustomlogic.Ifyouareusingthe'default-lazy-init'attributeonthedeclarationofyour<objects/>element,besuretomarkyourvariousIObjectFactoryPostProcessorobjectdefinitionswith'lazy-init="false"'.

5.9.2.1. Example: ThePropertyPlaceholderConfigurer

Page 170: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The PropertyPlaceholderConfigurer is an excellent solutionwhen you want to externalize a few properties from a file containing objectdefinitions. This is useful to allow the person deploying an application tocustomizeenvironment specificproperties (forexampledatabaseconfigurationstrings,usernames,andpasswords),withoutthecomplexityorriskofmodifyingthemainXMLdefinitionfileorfilesforthecontainer.Variablesubstitutionisperformedonsimplepropertyvalues, lists,dictionaries,sets, constructorvalues, object typename, andobject names in runtimeobjectreferences. Furthermore, placeholder values can also cross-reference otherplaceholders.Note thatIApplicationContexts are able to automatically recognizeand apply objects deployed in them that implement theIObjectFactoryPostProcessor interface. This means that asdescribed here, applying aPropertyPlaceholderConfigurer ismuchmoreconvenientwhenusinganIApplicationContext.Forthisreason,itisrecommendedthatuserswishingtousethisorotherobject factorypostprocessors use an IApplicationContext instead of anIObjectFactory.Intheexamplebelowadataaccessobjectneedstobeconfiguredwithadatabaseconnectionandalsoavalue for themaximumnumberof results to return inaquery.InsteadofhardcodingthevaluesintothemainSpring.NETconfigurationfileweuseplaceholders,intheNAntstyleof${variableName},andobtaintheirvaluesfromNameValueSectionsinthestandard.NETapplicationconfigurationfile.TheSpring.NETconfigurationfilelookslike:

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

</sectionGroup>

<sectionname="DaoConfiguration"type="System.Configuration.NameValueSectionHandler"

<sectionname="DatabaseConfiguration"type="System.Configuration.NameValueSectionHandler"

</configSections>

<DaoConfiguration>

<addkey="maxResults"value="1000"/>

Page 171: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</DaoConfiguration>

<DatabaseConfiguration>

<addkey="connection.string"value="dsn=MyDSN;uid=sa;pwd=myPassword;"

</DatabaseConfiguration>

<spring>

<context>

<resourceuri="assembly://DaoApp/DaoApp/objects.xml"/>

</context>

</spring>

</configuration>

NoticethepresenceoftwoNameValueSectionsintheconfigurationfile.ThesenamevaluepairswillbereferredtointheSpring.NETconfigurationfile.Inthisexamplewe are using an embedded assembly resource for the location of theSpring.NETconfigurationfilesoastoreducethechanceofaccidentaltamperingindeployment.ThisSpring.NETconfigurationfileisshownbelow.

<objectsxmlns="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"

<objectname="productDao"type="DaoApp.SimpleProductDao,DaoApp"

<propertyname="maxResults"value="${maxResults}"/>

<propertyname="dbConnection"ref="myConnection"/>

</object>

<objectname="myConnection"type="System.Data.Odbc.OdbcConnection,System.Data"

<propertyname="connectionstring"value="${connection.string}"

</object>

<objectname="appConfigPropertyHolder"

type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer,Spring.Core"

<propertyname="configSections">

<value>DaoConfiguration,DatabaseConfiguration</value>

</property>

Page 172: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</object>

</objects>

The values of ${maxResults} and ${connection.string}match the key names used in the two NameValueSectionHandlersDaoConfiguration and DatabaseConfiguration. ThePropertyPlaceholderConfigurer refers to these two sectionsvia a comma delimited list of section names in the configSectionsproperty. If you are using section groups, prefix the section group name, forexamplemyConfigSection/DaoConfiguraiton.The PropertyPlaceholderConfigurer class also supportsretrievingnamevaluepairs fromotherIResource locations.Thesecanbespecified using the Location and Locations properties of thePropertyPlaceHolderConfigurerclass.If there are properties with the same name in different resource locations thedefaultbehavioristhatthelastpropertyprocessedoverridesthepreviousvalues.This is behavior is controlled by the LastLocationOverridesproperty. True enables overriding while false will append the values as onewouldnormallyexpectusingNameValueCollection.Add.

Note

InanASP.NETenvironmentyoumustspecifythefull,four-partnameoftheassemblywhenusingaNameValueFileSectionHandler

<sectionname="hibernateConfiguration"

type="System.Configuration.NameValueFileSectionHandler,System,

Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"

5.9.2.1.1.Type,Ref,andExpressionsubstitution

ThePropertyPlaceholderConfigurercanbeusedtosubstitutetypenames,whichissometimesusefulwhenyouhavetopickaparticularimplementationclassatruntime.Forexample:

Page 173: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="MyMovieFinder"type="${custom.moviefinder.type}"

Iftheclassisunabletoberesolvedatruntimetoavalidtype,resolutionoftheobject will fail once it is about to be created (which is during thePreInstantiateSingletons() phase of an ApplicationContext for a non-lazy-initobject.)Similarlyyoucanreplace'ref'and'expression'metadata,asshownbelow

<objectid="TestObject"type="Simple.TestObject,MyAssembly"

<propertyname="age"expression="${ageExpression}"/>

<propertyname="spouse"ref="${spouse-ref}"/>

</object>

5.9.2.1.2.ReplacementwithEnvironmentVariables

You may also use the value environment variables to replace propertyplaceholders. The use of environment variables is controlled via the propertyEnvironmentVariableMode.Thisproperty isanenumerationof thetype EnvironmentVariablesMode and has three values, Never,Fallback, and Override.Fallback is the default value and will resolve apropertyplaceholder if itwasnotalreadydonesoviaavalue fromaresourcelocation.Overridewillapplyenvironmentvariablesbeforeapplyingvaluesdefined from a resource location. Never will, quite appropriately, disableenvironment variable substitution. An example of how thePropertyPlaceholderConfigurer XML is modified to enableoverrideusageisshownbelow

<objectname="appConfigPropertyHolder"

type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer,Spring.Core"

<propertyname="configSections"value="DaoConfiguration,DatabaseConfiguration"

<propertyname="EnvironmentVariableMode"value="Override"

</object>

</objects>

5.9.2.2. Example: The

Page 174: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PropertyOverrideConfigurer

ThePropertyOverrideConfigurer, another object factory post-processor, is similar to the PropertyPlaceholderConfigurer,butincontrasttothelatter,theoriginaldefinitionscanhavedefaultvaluesornovalues at all for object properties. If an overriding configuration file does nothaveanentryforacertainobjectproperty,thedefaultcontextdefinitionisused.Notethattheobjectfactorydefinitionisnotawareofbeingoverridden,soitisnot immediately obvious when looking at the XML definition file that theoverride configurer is being used. In case that there are multiplePropertyOverrideConfigurer instances that define differentvaluesforthesameobjectproperty,thelastonewillwin(duetotheoverridingmechanism).The example usage is similar to when usingPropertyPlaceHolderConfigurer except that the key namereferstothenamegiventotheobjectintheSpring.NETconfigurationfileandissuffixed via 'dot' notation with the name of the property For example, if theapplicationconfigurationfileis

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

</sectionGroup>

<sectionname="DaoConfigurationOverride"type="System.Configuration.NameValueSectionHandler"

</configSections>

<DaoConfigurationOverride>

<addkey="productDao.maxResults"value="1000"/>

</DaoConfigurationOverride>

<spring>

<context>

<resourceuri="assembly://DaoApp/DaoApp/objects.xml"/>

</context>

</spring>

</configuration>

Page 175: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Then the value of 1000 will be used to overlay the value of 2000 set in theSpring.NETconfigurationfileshownbelow

<objectsxmlns="http://www.springframework.net"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.nethttp://www.springframework.net/xsd/spring-objects.xsd"

<objectname="productDao"type="PropPlayApp.SimpleProductDao,PropPlayApp"

<propertyname="maxResults"value="2000"/>

<propertyname="dbConnection"ref="myConnection"/>

<propertyname="log"ref="daoLog"/>

</object>

<objectname="daoLog"type="Spring.Objects.Factory.Config.LogFactoryObject,Spring.Core"

<propertyname="logName"value="DAOLogger"/>

</object>

<objectname="myConnection"type="System.Data.Odbc.OdbcConnection,System.Data"

<propertyname="connectionstring">

<value>dsn=MyDSN;uid=sa;pwd=myPassword;</value>

</property>

</object>

<objectname="appConfigPropertyOverride"type="Spring.Objects.Factory.Config.PropertyOverrideConfigurer,Spring.Core"

<propertyname="configSections">

<value>DaoConfigurationOverride</value>

</property>

</object>

</objects>

5.9.2.3.IVariableSourceThe IVariableSource is the base interface for providing the ability to get thevalueofpropertyplaceholders(name-value)pairsfromavarietyofsources.Outofthebox,Spring.NETsupportsanumberofvariablesourcesthatallowuserstoobtain variable values from .NET config files, java-style property files,environmentvariables, command line arguments and the registry and the newconnectionstringsconfigurationsection in .NET2.0.The listof implementingclasses is listed below. Please refer to the SDK documentation for more

Page 176: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

information.

ConfigSectionVariableSource

PropertyFileVariableSource

EnvironmentVariableSource

CommandLineArgsVariableSource

RegistryVariableSource

SpecialFolderVariableSource

ConnectionStringsVariableSource

You use this by defining an instance ofSpring.Objects.Factory.Config.VariablePlaceholderConfigurer

in your configuration and set the propertyVariableSource to a singleIVariableSourceinstanceorthelistpropertyVariableSourcestoalistofIVariableSourceinstances.Inthecaseofthesamepropertydefined inmultipleIVariableSource implementations, the first one inthelistthatcontainsthepropertyvaluewillbeused.

<objecttype="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer,Spring.Core"

<propertyname="VariableSources">

<list>

<objecttype="Spring.Objects.Factory.Config.ConfigSectionVariableSource,Spring.Core"

<propertyname="SectionNames"value="CryptedConfiguration"

</object>

</list>

</property>

</object>

TheIVariableSourceinterfaceisshownbelow

publicinterfaceIVariableSource

{

stringResolveVariable(stringname);

}

Thisisasimplecontracttoimplementifyoushoulddecidetocreateyourown

Page 177: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

custom implemention.Lookat the sourcecodeof the current implementationsfor some inspiration if you go that route. To register your own customimplemenation,simplyconfigureVariablePlaceholderConfigurertorefertoyourclass.

5.9.3. Customizing instantiation logic usingIFactoryObjects

TheSpring.Objects.Factory.IFactoryObject interface istobeimplementedbyobjectsthatarethemselvesfactories.TheIFactoryObject interface isapointofpluggability into theSpringIoCcontainersinstantiationlogic.Ifyouhavesomecomplexinitializationcodethat is better expressed inC#asopposed to a (potentially) verbose amount ofXML, you can create your own IFactoryObject, write the complexinitialization inside that class, and then plug your customIFactoryObjectintothecontainer.

TheIFactoryObjectinterfaceprovidesonemethodandtwo(read-only)properties:

objectGetObject():hastoreturnaninstanceof theobject thisfactorycreates.Theinstancecanpossiblybeshared(dependingonwhetherthisfactoryprovidessingletonsorprototypes).

bool IsSingleton: has to return true if this IFactoryObjectreturnssingletons,falseotherwise.

TypeObjectType:has to returneither theobject type returnedbytheGetObject()methodornullifthetypeisn'tknowninadvance.

IFactoryObject

TheIFactoryObjectconceptandinterface isused inanumberofplaceswithinthe Spring Framework. Some examples of its use is described in Section 5.3.9,“Setting a reference using the members of other objects and classes.” for thePropertyRetrievingFactoryObject andFieldRetrievingFactoryObject. An additional use of creatingan custom IFactoryObject implementation is to retrieve an object from anembeddedresourcefileanduseittosetanotherobjectsdependency.Anexampleofthisisprovidedhere.

Page 178: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Finally, there is sometimes a need to ask a container for an actualIFactoryObject instance itself,not theobject itproduces.Thismaybeachieved by prepending the object id with '&' (sans quotes) when calling theGetObject method of the IObjectFactory (includingIApplicationContext). So for a givenIFactoryObject withan id of 'myObject', invoking GetObject("myObject") on thecontainer will return the product of theIFactoryObject, but invokingGetObject("&myObject") will return the IFactoryObjectinstanceitself.

5.9.3.1.IConfigurableFactoryObjectTheSpring.Objects.Factory.IConfigurableFactoryObject

interfaceinheritsfromIFactoryObjectinterfaceandaddsthefollowingproperty.

IObjectDefinition ProductTemplate : Gets thetemplateobjectdefinition thatshouldbeused toconfigure the instanceoftheobjectmanagedbythisfactory.

IConfigurableFactoryObject implementions you already haveexamplesofinSection27.3,“Client-side”areWebServiceProxyFactory.

Page 179: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.10.TheIApplicationContextWhile theSpring.Objects namespace provides basic functionality formanaging and manipulating objects, often in a programmatic way, theSpring.Context namespace introduces theIApplicationContext interface, which enhances the functionalityprovidedbytheIObjectFactoryinterfaceinamoreframework-orientedstyle. Many users will use ApplicationContext in a completely declarativefashion, not even having to create itmanually, but instead relying on supportclassessuchasthe.NETconfigurationsectionhandlerssuchasContextHandlerandWebContextHandlertogethertodeclarativelydefinetheApplicationContextandretrieveit thoughaContextRegistry.(Ofcourseit isstillpossibletocreateanIApplicationContextProgramatically).

The basis for the context module is the IApplicationContextinterface, located in theSpring.Contextnamespace.Deriving from theIObjectFactory interface, it provides all the functionality of theIObjectFactory. To be able to work in a more framework-orientedfashion, using layering and hierarchical contexts, theSpring.Contextnamespacealsoprovidesthefollowingfunctionality

Loadingofmultiple (hierarchical) contexts, allowing some of them to befocusedandusedononeparticular layer,forexampletheweblayerofanapplication.

Access to localized resources at the application level by implementingIMessageSource.

UniformaccesstoresourcesthatcanbereadinasanInputStream,suchasURLsandfilesbyimplementingIResourceLoader

LooselyCoupledEventPropagation.Publishers and subscribers of eventsdonothavetobedirectlyawareofeachotherastheyregistertheirinterestindirectlythroughtheapplicationcontext.

5.10.1.IObjectFactoryorIApplicationContext?Shortversion:useanIApplicationContextunlessyouhavea reallygoodreasonfornotdoingso.Forthoseofyouthatarelookingforslightlymore

Page 180: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

depthastothe'butwhy'oftheaboverecommendation,keepreading.AstheIApplicationContext includesall thefunctionality theobjectfactoryviaitsinheritanceoftheIObjectFactoryinterface,itisgenerallyrecommended to be used over the IObjectFactory except for a fewlimited situations where memory consumption might be critical. This maybecome more important if the .NET Compact Framework is supported. Thehistory of IObjectFactory comes from the Spring Java framework,where the use of Spring in Applets was a concern to reduce memoryconsumption. However, for most 'typical' enterprise applications and systems,the IApplicationContext is what you will want to use. Springgenerallymakes heavy use of theIObjectPostProcessor extensionpoint (to effect proxying and suchlike), and if you are using just a plainIObjectFactory thena fairamountof support suchas transactionsandAOPwill not take effect (at least notwithout some extra steps on your part),which could be confusing because nothing will actually be wrong with theconfiguration.Find below a feature matrix that lists what features are provided by theIObjectFactory and IApplicationContext interfaces (andattendant implementations). The following sections describe functionality thatIApplicationContext adds to the basic IObjectFactorycapabilitiesinalotmoredepththanthesaidfeaturematrix.)

Table5.7.FeatureMatrixFeature IObjectFactoryIApplicationContext

Objectinstantiation/wiring Yes Yes

AutomaticIObjectPostProcessor

registrationNo Yes

AutomaticIObjectFactoryPostProcessor

registrationNo Yes

ConvenientIMessageSourceaccess No Yes

ApplicationEventpublication No Yes

Page 181: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Singletonservicelocatorstyleaccess No Yes

Declarativeregistrationofcustomresourceprotocolhandler,XMLParsersforobjectdefinitions,andtypealiases

No Yes

Page 182: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.11.ConfigurationofIApplicationContextWell known locations in the .NET application configuration file are used toregisterresourcehandlers,customparsers,typealias,andcustomtypeconvertsinaddition to thecontextandobjectssectionsmentionedpreviously.Asample.NETapplicationconfiguration file showingall these features is shownbelow.Each section requires the use of a custom configuration section handler.Notethatthetypesshownforresourcehandlersandparsersarefictional.

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

<sectionname="resources"type="Spring.Context.Support.

<sectionname="typeAliases"type="Spring.Context.Support.TypeAliasesSectionHandler,Spring.Core"

<sectionname="typeConverters"type="Spring.Context.Support.TypeConvertersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Aop.Config.AopNamespaceParser,Spring.Aop"

<parsertype="Spring.Data.Config.DatabaseNamespaceParser,Spring.Data"

</parsers>

<resources>

<handlerprotocol="db"type="MyCompany.MyApp.Resources.MyDbResource"

</resources>

<contextcaseSensitive="false">

<resourceuri="config://spring/objects"/>

<resourceuri="db://user:pass@dbName/MyDefinitionsTable"

</context>

Page 183: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<typeAliases>

<aliasname="WebServiceExporter"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

<aliasname="DefaultPointcutAdvisor"type="Spring.Aop.Support.DefaultPointcutAdvisor,Spring.Aop"

<aliasname="AttributePointcut"type="Spring.Aop.Support.AttributeMatchMethodPointcut,Spring.Aop"

<aliasname="CacheAttribute"type="Spring.Attributes.CacheAttribute,Spring.Core"

<aliasname="MyType"type="MyCompany.MyProject.MyNamespace.MyType,MyAssembly"

</typeAliases>

<typeConverters>

<converterfor="Spring.Expressions.IExpression,Spring.Core"

<converterfor="MyTypeAlias"type="MyCompany.MyProject.Converters.MyTypeConverter,MyAssembly"

</typeConverters>

<objectsxmlns="http://www.springframework.net">

...

</objects>

</spring>

</configuration>

The new sections are described below. The attribute caseSensitiveallowstheforbothIObjectFactoryandIApplicationContextimplementations to not pay attention to the case of the object names. This isimportantinwebapplicationssothatASP.NETpagescanberesolvedinacaseindependentmanner.Thedefaultvalueistrue.

5.11.1.RegisteringcustomparsersInsteadofusingthedefaultXMLschemathat isgeneric innature todefineanobject's properties and dependencies, you can create your own XML schemaspecifictoanapplicationdomain.ThishasthebenefitofbeingeasiertotypeandgettingXMLintellisense for theschemabeingused.Thedownside is thatyouneedtowritecodethatwill transformthisXMLintoSpringobjectdefinitions.One would typically implement a custom parser by deriving from the classObjectsNamespaceParser and overriding the methods intParseRootElement(XmlElement root,

XmlResourceReader reader) and int

ParseElement(XmlElement element,

Page 184: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

XmlResourceReaderreader). Registering custom parsers outsideofApp.configwillbeaddressedinafuturerelease.To register a custom parser register a section handler of the typeSpring.Context.Support.NamespaceParsersSectionHandler

in the configSecitons section of App.config. The parser configuration sectioncontainsoneormore<parser>elementseachwithatypeattribute.BelowisanexamplethatregistersallthenamespacesprovidedinSpring.

Note

AsofSpring.NET1.2.0itisnolongernecessarytoexplicitlyconfigurethenamespaceparsersthatcomewithSpringviaacustomsectioninApp.config.Youwillstillneedtoregistercustomnamespaceparsersifyouarewritingyourown.

<configuration>

<configSections>

<sectionGroupname="spring">

<!--otherconfigurationsectionhandlerdefinedhere-->

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Aop.Config.AopNamespaceParser,Spring.Aop"

<parsertype="Spring.Data.Config.DatabaseNamespaceParser,Spring.Data"

<parsertype="Spring.Transaction.Config.TxNamespaceParser,Spring.Data"

<parsertype="Spring.Validation.Config.ValidationNamespaceParser,Spring.Core"

<parsertype="Spring.Remoting.Config.RemotingNamespaceParser,Spring.Services"

</parsers>

</spring>

</configuration>

You can also register custom parser programmatically using theNamespaceParserRegistry.Here isanexample takenfromthecodeused in theTransactionsQuickstartapplication.

Page 185: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));

NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));

NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));

IApplicationContextcontext=

newXmlApplicationContext("assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/system-test-local-config.xml"

5.11.2.RegisteringcustomresourcehandlersCreating a custom resource handler means implementing the IResourceinterface. The base classAbstractResource is a useful starting point.LookattheSpringsourceforclassessuchasFileSystemResourceorAssemblyResource for implementation tips. You can register yourcustom resource handler either within App.config, as shown in the programlisting at the start of this section using a.ResourceHandlersSectionHandler or define an object of thetypeSpring.Objects.Factory.Config.ResourceHandlerConfigurer

as you would any other Spring managed object. An example of the latter isshownbelow:

<objectid="myResourceHandlers"type="Spring.Objects.Factory.Config.

<propertyname="ResourceHandlers">

<dictionary>

<entrykey="db"value="MyCompany.MyApp.Resources.MyDbResource,MyAssembly"

</dictionary>

</property>

</object>

5.11.3.RegisteringTypeAliasesTypealiasesallowyou to simplifySpringconfiguration fileby replacingfullyqualified type name with an alias for frequently used types. Aliases can beregistered both within a config file and programatically and can be usedanywhere in the context config file where a fully qualified type name isexpected.Typealiasescanalsobedefinedforgenerictypes.Onewaytoconfigureatypealiasistodefinetheminacustomconfigsectionin

Page 186: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

theWeb/App.configfileforyourapplication,aswellasthecustomconfigurationsectionhandler.SeethepreviousXMLconfigurationlistingforanexamplethatmakesanaliasfortheWebServiceExportertype.Onceyouhavealiasesdefined,youcan simplyuse themanywherewhereyouwouldnormally specifya fullyqualifiedtypename:

<objectid="MyWebService"type="WebServiceExporter">

...

</object>

<objectid="cacheAspect"type="DefaultPointcutAdvisor">

<propertyname="Pointcut">

<objecttype="AttributePointcut">

<propertyname="Attribute"value="CacheAttribute"

</object>

</property>

<propertyname="Advice"ref="aspNetCacheAdvice"/>

</object>

To register a type alias register a section handler of the typeSpring.Context.Support.TypeAliasesSectionHandler

intheconfigSecitonssectionofApp.config.Thetypealiasconfigurationsectioncontains oneormore<alias> elements eachwith a name and a type attribute.BelowisanexamplethatregistersthealiasforWebServiceExporter

<configuration>

<configSections>

<sectionGroupname="spring">

<!--otherconfigurationsectionhandlerdefinedhere-->

<sectionname="parsers"type="Spring.Context.Support.TypeAliasesSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<typeAliases>

<aliasname="WebServiceExporter"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

</typeAliases>

</spring>

Page 187: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</configuration>

For an example showing type aliases for generic types seeSection 5.2.5, “Objectcreationofgenerictypes”.Another way is to define an object of the typeSpring.Objects.Factory.Config.TypeAliasConfigurer

within the regular<objects> sectionof any standardSpring configuration file.Thisapproachallowsformoremodularityindefiningtypealiases,forexampleifyoucan't accessApp.config/Web.config.Anexampleof registrationusing aTypeAliasConfigurerisshownbelow

<objectid="myTypeAlias"type="Spring.Objects.Factory.Config.TypeAliasConfigurer,Spring.Core"

<propertyname="TypeAliases">

<dictionary>

<entrykey="WebServiceExporter"value="Spring.Web.Services.WebServiceExporter,Spring.Web"

<entrykey="DefaultPointcutAdvisor"value="Spring.Aop.Support.DefaultPointcutAdvisor,Spring.Aop"

<entrykey="MyType"value="MyCompany.MyProject.MyNamespace.MyType,MyAssembly"

</dictionary>

</property>

</object>

5.11.4.RegisteringTypeConvertersThe standard .NET mechanism for specifying a type converter is to add aTypeConverter attribute to a type definition to specify the type of theConverter.This is thepreferredwayofdefining typeconverters ifyoucontrolthesourcecode for the type thatyouwant todefineaconverter for.However,thisconfigurationsectionallowsyoutospecifyconvertersforthetypesthatyoudon't control, and it also allows you to override some of the standard typeconverters,suchastheonesthataredefinedforsomeofthetypesinthe.NETBaseClassLibrary.You can specify the type converters in App.config by usingSpring.Context.Support.TypeConvertersSectionHandler as shown before ordefine an object of the typeSpring.Objects.Factory.Config.CustomConverterConfigurer

AnexampleofregistrationusingaCustomConverterConfigurerisshownbelow

Page 188: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="myTypeConverters"type="Spring.Objects.Factory.Config.CustomConverterConfigurer,Spring.Core"

<propertyname="CustomConverters">

<dictionary>

<entrykey="System.Date"value="MyCompany.MyProject.MyNamespace.MyCustomDateConverter,MyAssembly"

</dictionary>

</property>

</object>

Page 189: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.12. Added functionality of theIApplicationContext

As already stated in the previous section, theIApplicationContexthasacoupleoffeaturesthatdistinguishitfromtheIObjectFactory.Letusreviewthemone-by-one.

5.12.1.ContextHierarchiesYou can structure the configuration information of application context intohierarchiesthatnaturallyreflecttheinternallayeringofyourapplication.Asanexample,abstractobjectdefinitionsmayappear inaparentapplicationcontextconfigurationfile,possiblyasanembeddedassemblyresourcesoasnottoinviteaccidentalchanges.

<spring>

<context>

<resourceuri="assembly://MyAssembly/MyProject/root-objects.xml"

<contextname="mySubContext">

<resourceuri="file://objects.xml"/>

</context>

</context>

</spring>

Thenestingofcontextelementsreflects theparent-childhierarchyyouarecreating.Thenestingcanbetoanylevelthoughitisunlikelyonewouldneedadeepapplicationhierarchy.Thexmlfilemustcontainthe<objects>astherootname.Anotherexampleofahierarchy,butusingsectionsintheapplicationconfigurationfileisshownbelow.

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

<sectionGroupname="child">

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

</sectionGroup>

</sectionGroup>

</configSections>

Page 190: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<spring>

<contextname="ParentContext">

<resourceuri="config://spring/objects"/>

<contextname="ChildContext">

<resourceuri="config://spring/child/objects"/>

</context>

</context>

<objectsxmlns="http://www.springframework.net">

...

</objects>

<child>

<objectsxmlns="http://www.springframework.net">

...

</objects>

</child>

</spring>

Asareminder,thetypeattributeofthecontexttagisoptionalanddefaultstoSpring.Context.Support.XmlApplicationContext.Thenameof the context canbeused in conjunctionwith the service locator class,ContextRegistry,discussedinSection5.15,“ServiceLocatoraccess”

5.12.2.UsingIMessageSourceThe IApplicationContext interface extends an interface calledIMessageSource andprovides localization (i18nor internationalization)services for textmessages and other resource data types such as images. Thisfunctionalitymakesiteasiertouse.NET'slocalizationfeaturesatanapplicationlevel and also offers some performance enhancements due to caching ofretrieved resources. Together with the NestingMessageSource,capable of hierarchical message resolving, these are the basic interfaces

Page 191: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Spring.NETprovidesforlocalization.Let'squicklyreviewthemethodsdefinedthere:

string GetMessage(string name): retrieves a messagefromtheIMessageSourceandusingCurrentUICulture.

string GetMessage(string name, CultureInfo

cultureInfo):retrievesamessagefromtheIMessageSourceusingaspecifiedculture.

string GetMessage(string name, params

object[] args): retrieves a message from theIMessageSource using a variable list of arguments as replacementvalues in the message. The CurrentUICulture is used to resolve themessage.

string GetMessage(string name, CultureInfo

cultureInfo, params object[] args): retrieves amessagefromtheIMessageSourceusingavariablelistofargumentsas replacement values in the message. The specified culture is used toresolvethemessage.

string GetMessage(string name, string

defaultMessage, CultureInfo culture, params

object[] arguments): retrieves a message from theIMessageSource using a variable list of arguments as replacementvaluesinthemessage.Thespecifiedcultureisusedtoresolvethemessage.Ifnomessagecanberesolved,thedefaultmessageisused.

string GetMessage(IMessageSourceResolvable

resolvable, CultureInfo culture) : all propertiesused in the methods above are also wrapped in a class - theMessageSourceResolvable,whichyoucanuseinthismethod.

object GetResourceObject(string name):Get alocalized resource object, i.e. Icon, Image, etc. given the resource name.TheCurrentUICultureisusedtoresolvetheresourceobject.

object GetResourceObject(string name,

CultureInfocultureInfo):Get a localized resource object,

Page 192: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

i.e.Icon,Image,etc.giventheresourcename.Thespecifiedcultureisusedtoresolvetheresourceobject.

void ApplyResources(object value, string

objectName, CultureInfo cultureInfo): Uses aComponentResourceManagertoapplyresourcestoallobjectpropertiesthathave a matching key name. Resource key names are of the formobjectName.propertyName

WhenanIApplicationContextgetsloaded,itautomaticallysearchesforanIMessageSourceobjectdefined in thecontext.Theobjecthas tohavethenamemessageSource.Ifsuchanobjectisfound,allcallstothemethods described above will be delegated to the message source that wasfound. If no message source was found, the IApplicationContextcheckstoseeifithasaparentcontainingasimilarobject,withasimilarname.Ifso, itusesthatobjectastheIMessageSource. If itcan't findanysourceformessages,anemptyStaticMessageSourcewillbe instantiated inordertobeabletoacceptcallstothemethodsdefinedabove.

Fallbackbehavior

ThefallbackrulesforlocalizedresourcesseemtohaveabugthatisfixedbyapplyingServicePack1for.NET1.1.ThisaffectstheuseofIMessageSource.GetMessagemethodsthatspecifyCultureInfo.Thecoreoftheissueinthe.NETBCListhemethodResourceManager.GetObjectthatacceptsCultureInfo.

Spring.NET provides twoIMessageSource implementations. These areResourceSetMessageSource and StaticMessageSource.Both implement IHierarchicalMessageSource to resolvemessages hierarchically. The StaticMessageSource is hardly everused but provides programmatic ways to add messages to the source. TheResourceSetMessageSource ismore interestingandan example isprovidedforinthedistributionanddiscussedmoreextensivelyintheChapter33,IoC Quickstarts section. The ResourceSetMessageSource isconfigured by providing a list ofResourceManagers.When amessagecode is tobe resolved, the listofResourceManagers is searched to resolve thecode. For eachResourceManager aResourceSet is retrieved and

Page 193: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

asked to resolve the code.Note that this search does not replace the standardhub-and-spoke search for localized resources. The ResourceManagers listspecifiesthemultiple'hubs'wherethestandardsearchstarts.

<objectname="messageSource"type="Spring.Context.Support.ResourceSetMessageSource,Spring.Core"

<propertyname="resourceManagers">

<list>

<value>Spring.Examples.AppContext.MyResource,Spring.Examples.AppContext

</list>

</property>

</object>

You can specify the arguments to construct aResourceManager as a twopartstringvaluecontaining thebasenameof the resource and the assemblyname.This will be converted to a ResourceManager via theResourceManagerConverterTypeConverter.This converter canbesimilarly used to set a property on any object that is of the typeResourceManager. You may also specify an instance of theResourceManagertouseviaanobjectreference.TheconvenienceclassSpring.Objects.Factory.Config.ResourceManagerFactoryObject

canbeusedtoconvenientlycreateaninstanceofaResourceManager.

<objectname="myResourceManager"type="Spring.Objects.Factory.Config.ResourceManagerFactoryObject,Spring.Core"

<propertyname="baseName">

<value>Spring.Examples.AppContext.MyResource</value>

</property>

<propertyname="assemblyName">

<value>Spring.Examples.AppContext</value>

</property>

</object>

Inapplicationcode,acalltoGetMessagewillretrieveaproperlylocalizedmessage stringbasedon a codevalue.Any arguments present in the retrievedstring are replaced using String.Format semantics. TheResourceManagers, ResourceSets and retrieved strings are cached to providequicker lookup performance. The key 'HelloMessage' is contained in theresourcefilewithavalueofHello{0}{1}.The followingcall on theapplication contextwill return the stringHelloMr.Anderson.Note

Page 194: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

that the caching of ResourceSets is via the concatenation of theResourceManagerbasenameandtheCultureInfostring.Thiscombinationmustbeunique.

stringmsg=ctx.GetMessage("HelloMessage",

newobject[]{"Mr.","Anderson"},

CultureInfo.CurrentCulture);

Itispossibletochaintheresolutionofmessagesbypassingarguments thatarethemselvesmessagestoberesolvedgivingyougreaterflexibilityinhowyoucanstructureyourmessageresolution.Thisisachievedbypassingasanargumentaclass that implementsIMessageResolvable instead of a string literal.TheconvenienceclassDefaultMessageResolvable isavailable forthis purpose. As an example if the resource file contains a key nameerror.requiredthathasthevalue'{0}isrequired{1}'andanother key namefield.firstnamewith the value 'Firstname'.Thefollowingcodewillcreatethestring'Firstnameisrequireddude!'

string[]codes={"field.firstname"};

DefaultMessageResolvabledmr=newDefaultMessageResolvable(codes,

ctx.GetMessage("error.required",

newobject[]{dmr,"dude!"},

CultureInfo.CurrentCulture));

The examples directory in the distribution contains an example program,Spring.Examples.AppContext, that demonstrates usage of thesefeatures.TheIMessageSourceAware interface can also be used to acquire areferencetoanyIMessageSourcethathasbeendefined.Anyobjectthatis defined in an IApplicationContext that implements theIMessageSourceAware interfacewill be injectedwith the applicationcontext's IMessageSource when it (the object) is being created andconfigured.

5.12.3.UsingresourceswithinSpring.NET

Page 195: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Alotofapplicationsneedtoaccessresources.Resourceshere,mightmeanfiles,butalsonewsfeedsfromtheInternetornormalwebpages.Spring.NETprovidesa clean and transparent way of accessing resources in a protocol independentway. The IApplicationContext has a method(GetResource(string)) to take care of this. Refer to Section 7.1,“Introduction” for more information on the string format to use and theIResourceabstractioningeneral.

5.12.4.LooselycoupledeventsThe Eventing Registry allows developers to utilize a loosely coupled eventwiring mechanism. By decoupling the event publication and the eventsubscription,mostofthemundaneeventwiringishandledbytheIoCcontainer.Eventpublisherscanpublish theirevent toacentral registry, eitherallof theirevents or a subset basedon criteria such asdelegate type,name, returnvalue,etc... Event subscribers can choose to subscribe to any number of publishedevents.Subscriberscansubscribertoeventsbasedonthetypeofobjectexposingthem, allowing one subscriber to handle all events of a certain type withoutregardstohowmanydifferentinstancesofthattypearecreated.The Spring.Objects.Events.IEventRegistry interfacerepresentsthecentralregistryanddefinespublishandsubscribemethods.

void PublishEvents( object sourceObject ):publishesalleventsof thesourceobject tosubscribersthatimplementthecorrecthandlermethods.

voidSubscribe(objectsubscriber):The subscriberreceivesalleventsfromthesourceobjectforwhichithasmatchinghandlermethods.

void Subscribe(object subscriber, Type

targetSourceType): The subscriber receives all events from asource object of a particular type for which it has matching handlermethods.

voidUnsubscribe(objectsubscriber):Unsubscribeall events from the source object for which it has matching handlermethods.

void Unsubscribe(object subscriber, Type

Page 196: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

targetSourceType):Unsubscribealleventsfromasourceobjectofaparticulartypeforwhichithasmatchinghandlermethods.

IApplicationContext implements this interface and delegates theimplementation to an instance ofSpring.Objects.Events.Support.EventRegistry. Youare free to create and use asmany EventRegistries as you like but since it iscommon to use only one in an application, IApplicationContextprovidesconvenientaccesstoasingleinstance.Within theexample/Spring/Spring.Examples.EventRegistry

directoryyouwill findanexampleonhowtousethisfunctionality.Whenyouopen up the project, themost interesting file is the EventRegistryApp.cs file.This application loads a set of object definitions from the applicationconfigurationfileintoanIApplicationContextinstance.Fromthere,threeobjects are loaded up: one publisher and two subscribers. The publisherpublishesitseventstotheIApplicationContextinstance:

//CreatetheApplicationcontextusingconfigurationfile

IApplicationContextctx=ContextRegistry.GetContext();

//Getsthepublisherfromtheapplicationcontext

MyEventPublisherpublisher=(MyEventPublisher)ctx.GetObject(

//Publisheseventstothecontext.

ctx.PublishEvents(publisher);

One of the two subscribers subscribes to all events published to theIApplicationContext instance,using the publisher type as the filtercriteria.

//Getsfirstinstanceofsubscriber

MyEventSubscribersubscriber=(MyEventSubscriber)ctx.GetObject(

//Getssecondinstanceofsubscriber

MyEventSubscribersubscriber2=(MyEventSubscriber)ctx.GetObject(

//SubscribesthefirstinstancetotheanyeventspublishedbythetypeMyEventPublisher

ctx.Subscribe(subscriber,typeof(MyEventPublisher));

Page 197: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Thiswillwire the first subscriber to the original event publisher.Anytime theevent publisher fires an event,(publisher.ClientMethodThatTriggersEvent1();) thefirst subscriberwill handle the event, but the second subscriberwill not. Thisallowsforselectivesubscription,regardlessoftheoriginalprototypedefinition.

5.12.5. Event notification fromIApplicationContext

Event handling in theIApplicationContext is provided through theIApplicationListener interface that contains the single methodvoid OnApplicationEvent( object source,

ApplicationEventArgs applicationEventArgs ).Classes that implement the IApplicationListener interface areautomatically registeredasa listenerwith theIApplicationContext.Publishing an event is done via the context's PublishEvent(ApplicationEventArgs eventArgs ) method. ThisimplementationisbasedonthetraditionalObserverdesignpattern.The event argument type,ApplicationEventArgs, adds the time ofthe event firing as a property.The derived classContextEventArgs isused to notify observers on the lifecycle events of the application context. ItcontainsapropertyContextEventEvent thatreturnstheenumerationRefreshedorClosed..TheRefreshedenumerationvalueindicatedthat the IApplicationContext was either initialized or refreshed.Initializedheremeansthatallobjectsareloaded,singletonsarepre-instantiatedand the IApplicationContext is ready for use. The Closed ispublished when the IApplicationContext is closed using theDispose() method on theIConfigurableApplicationContext interface. Closed heremeansthatsingletonsaredestroyed.Implementing custom events can be done as well. Simply call thePublishEventmethodontheIApplicationContext,specifyingaparameterwhichisaninstanceofyourcustomeventargumentsubclass.

Page 198: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Let'shavealookatanexample.First,theIApplicationContext:

<objectid="emailer"type="Example.EmailObject">

<propertyname="blackList">

<list>

<value>[email protected]</value>

<value>[email protected]</value>

<value>[email protected]</value>

</list>

</property>

</object>

<objectid="blackListListener"type="Example.BlackListNotifier"

<propertyname="notificationAddress">

<value>[email protected]</value>

</property>

</object>

andthen,theactualobjects:

publicclassEmailObject:IApplicationContextAware{

//theblacklist

privateIListblackList;

publicIListBlackList

{

set{this.blackList=value;}

}

publicIApplicationContextApplicationContext

{

set{this.ctx=value;}

}

publicvoidSendEmail(stringaddress,stringtext){

if(blackList.contains(address))

{

BlackListEventevt=newBlackListEvent(address,text);

ctx.publishEvent(evt);

return;

}

Page 199: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

//sendemail...

}

}

publicclassBlackListNotifier:IApplicationListener

{

//notificationaddress

privatestringnotificationAddress;

publicstringNotificationAddress

{

set{this.notificationAddress=value;}

}

publicvoidOnApplicationEvent(ApplicationEventevt)

{

if(evtinstanceofBlackListEvent)

{

//notifyappropriateperson

}

}

}

Page 200: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.13.CustomizedbehaviorintheApplicationContextTheIObjectFactoryalreadyoffersanumberofmechanisms tocontrolthe lifecycle of objects deployed in it (such as marker interfaces likeIInitializingObject and System.IDisposable, theirconfiguration only equivalents such as init-method and destroy-method) attributes in an XmlObjectFactory configuration, and object post-processors. In anIApplicationContext, all of these still work, butadditionalmechanisms are added for customizing behavior of objects and thecontainer.

5.13.1. The IApplicationContextAware markerinterfaceAll marker interfaces available with ObjectFactories still work. TheIApplicationContext does add one extra marker interface whichobjects may implement, IApplicationContextAware. An objectwhichimplementsthis interfaceandisdeployedintothecontextwillbecalledback on creation of the object, using the interface'sApplicationContext property, and provided with a reference to thecontext,whichmaybestoredforlaterinteractionwiththecontext.

5.13.2.TheIObjectPostProcessorObject post-processors are classes which implement theSpring.Objects.Factory.Config.IObjectPostProcessor

interface,havealreadybeenmentioned.Itisworthmentioningagainherethough,that post-processors are much more convenient to use inIApplicationContexts than in plain IObjectFactory

instances. In an IApplicationContext, any deployed object whichimplementstheabovemarkerinterfaceisautomaticallydetectedandregisteredasanobjectpost-processor, tobecalledappropriatelyatcreationtimeforeachobjectinthefactory.

5.13.3.TheIObjectFactoryPostProcessorObject factory post-processors are classes which implement the

Page 201: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Spring.Objects.Factory.Config.IObjectFactoryPostProcessor

interface,havealreadybeenmentioned.Itisworthmentioningagainherethough,that object factory post-processors are much more convenient to use inIApplicationContexts. In an IApplicationContext, anydeployedobjectwhich implements theabovemarker interface isautomaticallydetectedasanobjectfactorypost-processor,tobecalledattheappropriatetime.

5.13.4.ThePropertyPlaceholderConfigurerThePropertyPlaceholderConfigurerhasalreadybeendescribedin the context of its use within an IObjectFactory. It is worthmentioninghere though, that it is generallymore convenient to use itwith anIApplicationContext,sincethecontextwillautomaticallyrecognizeand apply any object factory post-processors, such as this one,when they aresimplydeployedintoitlikeanyotherobject.Thereisnoneedforamanualsteptoexecuteit.

Page 202: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.14. Configuration of ApplicationContext without usingXMLThe class GenericApplicationContext can be used as a basis for creating anIApplicationContext implementation that read the container metadata fromsourcesotherthanXML.Thiscouldbebyscanningobjectsina.DLLforknownattributes or a scripting language that leverages a DSL to create terseIObjectDefinitions. There is a class,Spring.Objects.Factory.Support.ObjectDefinitionBuilder offers someconveniencemethodsforcreatinganIObjectDefinitioninalessverbosemannerthanusingtheRootObjectDefinitionAPI.ThefollowingshowshowtoconfiguretheGenericApplicationContext to read fromXML, just so show familiar APIusage

GenericApplicationContextctx=newGenericApplicationContext();

XmlObjectDefinitionReaderreader=newXmlObjectDefinitionReader(ctx);

reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextB.xml"

reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextC.xml"

reader.LoadObjectDefinitions("assembly://Spring.Core.Tests/Spring.Context.Support/contextA.xml"

ctx.Refresh();

The implementation of IObjectDefinitionReader is responsible for creating theconfigurationmetadata,i.e.,implementationsofRootObjectDefinition,etc.Noteawebversionofthisapplicationclasshasnotyetbeenimplemented.Anexample,withayettobecreatedDLLscanner,thatwouldgetconfigurationmetadata from the .dll named MyAssembly.dll located in the runtime path,wouldlooksomethinglikethis

GenericApplicationContextctx=newGenericApplicationContext();

ObjectDefinitionScannerscanner=newObjectDefinitionScanner(ctx);

scanner.scan("MyAssembly.dll");

ctx.refresh();

RefertotheSpringAPIdocumentationformoreinformation.

Page 203: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.15.ServiceLocatoraccessThemajorityof thecode insideanapplication isbestwritten inaDependencyInjection (Inversion of Control) style, where that code is served out of anIObjectFactory or IApplicationContext container, has itsown dependencies supplied by the container when it is created, and iscompletely unaware of the container.However, there is sometimes a need forsingleton (or quasi-singleton) style access to an IObjectFactory orIApplicationContext. For example, third party code may try toconstructanewobjectdirectlywithouttheabilitytoforceittogettheseobjectsout of the IObjectFactory. Similarly, nested user control components in aWinForms application are created inside the generated code inInitializeComponent. If this user control would like to obtain references toobjects contained in the container it canuse the service locator style approachand'reachout'frominsidethecodetoobtaintheobjectitrequires.(NotesupportforDIinWinFormsisunderdevelopment.)The Spring.Context.Support.ContextRegistry classallows you to obtain a reference to anIApplicationContext via astaticlocatormethod.TheContextRegistryisinitializedwhencreatinganIApplicationContext throughuse of theContextHandlerdiscussedpreviously.ThesimplestaticmethodGetContext()canthenbeused to retrieve the context. Alternatively, if you create anIApplicationContextthoughothermeansyoucanregisteritwiththeContextRegistry via the method void

RegisterContext(IApplicationContext context) inthe start-up code of your application. Hierarchical context retrieval is alsosupportedthoughtheuseoftheGetContext(stringname)method,forexample:

IApplicationContexctx=ContextRegistry.GetContext("mySubContext"

This would retrieve the nested context for the context configuration shownpreviously.

<spring>

<context>

Page 204: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<resourceuri="assembly://MyAssembly/MyProject/root-objects.xml"

<contextname="mySubContext">

<resourceuri="file://objects.xml"/>

</context>

</context>

</spring>

DonotcallContextRegistry.GetContextwithinaconstructorasitwill result inandendless recursion. (This isscheduled tobefixed in1.1.1) In thiscase it isquite likely you can use the IApplicationContextAware interface and thenretrieveotherobjectsinaservicelocatorstyleinsideaninitializationmethod.TheContextRegistry.Clear() method will remove all contexts.On .NET 2.0, this will also call the ConfigurationManager's RefreshSectionmethodsothattheSpringcontextconfigurationsectionwillberereadfromdiskwhenitisretrievedagain.NotethatinawebapplicationRefeshSectionwillnotworkasadvertisedandyouwillneed to touch theweb.configfiles to reloadaconfiguration.

Page 205: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

5.16.StereotypeattributesBeginningwithSpring1.2,the[Repository]attributewasintroducedasamarkerforanyclassthatfulfillstheroleorstereotypeofarepository(a.k.a.DataAccessObject orDAO).Among the possibilities for leveraging such amarker is theautomatictranslationofexceptionsasdescribedinExceptionTranslation.Spring1.2introducesfurtherstereotypeannotations:[Component]and[Service].[Component]servesasagenericstereotypeforanySpring-managedcomponent;whereas,[Repository]and[Service]serveasspecializationsof[Component]formorespecificusecases(e.g.,inthepersistenceandservicelayers,respectively).The ASP.NET MVC [Controller] attribute will serve this purpose for thecontroller layer. What this means is that you can annotate your componentclasseswith[Component],butbyannotatingthemwith[Repository]or[Service]yourclassesaremoreproperlysuitedforprocessingbytoolsorassociatingwithaspects. For example, these stereotype annotations make ideal targets forpointcuts.Ofcourse,itisalsopossiblethat[Repository]and[Service]maycarryadditionalsemanticsinfuturereleasesoftheSpringFramework.Thus,ifyouaremaking a decision between using [Component] or [Service] for your servicelayer, [Service] is clearly the better choice. Similarly, as stated above,[Repository]isalreadysupportedasamarkerforautomaticexceptiontranslationinyourpersistencelayer.ThenextversionofSpringwillusethe[Component]attribute to perform attribute based autowiring by-type as in the Spring JavaFramework.

[1]SeethesectionentitledSection3.1,“InversionofControl”[2]MoreinformationaboutassemblynamescanbefoundintheAssemblyNamessectionofthe.NETFrameworkDeveloper'sGuide(installedaspartofthe.NETSDK), or online at Microsoft's MSDN website, by searching for AssemblyNames.[3] More information about creating custom TypeConverter

implementations can be found online at Microsoft's MSDN website, bysearchingforImplementingaTypeConverter.

Page 206: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter6.TheIObjectWrapperandTypeconversion

Page 207: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

6.1.IntroductionThe concepts encapsulated by the IObjectWrapper interface arefundamental to the workings of the core Spring.NET libraries The typicalapplication developer most probably will not ever have the need to use theIObjectWrapper directly... because this is reference documentationhowever,wefeltthatsomeexplanationofthiscoreinterfacemightberight.TheIObjectWrapper isexplained in thischapter since ifyouweregoing touse it at all, youwould probably do thatwhen trying to bind data to objects,which, nicely enough, is precisely the area that the IObjectWrapperaddresses.

Page 208: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

6.2.ManipulatingobjectsusingtheIObjectWrapperOne quite important concept of the Spring.Objects namespace isencapsulated in the definition IObjectWrapper interface and itscorresponding implementation, the ObjectWrapper class. ThefunctionalityofferedbytheIObjectWrapperincludesmethodstosetandget property values (either individually or in bulk), get property descriptors(instancesof theSystem.Reflection.PropertyInfoclass),andto query the readability and writability of properties. TheIObjectWrapper also offers support for nested properties, enabling thesetting of properties on subproperties to an unlimited depth. TheIObjectWrapper usually isn't used by application code directly, but byframeworkclassessuchasthevariousIObjectFactoryimplementations.

Theway theIObjectWrapper works is partly indicated by its name: itwrapsanobjecttoperformactionsonawrappedobjectinstance...suchactionswould include the setting and getting of properties exposed on the wrappedobject.Note:theconceptsexplainedinthissectionarenotimportanttoyouifyou'renotplanningtoworkwiththeIObjectWrapperdirectly.

6.2.1.SettingandgettingbasicandnestedpropertiesSetting andgettingproperties is doneusing theSetPropertyValue()andGetPropertyValue() methods, for which there are a couple ofoverloadedvariants.Thedetailsofthevariousoverloads(includingreturnvaluesandmethod parameters) are all described in the extensiveAPI documentationsuppliedasapartoftheSpring.NETdistribution.The aforementioned SetPropertyValue() andGetPropertyValue() methods have a number of conventions forindicating the path of a property. A property path is an expression thatimplementationsoftheIObjectWrapperinterfacecanusetolookupthepropertiesofthewrappedobject;someexamplesofpropertypathsinclude...

Table6.1.Examplesofpropertypaths

Page 209: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Path Explanationname Indicatesthenamepropertyofthewrappedobject.

account.name Indicatesthenestedpropertynameoftheaccountpropertyofthewrappedobject.

account[2]

Indicatesthethirdelementoftheaccountpropertyofthewrappedobject.Indexedpropertiesaretypicallycollectionssuchaslistsand

dictionaries,butcanbeanyclassthatexposesanindexer.

Belowyou'llfindsomeexamplesofworkingwiththeIObjectWrappertogetandsetproperties.Considerthefollowingtwoclasses:

[C#]

publicclassCompany

{

privatestringname;

privateEmployeemanagingDirector;

publicstringName

{

get{returnthis.name;}

set{this.name=value;}

}

publicEmployeeManagingDirector

{

get{returnthis.managingDirector;}

set{this.managingDirector=value;}

}

}

[C#]

publicclassEmployee

{

privatestringname;

privatefloatsalary;

publicstringName

{

Page 210: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

get{returnthis.name;}

set{this.name=value;}

}

publicfloatSalary

{

get{returnsalary;}

set{this.salary=value;}

}

}

The following code snippets show some examples of how to retrieve andmanipulate some of the properties of IObjectWrapper-wrappedCompanyandEmployeeinstances.

[C#]

Companyc=newCompany();

IObjectWrapperowComp=newObjectWrapper(c);

//settingthecompanyname...

owComp.SetPropertyValue("name","SalinaInc.");

//canalsobedonelikethis...

PropertyValuev=newPropertyValue("name","SalinaInc.");

owComp.SetPropertyValue(v);

//ok,let'screatethedirectorandbindittothecompany...

Employeedon=newEmployee();

IObjectWrapperowDon=newObjectWrapper(don);

owDon.SetPropertyValue("name","DonFabrizio");

owComp.SetPropertyValue("managingDirector",don);

//retrievingthesalaryoftheManagingDirectorthroughthecompany

floatsalary=(float)owComp.GetPropertyValue("managingDirector.salary"

NotethatsincethevariousSpring.NETlibrariesarecompliantwiththeCommonLanguageSpecification (CLS), the resolutionof arbitrary strings to properties,events,classesandsuchisperformedinacase-insensitivefashion.Thepreviousexamples were all written in the C# language, which is a case-sensitivelanguage,andyet theNamepropertyof theEmployeeclasswas setusingtheall-lowercase'name' string identifier.Thefollowingexample(using theclassesdefinedpreviously)shouldservetoillustratethis...

Page 211: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

[C#]

//ok,let'screatethedirectorandbindittothecompany...

Employeedon=newEmployee();

IObjectWrapperowDon=newObjectWrapper(don);

owDon.SetPropertyValue("naMe","DonFabrizio");

owDon.GetPropertyValue("nAmE");//gets"DonFabrizio"

IObjectWrapperowComp=newObjectWrapper(newCompany());

owComp.SetPropertyValue("ManaGINGdirecToR",don);

owComp.SetPropertyValue("mANaGiNgdirector.salARY",80000);

Console.WriteLine(don.Salary);//puts80000

Thecase-insensitivityofthevariousSpring.NETlibraries(dictatedbytheCLS)is not usually an issue... if you happen to have a class that has a number ofproperties,events,ormethodsthatdifferonlybytheircase,thenyoumightwantto consider refactoring your code, since this is generally regarded as poorprogrammingpractice.

6.2.2.OtherfeaturesworthmentioningInadditiontothefeaturesdescribedintheprecedingsectionsthereanumberoffeaturesthatmightbeinterestingtoyou,thoughnotworthanentiresection.

determiningreadabilityandwritability:usingtheIsReadable()andIsWritable()methods,youcandeterminewhetherornotapropertyisreadableorwritable.

retrieving PropertyInfo instances: usingGetPropertyInfo(string) andGetPropertyInfos()you can retrieve instances of theSystem.Reflection.PropertyInfo class, thatmight comeinhandysometimeswhenyouneedaccesstothepropertymetadataspecifictotheobjectbeingwrapped.

Page 212: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

6.3.TypeconversionIfyouassociateaTypeConverterwiththedefinitionofacustomTypeusingthestandard.NETmechanism(seetheexamplecodebelow),Spring.NETwillusetheassociatedTypeConvertertodotheconversion.

[C#]

[TypeConverter(typeof(FooTypeConverter))]

publicclassFoo

{

}

TheTypeConverter class from the System.ComponentModelnamespace of the .NETBCL is used extensively by the various classes in theSpring.Corelibrary,assaidclass“...providesaunifiedwayofconvertingtypes of values to other types, as well as for accessing standard values andsubproperties.”[4]

For example, a date can be represented in a human readable format (such as30thAugust1984),whilewe'restillabletoconvertthehumanreadableform to the original date format or (even better) to an instance of theSystem.DateTime class. This behavior can be achieved by using thestandard .NET idiom of decorating a class with theTypeConverterAttribute.Spring.NETalsooffersanothermeansofassociatingaTypeConverterswithaclass.Youmightwanttodothistoachieveaconversionthatisnotpossibleusingstandardidiom...forexample,theSpring.Core library contains a custom TypeConverter thatconvertscomma-delimitedstringstoStringarrayinstances.Registeringcustomconverters on an IObjectWrapper instance gives the wrapper theknowledgeofhowtoconvertpropertiestothedesiredType.AnexampleofwherepropertyconversionisusedinSpring.NETisthesettingofproperties on objects, accomplished using the aforementionedTypeConverters.WhenmentioningSystem.String as the valueofapropertyofsomeobject(declaredinanXMLfileforinstance),Spring.NETwill (if the type of the associated property is System.Type) use theRuntimeTypeConverterclasstotrytoresolvethepropertyvaluetoa

Page 213: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Typeobject.TheexamplebelowdemonstratesthisautomaticconversionoftheExample.Xml.SAXParser (a string) into the corresponding Typeinstanceforuseinthisfactory-styleclass.

<objectsxmlns="http://www.springframework.net">

<objectid="parserFactory"type="Example.XmlParserFactory,ExamplesLibrary"

destroy-method="Close">

<propertyname="ParserClass"value="Example.Xml.SAXParser,ExamplesLibrary"

</object>

</objects>

[C#]

publicclassXmlParserFactory

{

privateTypeparserClass;

publicTypeParserClass

{

get{returnthis.parserClass;}

set{this.parserClass=value;}

}

publicXmlParserGetParser()

{

returnActivator.CreateInstance(ParserClass);

}

}

6.3.1.TypeConversionforEnumerationsThe default type converter for enumerations is theSystem.ComponentModel.EnumConverterclass.Tospecifythevalue for an enumerated property, simply use the name of the property. Forexample the TestObject class has a property of the enumerated typeFileMode.OneofthevaluesforthisenumerationisnamedCreate.ThefollowingXMLfragmentshowshowtoconfigurethisproperty

<objectid="rod"type="Spring.Objects.TestObject,Spring.Core.Tests"

<propertyname="name"value="Rod"/>

Page 214: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<propertyname="FileMode"value="Create"/>

</object>

Page 215: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

6.4.Built-inTypeConvertersSpring.NEThasanumberofbuilt-inTypeConverterstomakelifeeasy.Each of those is listed below and they are all located in theSpring.Objects.TypeConverters namespace of theSpring.Corelibrary.

Table6.2.Built-inTypeConverters

Type Explanation

RuntimeTypeConverterParsesstringsrepresentingSystem.Typestoactual

System.Typesandtheotherwayaround.

FileInfoConverterCapableofresolvingstringstoaSystem.IO.FileInfoobject.

StringArrayConverter Capableofresolvingacomma-delimitedlistofstringstostring-arrayandviceversa.

UriConverterCapableofresolvingastringrepresentationofaURItoactualUri-object.

FileInfoConverterCapableofresolvingastringrepresentationofaFileInfotoanactualFileInfo-object.

StreamConverterCapableofresolvingSpringIResourceURI(string)toitscorrespondingInputStream-object.

ResourceConverterCapableofresolvingSpringIResourceURI(string)toanIResourceobject.

ResourceManagerConverter

Capableofresolvingatwopartstring(resourcename,assemblyname)toaSystem.Resources.ResourceManagerobject.

RgbColorConverterCapableofresolvingacommaseparatedlistofRed,Green,BlueintegervaluestoaSystem.Drawing.Colorstructure.

RegexConverter ConvertsstringrepresentationofregularexpressionintoinstanceofSystem.Text.RegularExpressions.Regex

Spring.NET uses the standard .NET mechanisms for the resolution of

Page 216: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

System.Types, including, but not limited to checking any configurationfiles associated with your application, checking the Global Assembly Cache(GAC),andassemblyprobing.

6.4.1.CustomtypeconvertersYoucanregisteracustomtypeconvertereitherProgramaticallyusingtheclassTypeConverterRegistry or through configuration of Spring's container anddescribedinthesectionRegisteringTypeConverters.

[4] More information about creating custom TypeConverter

implementations can be found online at Microsoft's MSDN website, bysearchingforImplementingaTypeConverter.

Page 217: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter7.Resources

Page 218: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

7.1.IntroductionThe IResource interface contained in the Spring.Core.IOnamespace provides a common interface to describe and access data fromdiverseresourcelocations.ThisabstractionletsyoutreattheInputStreamfrom a file and from a URL in a polymorphic and protocol-independentmanner... the .NET BCL does not provide such an abstraction. TheIResource interface inherits from IInputStream that provides asingle property Stream InputStream. The IResource interfaceadds descriptive information about the resource via a number of additionalproperties. Several implementations for common resource locations, i.e. file,assembly, uri, are provided and you may also register custom IResourceimplementations.

Page 219: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

7.2.TheIResourceinterfaceTheIResourceinterfaceisshownbelow

publicinterfaceIResource:IInputStreamSource

{

boolIsOpen{get;}

UriUri{get;}

FileInfoFile{get;}

stringDescription{get;}

boolExists{get;}

IResourceCreateRelative(stringrelativePath);

}

Table7.1.IResourcePropertiesProperty Explanation

InputStreamInheritedfromIInputStream.OpensandreturnsaSystem.IO.Stream.ItisexpectedthateachinvocationreturnsafreshStream.Itistheresponsibilityofthecallertoclosethestream.

Exists returnsabooleanindicatingwhetherthisresourceactuallyexistsinphysicalform.

IsOpen

returnsabooleanindicatingwhetherthisresourcerepresentsahandlewithanopenstream.Iftrue,theInputStreamcannotbereadmultipletimes,andmustbereadonceonlyandthenclosedtoavoidresourceleaks.Willbefalseforallusualresourceimplementations,withtheexceptionofInputStreamResource.

Description Returnsadescriptionoftheresource,suchasthefullyqualifiedfilenameortheactualURL.

Uri TheUrirepresentationoftheresource.

File ReturnsaSystem.IO.FileInfoforthisresourceifitcanberesolvedtoanabsolutefilepath.

Page 220: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

andthemethods

Table7.2.IResourceMethodsMethod Explanation

IResourceCreateRelative

(stringrelativePath)Createsaresourcerelativetothisresourceusingrelativepathlikenotation(./and../).

You can obtain an actual URL or File object representing the resource if theunderlyingimplementationiscompatibleandsupportsthatfunctionality.The Resource abstraction is used extensively in Spring itself, as an argumenttype inmanymethod signatureswhen a resource is needed.Othermethods insome Spring APIs (such as the constructors to variousIApplicationContext implementations), takea Stringwhich is usedtocreateaResourceappropriatetothatcontextimplementationWhiletheResourceinterfaceisusedalotwithSpringandbySpring,it'sactuallyveryusefultouseasageneralutilityclassbyitselfinyourowncode,foraccesstoresources,evenwhenyourcodedoesn'tknoworcareaboutanyotherpartsofSpring.WhilethiscouplesyourcodetoSpring, it reallyonlycouplesit to thissmallsetofutilityclassesandcanbeconsideredequivalenttoanyotherlibraryyouwoulduseforthispurpose

Page 221: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

7.3.Built-inIResourceimplementationsTheresourceimplementationsprovidedare

AssemblyResource accesses data stored as .NET resourcesinside an assembly. Uri syntax isassembly://<AssemblyName>/<NameSpace>/<ResourceName>

ConfigSectionResource accesses Spring.NETconfigurationdatastoredinacustomconfigurationsectioninthe.NETapplicationconfiguration file (i.e.App.config).Uri syntaxisconfig://<pathtosection>FileSystemResource accesses file system data.Uri syntaxisfile://<filename>InputStreamResource a wrapper around a rawSystem.IO.Stream.Urisyntaxisnotsupported.UriResource accesses data from the standard System.Uriprotocolssuchashttpandhttps.In.NET2.0youcanusethisalsofortheftpprotocol.StandardUrisyntaxissupported.

RefertotheMSDNdocumentationformoreinformationonsupportedUri schemetypes.

7.3.1.RegisteringcustomIResourceimplementationsThe configuration section handler,ResourceHandlersSectionHandler, is used to register anycustomIResource implementationsyouhavecreated. In theconfigurationsection you list the type of IResource implementation and the protocolprefix.YourcustomIResource implementationmustprovideaconstructorthat takesastringas it'ssoleargument that represents theURIstring.Refer totheSDKdocumentation forResourceHandlersSectionHandlerfor more information. An example of theResourceHandlersSectionHandler is shown below for afictionalIResourceimplementationthatinterfaceswithadatabase.

<configuration>

<configSections>

Page 222: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<sectionGroupname="spring">

<sectionname='context'type='Spring.Context.Support.ContextHandler,Spring.Core'

<sectionname="resourceHandlers"

type="Spring.Context.Support.ResourceHandlersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<resourceHandlers>

<handlerprotocol="db"type="MyCompany.MyApp.Resources.MyDbResource,MyAssembly"

</resourceHandlers>

<context>

<resourceuri="db://user:pass@dbName/MyDefinitionsTable"

</context>

</spring>

</configuration>

Page 223: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

7.4.TheIResourceLoaderTo load resources given their Uri syntax, an implementation of theIResourceLoader is used. The default implementation isConfigurableResourceLoader. Typically you will not need toaccess thisclassdirectlysince theIApplicationContext implementsthe IResourceLoader interface that contains the single methodIResourceGetResource(stringlocation).TheprovidedimplementationsofIApplicationContextdelegate thismethod toaninstanceofConfigurableResourceLoaderwhichsupports theUriprotocols/schemeslistedpreviously.Ifyoudonotspecifyaprotocolthenthefileprotocolisused.Thefollowingshowssomesampleusage.

IResourceresource=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"

StreamReaderreader=newStreamReader(resource.InputStream);

Console.WriteLine(reader.ReadToEnd());

Other protocols can be registered along with a new implementations of anIResourcethatmustcorrectlyparseaUristringinitsconstructor.Anexampleofthis can be seen in the Spring.Web namespace that usesServer.MapPathtoresolvethefilenameofaresource.

TheCreateRelativemethodallowsyou to easily loadresourcesbasedonarelativepathname.Inthecaseofrelativeassemblyresources,therelativepathnavigatesthenamespacewithinanassembly.Forexample:

IResourceres=newAssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt"

IResourceres2=res.CreateRelative("./IO/TestIOResource.txt"

This loads the resourceTestResource.txt and then navigates to theSpring.Core.IO namespace and loads the resourceTestIOResource.txt

Page 224: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

7.5.TheIResourceLoaderAwareinterfaceTheIResourceLoaderAware interface is a special marker interface,identifyingobjects that expect tobeprovidedwith aIResourceLoaderreference.

publicinterfaceIResourceLoaderAware

{

IResourceLoaderResourceLoader

{

set;

get;

}

}

When a class implements IResourceLoaderAware and is deployedinto an application context (as a Spring-managed object), it is recognized asIResourceLoaderAware by the application context. The applicationcontext will then invoke the ResourceLoader property, supplying itself as theargument (remember, all application contexts in Spring implement theIResourceLoaderinterface).

Of course, since an IApplicationContext is aIResourceLoader, the object could also implement theIApplicationContextAware interface and use the suppliedapplicationcontextdirectlytoloadresources,butingeneral,it'sbettertousethespecializedIResourceLoader interface if that's all that's needed. Thecode would just be coupled to the resource loading interface, which can beconsidered a utility interface, and not the whole SpringIApplicationContextinterface.

Page 225: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

7.6.ApplicationcontextsandIResourcepathsAn application context constructor (for a specific application context type)generally takes a string or array of strings as the location path(s) of theresource(s) such asXML files thatmake up the definition of the context. Forexample, you can create an XmlApplicationContext from two resources asfollows:

IApplicationContextcontext=newXmlApplicationContext(

"file://objects.xml","assembly://MyAssembly/MyProject/objects-dal-layer.xml"

Page 226: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter8.ThreadingandConcurrencySupport

Page 227: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

8.1.IntroductionThepurposeoftheSpring.Threadingnamespaceistoprovideaplaceto keepuseful concurrency abstractions that augment those in theBCL. SinceDoug Lea has provided a wealth of mature public domain concurrencyabstractions in his Java based 'EDU.oswego.cs.dl.util.concurrent' libraries wedecidedtoportafewofhisabstractionsto.NET.Sofar,we'veonlyportedthreeclasses,theminimumnecessarytoprovidebasicobjectpoolingfunctionalitytosupportanAOPbasedpoolingaspectandtoprovideaSemaphoreclassthatwasmistakenlynotincludedin.NET1.0/1.1.There is also an important abstraction, IThreadStorage, for performing threadlocalstorage.

Page 228: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

8.2.ThreadLocalStorageDependingonyourruntimeenvironmenttherearedifferentstrategiestouseforstoring objects in thread local storage. If you are inweb applications a singleRequest may be executed on different threads. As such, the location to storethread local objects is in HttpContext.Current. For otherenvironmentsSystem.Runtime.Remoting.Messaging.CallContext isused.Formorebackgroundinformationonthemotivationbehindthesechoices,sayas compared to theattribute [ThreadStatic] refer to "Piers7"'sblogand thisforumpost.The interface IThreadStorageservesas thebasis for the thread localstorageabstractionandvariousimplementationscanbeselectedfromdependingon your runtime requirements. Configuring the implementation ofIThreadStorage makes it easier to have more portability across runtimeenvironments.TheAPIisquitesimpleandshownbelow

publicinterfaceIThreadStorage

{

objectGetData(stringname)

voidSetData(stringname,objectvalue)

voidFreeNamedDataSlot(stringname)

}

The methodsGetData andSetData are responsible for retrieving andsetting theobject that is to bebound to thread local storage and associating itwith a name. Clearing the thread local storage is done via the methodFreeNamedDataSlot.

InSpring.Coreistheimplementation,CallContextStorage,thatdirectly uses CallContext and also the implementationLogicalThreadContext which by default usesCallContextStorage but can be configured via the static methodSetStorage(IThreadStorage). The methods on

Page 229: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

CallContextStorageandLogicalThreadContextarestatic.InSpring.WebistheimplementationHttpContextStoragewhichuses the HttpContext to store thread local data andHybridContextStorage thatusesHttpContext ifwithin awebenvironment, i.e. HttpContext.Current != null, andCallContextotherwise.

SpringinternallyusesLogicalThreadContextasthisdoesn'trequireacoupling to the System.Web namespace. In the case of Spring based webapplications, Spring's WebSupportModule sets the storage strategy ofLogicalThreadContexttobeHybridContextStorage.

Page 230: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

8.3.SynchronizationPrimitivesWhenyou takea lookat these synchronizationclasses,you'llwonderwhy it'seven necessary when System.Threading provides plenty ofsynchronization options. Although System.Threading provides greatsynchronization classes, it doesn't provide well-factored abstractions andinterfacesforus.Withouttheseabstractions,wewilltendtocodeatalow-level.Withenoughexperience,you'lleventuallycomeupwithsomeabstractionsthatwork well. Doug Lea has already done a lot of that research and has a classlibrarythatwecantakeadvantageof.

8.3.1.ISyncISync is the central interface for all classes that control access to resourcesfrommultiplethreads.It'sasimpleinterfacewhichhastwobasicusecases.Thefirstcaseistoblockindefinitelyuntilaconditionismet:

voidConcurrentRun(ISynclock){

lock.Acquire();//blockuntilconditionmet

try{

//...accesssharedresources

}

finally{

lock.Release();

}

}

The other case is to specify a maximum amount of time to block before theconditionismet:

voidImpatientConcurrentRun(ISynclock){

//blockforatmost10millisecondsforcondition

if(lock.Attempt(10)){

try{

//...accesssharedresources

}

finally{

lock.Release();

}

}else{

Page 231: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

//complainoftimeout

}

}

8.3.2.SyncHolderThe SyncHolder class implements the System.IDisposableinterface and so provides a way to use an ISync with the using C#keyword:theISyncwillbeautomaticallyAcquiredandthenReleasedonexitingfromtheblock.Thisshouldsimplifytheprogrammingmodelforcodeusing(!)anISync:

ISyncsync=...

...

using(newSyncHolder(sync))

{

//...codetobeexecuted

//holdingtheISynclock

}

Thereisalsothetimedversion,alittlemorecumbersomeasyoumustdealwithtimeouts:

ISyncsync=...

longmsecs=100;

...

//trytoacquiretheISyncformsecsmilliseconds

try

{

using(newSyncHolder(sync,msecs))

{

//...codetobeexecuted

//holdingtheISynclock

}

}

catch(TimeoutException)

{

//dealwithfailedlockacquisition

}

Page 232: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

8.3.3.LatchThe Latch class implements the ISync interface and provides animplementationofalatch.Alatchisabooleanconditionthatissetatmostonce,ever. Once a single release is issued, all acquires will pass. It is similar to aManualResetEvent initialized unsignalled (Reset) and can only beSet().Atypicaluseistoactasastartsignalforagroupofworkerthreads.

classBoss{

Latch_startPermit;

voidWorker(){

//veryslowworkerinitialization...

//...attachtomessagingsystem

//...connecttodatabase

_startPermit.Acquire();

//...useresourcesinitializedinMush

//...dorealwork

}

voidMush(){

_startPermit=newLatch();

for(inti=0;i<10;++i){

newThread(newThreadStart(Worker)).Start();

}

//veryslowmaininitialization...

//...parseconfiguration

//...initializeotherresourcesusedbyworkers

_startPermit.Release();

}

}

8.3.4.SemaphoreTheSemaphore class implements theISync interface and provides animplementationof a semaphore.Conceptually, a semaphoremaintains a set of

Page 233: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

permits.EachAcquire()blocksifnecessaryuntilapermitisavailable,andthen takes it. EachRelease() adds a permit. However, no actual permitobjectsareused;theSemaphorejustkeepsacountofthenumberavailableandactsaccordingly.Atypicaluseistocontrolaccesstoapoolofsharedobjects.

classLimitedConcurrentUploader{

//ensurewedon'texceedmaxUploadsimultaneousuploads

Semaphore_available;

publicLimitedConcurrentUploader(maxUploads){

_available=newSemaphore(maxUploads);

}

//nomatterhowmanythreadscallthismethodnomore

//thanmaxUploadsconcurrentuploadswilloccur.

publicUpload(IDataTransferupload){

_available.Acquire();

try{

upload.TransferData();

}

finally{

_available.Release();

}

}

}

Page 234: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter9.ObjectPooling

Page 235: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

9.1.IntroductionTheSpring.Poolnamespace contains agenericAPI for implementingpools ofobjects.Objectpooling is awellknown technique tominimize the creationofobjects that can take a significant amount of time. Common examples are tocreateapoolofdatabaseconnectionssuchthateachrequesttothedatabasecanreuseanexistingconnectioninsteadofcreatingoneperclientrequest.Threadsare also another common candidate for pooling in order to increaseresponsivenessofanapplicationtomultipleconcurrentclientrequests..NET contains support for object pooling in these common scenarios. SupportfordatabaseconnectionpoolsisdirectlysupportedbyADO.NETdataprovidersas a configuration option. Similarly, thread pooling is supported via theSystem.ThreadPoolclass.Supportforpoolingofotherobjectscanbedoneusingthe CLR managed API to COM+ found in the System.EnterpriseServicesnamespace.Despite this built-in support there are scenarios where you would like to usealternative pool implementations. This may be because the defaultimplementations, such as System.ThreadPool, do notmeet your requirements.(For a discussion on advancedThreadPool usage seeSmart Thread Pool byAmiBar.) Alternatively, you may want to pool classes that do not inherit fromSystem.EnterpriseServices.ServicedComponent.Instead of making changes to the object model to meet this inheritancerequirement, Spring .NET provides similar support for pooling, but for anyobject, by using AOP proxies and a generic pool API for managing objectinstances.Note,thatifyouareconcernedonlywithapplyingpoolingtoanexistingobject,the pooling APIs discussed here are not very important. Instead the use andconfiguration ofSpring.Aop.Target.SimplePoolTargetSource is morerelevant. Poolingof objects can either be doneProgramatically or through theXMLconfigurationoftheSpring.NETcontainer.Attributesupportforpooling,similartotheServicedComponentapproach,willbeavailableinafuturereleaseofSpring.NET.Chapter33, IoCQuickstarts containsanexample that shows theuseof thepoolingAPIindependentofAOPfunctionality.

Page 236: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

9.2.InterfacesandImplementationsTheSpring.Pool namespace provides two simple interfaces to managepools of objects. The first interface,IObjectPool describes how to takeand put back an object from the pool. The second interfaceIPoolableObjectFactory is meant to be used in conjunctionwithimplementationsoftheIObjectPooltoprovideguidanceincallingvariouslifecycleeventsontheobjectsmanagedbythepool.Theseinterfacesarebasedon the Jakarta Commons Pool API.Spring.Pool.Support.SimplePool is a default implementationof IObjectPool andSpring.Aop.Target.SimplePoolTargetSource is theimplementationofIPoolableObjectFactoryforusewithAOP.Thecurrent goal of the Spring.Pool namespace is not to provide a one-for-onereplacementoftheJakartaCommonsPoolAPI,butrathertosupportbasicobjectpooling needs for commonAOP scenarios.Consequently, other interfaces andbaseclassesavailableintheJakartapackagearenotavailable.

Page 237: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter10.Spring.NETmiscellanea

Page 238: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

10.1.IntroductionThischaptercontainsmiscellaneainformationonfeatures,goodies,caveats thatdoesnotbelongtoanypariculararea.

Page 239: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

10.2.PathMatcherNote,Spring.Util.PathMatcher iscurrentlyonlyavailable inCVS,not theRC3release.IfyouwanttousethesefeaturepleasegetthecodefromCVS(instructions)or from the download section of the Spring.NETwebsite that contains an .zipwiththefullCVStree.Spring.Util.PathMatcher provides Ant/NAnt-like path namematchingfeatures.Todothematch,youusethemethod:

staticboolMatch(stringpattern,stringpath)

Ifyouwanttodecideifcaseisimportantornotusethemethod:

staticboolMatch(stringpattern,stringpath,boolignoreCase)

10.2.1.GeneralrulesTobuildyourpattern,youusethe*,?and**buildingblocks:

*:matchesanynumberofnonslashcharacters;

?:matchesexactly1(one)nonslash/dotcharacter;

**:matchesanysubdirectory,withouttakingcareofthedepth;

10.2.2.MatchingfilenamesAfilenamecanbematchedusingthefollowingnotation:

foo?bar.*

matches:

fooAbar.txt

foo1bar.txt

foo_bar.txt

foo-bar.txt

doesnotmatch:

Page 240: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

foo.bar.txt

foo/bar.txt

foo\bar.txt

Theclassicalallfilespattern:

*.*

matches:

foo.db

.db

foo

foo.bar.db

foo.db.db

db.db.db

doesnotmatch:

c:/

c:/foo.db

c:/foo

c:/.db

c:/foo.foo.db

//server/foo

10.2.3.MatchingsubdirectoriesA directory name can be matched at any depth level using the followingnotation:

**/db/**

Thatpatternmatchesthefollowingpaths:

/db

//server/db

c:/db

c:/spring/app/db/foo.db

//ProgramFiles/App/spaceddir/db/foo.db

Page 241: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

/home/spring/spaceddir/db/v1/foo.db

butdoesnotmatchthese:

c:/spring/app/db-v1/foo.db

/home/spring/spaceddir/db-v1/foo.db

Youcancomposesubdirectoriestomatchlikethis:

**/bin/**/tmp/**

Thatpatternmatchesthefollowingpaths:

c:/spring/foo/bin/bar/tmp/a

c:/spring/foo/bin/tmp/a/b.c

butdoesnotmatchthese:

c:/spring/foo/bin/bar/temp/a

c:/tmp/foo/bin/bar/a/b.c

Youcanusemoreadvancedpatterns:

**/.spring-assemblies*/**

matches:

c:/.spring-assemblies

c:/.spring-assembliesabcd73xs

c:/app/.spring-assembliesabcd73xs

c:/app/.spring-assembliesabcd73xs/foo.dll

//server/app/.spring-assembliesabcd73xs

doesnotmatch:

c:/app/.spring-assemblie

10.2.4.Casedoesmatter,slashesdon't

Page 242: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

.NET is expected to be a cross-platform development ... platform. So,PathMatcherwillmatchtakingcareofthecaseofthepatternandthecaseofthepath.Forexample:

**/db/**/*.DB

matches:

c:/spring/service/deploy/app/db/foo.DB

butdoesnotmatch:

c:/spring/service/deploy/app/DB/foo.DB

c:spring/service/deploy/app/spaceddir/DB/foo.DB

//server/share/service/deploy/app/DB/backup/foo.db

Ifyoudonotmatteraboutcase,youshouldexplicitlytellthePathmatcher.Back and forward slashes, in the very same cross-platform spirit, are notimportant:

spring/foo.bar

matchesallthefollowingpaths:

c:\spring\foo.bar

c:/spring\foo.bar

c:/spring/foo.bar

/spring/foo.bar

\spring\foo.bar

Page 243: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter11.ExpressionEvaluation

Page 244: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.1.IntroductionTheSpring.Expressionsnamespaceprovidesapowerfulexpressionlanguageforquerying andmanipulating an object graph at runtime. The language supportssettingandgettingofpropertyvalues,propertyassignment,methodinvocation,accessingthecontextofarrays,collectionsandindexers, logicalandarithmeticoperators,namedvariables,andretrievalofobjectsbynamefromSpring'sIoCcontainer. It also supports listprojectionand selection, aswell ascommon listaggregators.The functionality provided in this namespace serves as the foundation for avarietyofotherfeaturesinSpring.NETsuchasenhancedpropertyevaluationintheXMLbasedconfigurationoftheIoCcontainer,aDataValidationframework,andaDataBindingframeworkforASP.NET.Youwilllikelyfindothercoolusesforthislibraryinyourownworkwhererun-timeevaluationofcriteriabasedonan object's state is required. For those with a Java background, theSpring.Expressionsnamespaceprovides functionality similar to the JavabasedObjectGraphNavigationLanguage,OGNL.This chapter covers the features of the expression language using an InventorandInventor'sSocietyclassasthetargetobjectsforexpressionevaluation.Theclassdeclarationsandthedatausedtopopulatethemarelistedattheendofthechapter in section Section 11.4, “Classes used in the examples”. These classes areblatantly takenfromtheNUnit tests for theExpressionsnamespacewhichyoucanrefertoforadditionalexampleusage.

Page 245: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.2.EvaluatingExpressionsThesimplest,butnotthemostefficientwaytoperformexpressionevaluationisby using one of the static convenience methods of theExpressionEvaluatorclass:

publicstaticobjectGetValue(objectroot,stringexpression);

publicstaticobjectGetValue(objectroot,stringexpression,IDictionaryvariables)

publicstaticvoidSetValue(objectroot,stringexpression,

publicstaticvoidSetValue(objectroot,stringexpression,IDictionaryvariables,

Thefirstargumentis the 'root'object that theexpressionstring(2ndargument)willbeevaluatedagainst.Thethirdargumentisusedtosupportvariablesintheexpressionandwillbediscussedlater.Simpleusagetogetthevalueofanobjectproperty is shownbelowusing theInventor class.You can find the classlistinginsectionSection11.4,“Classesusedintheexamples”.

Inventortesla=newInventor("NikolaTesla",newDateTime(1856,7,9),

tesla.PlaceOfBirth.City="Smiljan";

stringevaluatedName=(string)ExpressionEvaluator.GetValue(tesla,

stringevaluatedCity=(string)ExpressionEvaluator.GetValue(tesla,

The value of 'evaluatedName' is 'Nikola Tesla' and that of 'evaluatedCity' is'Smiljan'. A period is used to navigate the nested properties of the object.Similarly to set the property of an object, saywewant to rewrite historyandchangeTesla'scityofbirth,wewouldsimplyaddthefollowingline

ExpressionEvaluator.SetValue(tesla,"PlaceOfBirth.City","NoviSad"

A much better way to evaluate expressions is to parse them once and thenevaluate as many times as you want usingExpressionclass. UnlikeExpressionEvaluator, which parses expression every time you

Page 246: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

invoke one of its methods, Expression class will cache the parsedexpression for increased performance. The methods of this class are listedbelow:

publicstaticIExpressionParse(stringexpression)

publicoverrideobjectGet(objectcontext,IDictionaryvariables)

publicoverridevoidSet(objectcontext,IDictionaryvariables,

TheretrievaloftheNamepropertyinthepreviousexampleusingtheExpressionclassisshownbelow

IExpressionexp=Expression.Parse("Name");

stringevaluatedName=(string)exp.GetValue(tesla,null);

Thedifferenceinperformancebetweenthetwoapproaches,whenevaluatingthesameexpressionmanytimes,isseveralordersofmagnitude,soyoushouldonlyuseconveniencemethodsoftheExpressionEvaluatorclasswhenyouaredoingone-offexpressionevaluations.Inallothercasesyoushouldparsetheexpressionfirstandthenevaluateitasmanytimesasyouneed.There are a few exception classes to be aware of when using theExpressionEvaluator. These areInvalidPropertyException, when you refer to a property thatdoesn't exist, NullValueInNestedPathException, when a nullvalue is encountered when traversing through the nested property list, andArgumentExceptionandNotSupportedExceptionwhenyoupassinvaluesthatareinerrorinsomeothermanner.TheexpressionlanguageisbasedonagrammarandusesANTLRtoconstructthelexerandparser.Errorsrelatingtobadsyntaxofthelanguagewillbecaughtatthis level of the language implementation. For those interested in the diggingdeeperintotheimplementation, thegrammarfile isnamedExpression.gandislocatedinthesrcdirectoryofthenamespace.Asasidenote,thereleaseversionoftheANTLRDLLincludedwithSpring.NETwassignedwiththeSpring.NETkey, which means that you should always use the included version ofantlr.runtime.dll within your application. Upcoming releases of

Page 247: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ANTLR will provide strongly signed assemblies, which will remove thisrequirement.

Page 248: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.3.LanguageReference

11.3.1.LiteralexpressionsThetypesofliteralexpressionssupportedarestrings,dates,numericvalues(int,real,andhex),booleanandnull.Stringaredelimitedbysinglequotes.Toputasinglequote itself inastringuse thebackslashcharacter.Thefollowing listingshowssimpleusageofliterals.Typicallytheywouldnotbeusedinisolationlikethis,butaspartofamorecomplexexpression,forexampleusingaliteralononesideofalogicalcomparisonoperator.

stringhelloWorld=(string)ExpressionEvaluator.GetValue(null

stringtonyPizza=(string)ExpressionEvaluator.GetValue(null

doubleavogadrosNumber=(double)ExpressionEvaluator.GetValue(

intmaxValue=(int)ExpressionEvaluator.GetValue(null,"0x7FFFFFFF"

DateTimebirthday=(DateTime)ExpressionEvaluator.GetValue(

DateTimeexactBirthday=

(DateTime)ExpressionEvaluator.GetValue(null,"date('19740824T131030','yyyyMMddTHHmmss')"

booltrueValue=(bool)ExpressionEvaluator.GetValue(null,"true"

objectnullValue=ExpressionEvaluator.GetValue(null,"null"

Note that the extra backslash character inTony'sPizza is to satisfyC# escapesyntax.Numberssupporttheuseofthenegativesign,exponentialnotation,anddecimal points.By default real numbers are parsed usingDouble.Parseunless the format character "M" or "F" is supplied, in which caseDecimal.ParseandSingle.Parsewouldbeused respectfully.Asshown above, if two arguments are given to the date literal thenDateTime.ParseExact will be used. Note that all parse methods ofclasses that are used internally reference theCultureInfo.InvariantCulture.

11.3.2.Properties,Arrays,Lists,Dictionaries,Indexers

Page 249: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

As shown in the previous example in Section 11.2, “Evaluating Expressions”,navigating through properties is easy, just use a period to indicate a nestedproperty value. The instances of Inventor class, pupin and tesla, werepopulatedwithdata listed insectionSection11.4, “Classesused in theexamples”.Tonavigate "down" and get Tesla's year of birth and Pupin's city of birth thefollowingexpressionsareused

intyear=(int)ExpressionEvaluator.GetValue(tesla,"DOB.Year"

stringcity=(string)ExpressionEvaluator.GetValue(pupin,"PlaCeOfBirTh.CiTy"

Forthesharp-eyed,thatisn'tatypointhepropertynameforplaceofbirth.Theexpression uses mixed cases to demonstrate that the evaluation is caseinsensitive.Thecontentsofarraysandlistsareobtainedusingsquarebracketnotation.

//InventionsArray

stringinvention=(string)ExpressionEvaluator.GetValue(tesla,

//MembersList

stringname=(string)ExpressionEvaluator.GetValue(ieee,"Members[0].Name"

//ListandArraynavigation

stringinvention=(string)ExpressionEvaluator.GetValue(ieee,

The contents of dictionaries are obtained by specifying the literal key valuewithin the brackets. In this case, because keys for theOfficers dictionary arestrings,wecanspecifystringliteral.

//Officer'sDictionary

Inventorpupin=(Inventor)ExpressionEvaluator.GetValue(ieee,

stringcity=(string)ExpressionEvaluator.GetValue(ieee,"Officers['president'].PlaceOfBirth.City"

ExpressionEvaluator.SetValue(ieee,"Officers['advisors'][0].PlaceOfBirth.Country"

Youmayalsospecifynonliteralvaluesinplaceofthequotedliteralvaluesbyusing another expression inside the square brackets such as variable names orstatic properties/methods on other types.These features are discussed in other

Page 250: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

sections.Indexersaresimilarlyreferencedusingsquarebrackets.Thefollowingisasmallexample that shows the use of indexers. Multidimensional indexers are alsosupported.

publicclassBar

{

privateint[]numbers=newint[]{1,2,3};

publicintthis[intindex]

{

get{returnnumbers[index];}

set{numbers[index]=value;}

}

}

Barb=newBar();

intval=(int)ExpressionEvaluator.GetValue(bar,"[1]")//evaluatedto2

ExpressionEvaluator.SetValue(bar,"[1]",3);//setvalueto3

11.3.2.1.DefiningArrays,ListsandDictionariesInlineInadditiontoaccessingarrays,listsanddictionariesbynavigatingthegraphforthecontextobject,Spring.NETExpressionLanguageallowsyoutodefinetheminline, within the expression. Inline lists are defined by simply enclosing acommaseparatedlistofitemswithcurlybrackets:

{1,2,3,4,5}

{'abc','xyz'}

Ifyouwanttoensurethatastronglytypedarrayisinitializedinsteadofaweaklytypedlist,youcanusearrayinitializerinstead:

newint[]{1,2,3,4,5}

newstring[]{'abc','xyz'}

Dictionarydefinitionsyntaxisabitdifferent:youneedtousea#prefixtotell

Page 251: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

expressionparsertoexpectkey/valuepairswithinthebracketsandtospecifyacommaseparatedlistofkey/valuepairswithinthebrackets:

#{'key1':'Value1','today':DateTime.Today}

#{1:'January',2:'February',3:'March',...}

Arrays, lists and dictionaries created this way can be used anywhere wherearrays,listsanddictionariesobtainedfromtheobjectgraphcanbeused,whichwewillseelaterintheexamples.Keepinmindthateventhoughexamplesaboveuseliteralsasarray/listelementsanddictionarykeysandvalues, that'sonlytosimplifytheexamples--youcanuseanyvalidexpressionwhereverliteralsareused.

11.3.3.MethodsMethods are invoked using typical C# programming syntax. You may alsoinvokemethodsonliterals.

//stringliteral

char[]chars=(char[])ExpressionEvaluator.GetValue(null,"'test'.ToCharArray(1,2)"

//dateliteral

intyear=(int)ExpressionEvaluator.GetValue(null,"date('1974/08/24').AddYears(31).Year"

//objectusage,calculateageofteslanavigatingfromtheIEEEsociety.

ExpressionEvaluator.GetValue(ieee,"Members[0].GetAge(date('2005-01-01')"

11.3.4.Operators

11.3.4.1.RelationaloperatorsThe relationaloperators;equal,notequal, less than, less thanor equal, greaterthan,andgreater thanorequalare supportedusing standardoperator notation.These operators take into account if the object implements theIComparableinterface.Enumerationsarealsosupportedbutyouwillneedto register the enumeration type, as described in Section Section 11.3.8, “TypeRegistration”, in order to use an enumeration value in an expression if it is notcontainedinthemscorlib.

Page 252: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ExpressionEvaluator.GetValue(null,"2==2")//true

ExpressionEvaluator.GetValue(null,"date('1974-08-24')!=DateTime.Today"

ExpressionEvaluator.GetValue(null,"2<-5.0")//false

ExpressionEvaluator.GetValue(null,"DateTime.Today<=date('1974-08-24')"

ExpressionEvaluator.GetValue(null,"'Test'>='test'")//true

Enumerationscanbeevaluatedasshownbelow

FooColorfColor=newFooColor();

ExpressionEvaluator.SetValue(fColor,"Color",KnownColor.Blue);

booltrueValue=(bool)ExpressionEvaluator.GetValue(fColor,

WhereFooColoristhefollowingclass.

publicclassFooColor

{

privateKnownColorknownColor;

publicKnownColorColor

{

get{returnknownColor;}

set{knownColor=value;}

}

}

In addition to standard relational operators, Spring.NETExpression Languagesupportssomeadditional,veryusefuloperatorsthatwere"borrowed"fromSQL,suchas in, likeandbetween,aswellas isandmatches operators,whichallowyou to test if object is of a specific type or if the value matches a regularexpression.

ExpressionEvaluator.GetValue(null,"3in{1,2,3,4,5}")

ExpressionEvaluator.GetValue(null,"'Abc'like'[A-Z]b*'")

Page 253: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ExpressionEvaluator.GetValue(null,"'Abc'like'?'")//false

ExpressionEvaluator.GetValue(null,"1between{1,5}")//true

ExpressionEvaluator.GetValue(null,"'efg'between{'abc','xyz'}"

ExpressionEvaluator.GetValue(null,"'xyz'isint")//false

ExpressionEvaluator.GetValue(null,"{1,2,3,4,5}isIList"

ExpressionEvaluator.GetValue(null,"'5.0067'matches'^-?\\d+(\\.\\d{2})?$'"

ExpressionEvaluator.GetValue(null,@"'5.00'matches'^-?\d+(\.\d{2})?$'"

Note that the Visual Basic and not SQL syntax is used for the like operatorpatternstring.

11.3.4.2.LogicaloperatorsThe logical operators that are supported are and, or, and not. Their use isdemonstratedbelow

//AND

boolfalseValue=(bool)ExpressionEvaluator.GetValue(null,

stringexpression=@"IsMember('NikolaTesla')andIsMember('MihajloPupin')"

booltrueValue=(bool)ExpressionEvaluator.GetValue(ieee,expression);

//OR

booltrueValue=(bool)ExpressionEvaluator.GetValue(null,"trueorfalse"

stringexpression=@"IsMember('NikolaTesla')orIsMember('AlbertEinstien')"

booltrueValue=(bool)ExpressionEvaluator.GetValue(ieee,expression);

//NOT

boolfalseValue=(bool)ExpressionEvaluator.GetValue(null,

//ANDandNOT

stringexpression=@"IsMember('NikolaTesla')and!IsMember('MihajloPupin')"

boolfalseValue=(bool)ExpressionEvaluator.GetValue(ieee,expression);

Page 254: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.3.4.3.MathematicaloperatorsTheadditionoperatorcanbeusedonnumbers,stringsanddates.Subtractioncanbeusedonnumbersanddates.Multiplicationanddivisioncanbeusedonlyonnumbers. Other mathematical operators supported are modulus (%) andexponential power (^). Standard operator precedence is enforced. Theseoperatorsaredemonstratedbelow

//Addition

inttwo=(int)ExpressionEvaluator.GetValue(null,"1+1");

StringtestString=(String)ExpressionEvaluator.GetValue(null

DateTimedt=(DateTime)ExpressionEvaluator.GetValue(null,"date('1974-08-24')+5"

//Subtraction

intfour=(int)ExpressionEvaluator.GetValue(null,"1--3"

Decimaldec=(Decimal)ExpressionEvaluator.GetValue(null,"1000.00m-1e4"

TimeSpants=(TimeSpan)ExpressionEvaluator.GetValue(null,

//Multiplication

intsix=(int)ExpressionEvaluator.GetValue(null,"-2*-3"

inttwentyFour=(int)ExpressionEvaluator.GetValue(null,"2.0*3e0*4"

//Division

intminusTwo=(int)ExpressionEvaluator.GetValue(null,"6/-3"

intone=(int)ExpressionEvaluator.GetValue(null,"8.0/4e0/2"

//Modulus

intthree=(int)ExpressionEvaluator.GetValue(null,"7%4"

intone=(int)ExpressionEvaluator.GetValue(null,"8.0%5e0%2"

//Exponent

Page 255: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

intsixteen=(int)ExpressionEvaluator.GetValue(null,"-2^4"

//Operatorprecedence

intminusFortyFive=(int)ExpressionEvaluator.GetValue(null

11.3.5.AssignmentSetting of a property is done by using the assignment operator. This wouldtypically be done within a call to GetValue since in the simple caseSetValueoffersthesamefunctionality.Assignmentinthismannerisusefulwhencombiningmultipleoperators inanexpression list,discussed in thenextsection.Someexamplesofassignmentareshownbelow

Inventorinventor=newInventor();

Stringaleks=(String)ExpressionEvaluator.GetValue(inventor,

DateTimedt=(DateTime)ExpressionEvaluator.GetValue(inventor,

//Setthevicepresidentofthesociety

Inventortesla=(Inventor)ExpressionEvaluator.GetValue(ieee,

11.3.6.ExpressionlistsMultiple expressions can be evaluated against the same context object byseparating them with a semicolon and enclosing the entire expression withinparentheses. The value returned is the value of the last expression in the list.Examplesofthisareshownbelow

//PerformpropertyassignmentsandthenreturnNameproperty.

Stringpupin=(String)ExpressionEvaluator.GetValue(ieee.Members,

"([1].PlaceOfBirth.City='Beograd';[1].PlaceOfBirth.Country='Serbia';[1].Name)"

//pupin="MihajloPupin"

11.3.7.TypesInmanycases,youcanreferencetypesbysimplyspecifyingtypename:

Page 256: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ExpressionEvaluator.GetValue(null,"1isint")

ExpressionEvaluator.GetValue(null,"DateTime.Today")

ExpressionEvaluator.GetValue(null,"newstring[]{'abc','efg'}"

This is possible for all standard types frommscorlib, as well as for anyother type that is registered with theTypeRegistry as described in thenextsection.Forallothertypes,youneedtousespecialT(typeName)expression:

TypedateType=(Type)ExpressionEvaluator.GetValue(null,"T(System.DateTime)"

TypeevalType=(Type)ExpressionEvaluator.GetValue(null,"T(Spring.Expressions.ExpressionEvaluator,Spring.Core)"

booltrueValue=(bool)ExpressionEvaluator.GetValue(tesla,

Note

TheimplementationdelegatestoSpring'sObjectUtils.ResolveTypemethodfortheactualtyperesolution,whichmeansthatthetypesusedwithinexpressionsareresolvedintheexactlythesamewayasthetypesspecifiedinSpringconfigurationfiles.

11.3.8.TypeRegistrationTorefer toa typewithinanexpression that isnot in themscorlibyouneed toregister it with the TypeRegistry. This will allow you to refer to ashorthandnameofthetypewithinyourexpressions.Thisiscommonlyusedinexpressionthatusethenewoperatororrefertoastaticpropertiesofanobject.Exampleusageisshownbelow.

TypeRegistry.RegisterType("Society",typeof(Society));

Inventorpupin=(Inventor)ExpressionEvaluator.GetValue(ieee,

Alternatively, you can register types using typeAliases configurationsection.

Page 257: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.3.9.ConstructorsConstructors can be invoked using the new operator. For classes outsidemscorlibyouwillneedtoregisteryourtypessotheycanberesolved.Examplesofusingconstructorsareshownbelow:

//simplector

DateTimedt=(DateTime)ExpressionEvaluator.GetValue(null,

//RegisterInventortypethencreatenewinventorinstancewithinAddmethodinsideanexpressionlist.

//ThenreturnthenewcountoftheMemberscollection.

TypeRegistry.RegisterType(typeof(Inventor));

intthree=(int)ExpressionEvaluator.GetValue(ieee.Members,

As a convenience, Spring.NET also allows you to define named constructorarguments,whichareusedtosetobject'spropertiesafterinstantiation,similartothe way standard .NET attributes work. For example, you could create aninstance of theInventor class and set itsInventions property in asinglestatement:

Inventoraleks=(Inventor)ExpressionEvaluator.GetValue(null

Theonly ruleyouhave to follow is thatnamedargumentsshouldbespecifiedafterstandardconstructorarguments,justlikeinthe.NETattributes.Whileweareonthesubject,Spring.NETExpressionLanguagealsoprovidesaconvenientsyntaxfor.NETattributeinstancecreation.Insteadofusingstandardconstructorsyntax,youcanuseasomewhatshorterandmorefamiliarsyntaxtocreateaninstanceofa.NETattributeclass:

WebMethodAttributewebMethod=(WebMethodAttribute)ExpressionEvaluator.GetValue(

Asyoucansee,withtheexceptionofthe@prefix,syntaxisexactlythesameasinC#.Slightly different syntax is not the only thing that differentiates an attributeexpressionfromastandardconstructorinvocationexpression.Inadditiontothat,attribute expression uses slightly different type resolutionmechanism andwill

Page 258: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

attempttoloadboththespecifiedtypenameandthespecifiedtypenamewithanAttributesuffix,justliketheC#compiler.

11.3.10.VariablesVariablescanreferencedintheexpressionusingthesyntax#variableName.ThevariablesarepassedinandoutoftheexpressionusingthedictionaryparameterinExpressionEvaluator'sGetValueorSetValuemethods.

publicstaticobjectGetValue(objectroot,stringexpression,IDictionaryvariables)

publicstaticvoidSetValue(objectroot,stringexpression,IDictionaryvariables,

Thevariablename is thekeyvalueof thedictionary.Exampleusage is shownbelow;

IDictionaryvars=newHashtable();

vars["newName"]="MikeTesla";

ExpressionEvaluator.GetValue(tesla,"Name=#newName",vars));

Youcanalsousethedictionaryasaplacetostorevaluesoftheobjectastheyareevaluatedinside theexpression.Forexample tochangeTesla's firstnamebackagainandkeeptheoldvalue;

ExpressionEvaluator.GetValue(tesla,"{#oldName=Name;Name='NikolaTesla'}"

StringoldName=(String)vars["oldName"];//MikeTesla

Variablenamescanalsobeusedinsideindexersormapsinsteadofliteralvalues.Forexample;

vars["prez"]="president";

Inventorpupin=(Inventor)ExpressionEvaluator.GetValue(ieee,

11.3.10.1.The'#this'and'#root'variablesThere are two special variables that are always defined and can bereferenceswithintheexpression:#thisand#root.

The#thisvariablecanbeusedtoexplicitlyrefertothecontextforthenode

Page 259: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

thatiscurrentlybeingevaluated:

//setsthenameofthepresidentandreturnsitsinstance

ExpressionEvaluator.GetValue(ieee,"Officers['president'].(#this.Name='NikolaTesla';#this)"

Similarly, the#root variable allows you to refer to the root context for theexpression:

//removespresidentfromtheOfficersdictionaryandreturnsremovedinstance

ExpressionEvaluator.GetValue(ieee,"Officers['president'].(#root.Officers.Remove('president');#this)"

11.3.11.TernaryOperator(If-Then-Else)You can use the ternary operator for performing if-then-else conditional logicinsidetheexpression.Aminimalexampleis;

StringaTrueString=(String)ExpressionEvaluator.GetValue(

In this case, theboolean false results in returning the stringvalue 'trueExp'.Alessartificialexampleisshownbelow

ExpressionEvaluator.SetValue(ieee,"Name","IEEE");

IDictionaryvars=newHashtable();

vars["queryName"]="NikolaTesla";

stringexpression=@"IsMember(#queryName)

?#queryName+'isamemberofthe'+Name+'Society'

:#queryName+'isnotamemberofthe'+Name+'Society'"

StringqueryResultString=(String)ExpressionEvaluator.GetValue(ieee,expression,vars));

//queryResultString="NikolaTeslaisamemberoftheIEEESociety"

11.3.12.ListProjectionandSelectionListprojectionandselectionareverypowerfulexpressionlanguagefeaturesthatallowyoutotransformthesourcelistintoanotherlistbyeitherprojectingacrossits "columns", or selecting from its "rows". In otherwords, projection can bethought of as a column selector in a SQLSELECT statement,while selection

Page 260: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

wouldbecomparabletotheWHEREclause.Forexample,let'ssaythatweneedalistofthecitieswhereourinventorswereborn. This could be easily obtained by projecting on thePlaceOfBirth.Cityproperty:

IListplacesOfBirth=(IList)ExpressionEvaluator.GetValue(ieee,

Orwecangetthelistofofficers'names:

IListofficersNames=(IList)ExpressionEvaluator.GetValue(ieee,

As you can see from the examples, projection uses!{projectionExpression}syntax and will return a new list of the same length as the original list buttypicallywiththeelementsofadifferenttype.Ontheotherhand,selection,whichuses?{projectionExpression}syntax,willfilterthelistandreturnanewlistcontainingasubsetoftheoriginalelementlist.Forexample,selectionwouldallowustoeasilygetalistofSerbianinventors:

IListserbianInventors=(IList)ExpressionEvaluator.GetValue(ieee,

Ortogetalistofinventorsthatinventedsonar:

IListsonarInventors=(IList)ExpressionEvaluator.GetValue(ieee,

Or we can combine selection and projection to get a list of sonar inventors'names:

IListsonarInventorsNames=(IList)ExpressionEvaluator.GetValue(ieee,

As a convenience, Spring.NET Expression Language also supports a specialsyntaxforselectingthefirstorlastmatch.Unlikeregularselection,whichwillreturn an empty list if no matches are found, first or last match selectionexpressionwilleitherreturnaninstanceofthematchedelement,ornullifnomatchingelementswerefound.Inordertoreturnafirstmatchyoushouldprefixyourselectionexpressionwith^{ insteadof?{,and to return lastmatchyoushoulduse${prefix:

Page 261: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ExpressionEvaluator.GetValue(ieee,"Members.^{Nationality=='Serbian'}.Name"

ExpressionEvaluator.GetValue(ieee,"Members.${Nationality=='Serbian'}.Name"

Notice that we access the Name property directly on the selection result,because an actual matched instance is returned by the first and last matchexpressioninsteadofafilteredlist.

11.3.13.CollectionProcessorsandAggregatorsIn addition to list projection and selection, Spring.NET Expression Languagealso supports several collectionprocessors, such asdistinct,nonNullandsort,aswellasanumberofcommonlyusedaggregators,suchasmax,min,count,sumandaverage.The difference between processors and aggregators is that processors return anew or transformed collection, while aggregators return a single value. Otherthanthat,theyareverysimilar--bothprocessorsandaggregatorsareinvokedona collection node using standard method invocation expression syntax, whichmakesthemverysimpletouseandallowseasychainingofmultipleprocessors.

11.3.13.1.CountAggregatorThecountaggregatorisasafewaytoobtainanumberofitemsinacollection.Itcan be applied to a collection of any type, including arrays, which helpseliminate the decision on whether to use Count or Length propertydepending on the context. Unlike its standard .NET counterparts, countaggregator can also be invoked on the null context without throwing aNullReferenceException. It will simply return zero in this case,which makes it much safer than standard .NET properties within largerexpression.

ExpressionEvaluator.GetValue(null,"{1,5,-3}.count()")//3

ExpressionEvaluator.GetValue(null,"count()")//0

11.3.13.2.SumAggregatorThesumaggregatorcanbeusedtocalculateatotalforthelistofnumericvalues.If numbers within the list are not of the same type or precision, it willautomatically perform necessary conversion and the result will be the highest

Page 262: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

precisiontype.Ifanyofthecollectionelementsisnotanumber,thisaggregatorwillthrowanInvalidArgumentException.

ExpressionEvaluator.GetValue(null,"{1,5,-3,10}.sum()")

ExpressionEvaluator.GetValue(null,"{5,5.8,12.2,1}.sum()"

11.3.13.3.AverageAggregatorTheaverageaggregatorwillreturntheaverageforthecollectionofnumbers.Itwill use the same typecoercion rules, as the sumaggregator inorder tobeaspreciseaspossible.Justlikethesumaggregator,ifanyofthecollectionelementsisnotanumber,itwillthrowanInvalidArgumentException.

ExpressionEvaluator.GetValue(null,"{1,5,-4,10}.average()"

ExpressionEvaluator.GetValue(null,"{1,5,-2,10}.average()"

11.3.13.4.MinimumAggregatorTheminimum aggregator will return the smallest item in the list. In order todetermine what "the smallest" actually means, this aggregator relies on theassumption that the collection items are of the uniform type and that theyimplement the IComparable interface. If that is not the case, thisaggregatorwillthrowanInvalidArgumentException.

ExpressionEvaluator.GetValue(null,"{1,5,-3,10}.min()")

ExpressionEvaluator.GetValue(null,"{'abc','efg','xyz'}.min()"

11.3.13.5.MaximumAggregatorThe maximum aggregator will return the largest item in the list. In order todetermine what "the largest" actually means, this aggregator relies on theassumption that the collection items are of the uniform type and that theyimplementIComparable interface. If that is not the case, this aggregatorwillthrowanInvalidArgumentException.

ExpressionEvaluator.GetValue(null,"{1,5,-3,10}.max()")

ExpressionEvaluator.GetValue(null,"{'abc','efg','xyz'}.max()"

Page 263: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.3.13.6.Non-nullProcessorA non-null processor is a very simple collection processor that eliminates allnullvaluesfromthecollection.

ExpressionEvaluator.GetValue(null,"{'abc','xyz',null,'abc','def',null}.nonNull()"

ExpressionEvaluator.GetValue(null,"{'abc','xyz',null,'abc','def',null}.nonNull().distinct().sort()"

11.3.13.7.DistinctProcessorAdistinctprocessorisveryusefulwhenyouwanttoensurethatyoudon'thaveduplicate items in the collection. It can also accept an optional Booleanargument thatwilldeterminewhethernull values should be included in theresults.Thedefaultisfalse,whichmeansthattheywillnotbeincluded.

ExpressionEvaluator.GetValue(null,"{'abc','xyz','abc','def',null,'def'}.distinct(true).sort()"

ExpressionEvaluator.GetValue(null,"{'abc','xyz','abc','def',null,'def'}.distinct(false).sort()"

11.3.13.8.SortProcessorThe sort processor can be used to sort uniform collections of elements thatimplementIComparable.

ExpressionEvaluator.GetValue(null,"{1.2,5.5,-3.3}.sort()"

ExpressionEvaluator.GetValue(null,"{'abc','xyz','abc','def',null,'def'}.sort()"

Thesortprocessoralsoacceptsabooleanvalueasanargumenttodeterminesortorder,sort(false)willsortthecollectionindecendingorder.

11.3.13.9.TypeConversionProcessorTheconvertprocessorcanbeusedtoconvertacollectionofelementstoagivenType.

object[]arr=newobject[]{"0",1,1.1m,"1.1",1.1f};

decimal[]result=(decimal[])ExpressionEvaluator.GetValue(arr,

11.3.13.10.ReverseProcessor

Page 264: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Thereverseprocessorreturnsthereverseorderofelementsinthelist

object[]arr=newobject[]{"0",1,2.1m,"3",4.1f};

object[]result=newArrayList((ICollection)ExpressionEvaluator.GetValue(arr,

11.3.13.11.OrderByProcessorCollections can be ordered in three ways, an expression, a SpEL lamdaexpreression,oradelegate.

//orderByexpression

IExpressionexp=Expression.Parse("orderBy('ToString()')");

object[]input=newobject[]{'b',1,2.0,"a"};

object[]ordered=exp.GetValue(input);//{1,2.0,"a",'b'}

//SpELlambdaexpressions

IExpressionexp=Expression.Parse("orderBy({|a,b|$a.ToString().CompareTo($b.ToString())})"

object[]input=newobject[]{'b',1,2.0,"a"};

object[]ordered=exp.GetValue(input);//{1,2.0,"a",'b'}

Hashtablevars=newHashtable();

Expression.RegisterFunction("compare","{|a,b|$a.ToString().CompareTo($b.ToString())}"

exp=Expression.Parse("orderBy(#compare)");

ordered=exp.GetValue(input,vars);//{1,2.0,"a",'b'}

//.NETdelegate

privatedelegateintCompareCallback(objectx,objecty);

privateintCompareObjects(objectx,objecty)

{

if(x==y)return0;

returnx.ToString().CompareTo(""+y);

}

Hashtablevars=newHashtable();

vars["compare"]=newCompareCallback(CompareObjects);

IExpressionexp=Expression.Parse("orderBy(#compare)");

object[]input=newobject[]{'b',1,2.0,"a"};

object[]ordered=exp.GetValue(input);//{1,2.0,"a",'b'}

Page 265: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.3.13.12.UserDefinedCollectionProcessorYoucanregisteryourowncollectionprocessorforuseinevaluationacollection.HereisanexampleofaICollectionProcessorimplementationthatsumsonlytheevennumbersofanintegerlist

publicclassIntEvenSumCollectionProcessor:ICollectionProcessor

{

publicobjectProcess(ICollectionsource,object

{

objecttotal=0d;

foreach(objectiteminsource)

{

if(item!=null)

{

if(NumberUtils.IsInteger(item))

{

if((int)item%2==0)

{

total=NumberUtils.Add(total,item);

}

}

else

{

thrownewArgumentException("Sumcanonlybecalculatedforacollectionofnumericvalues."

}

}

}

returntotal;

}

}

publicvoidDoWork()

{

Hashtablevars=newHashtable();

vars["EvenSum"]=newIntEvenSumCollectionProcessor();

intresult=(int)ExpressionEvaluator.GetValue(null

}

Page 266: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.3.14.SpringObjectReferencesExpressionscanrefertoobjectsthataredeclaredinSpring'sapplicationcontextusingthesyntax@(contextName:objectName).IfnocontextNameisspecifiedthedefaultrootcontextname(Spring.RootContext)isused.Usingtheapplication context defined in the MovieFinder example from Chapter 33, IoCQuickstarts, the following expression returns the number ofmovies directed byRobertoBenigni.

publicstaticvoidMain()

{

...

//Retrievecontextdefinedinthespring/contextsectionof

//thestandard.NETconfigurationfile.

IApplicationContextctx=ContextRegistry.GetContext();

intnumMovies=(int)ExpressionEvaluator.GetValue(null,

"@(MyMovieLister).MoviesDirectedBy('RobertoBenigni').Length"

...

}

ThevariablenumMoviesisevaluatedto2inthisexample.

11.3.15.LambdaExpressionsAsomewhat advanced,but averypowerful featureofSpring.NETExpressionLanguage are lambda expressions. Lambda expressions allow you to defineinline functions,which can thenbeusedwithinyour expressions just like anyotherfunctionormethod.Youmayalsouse.NETdelegatesasdescribedinthenextsection.Thesyntaxfordefininglambdaexpressionsis:#functionName={|argList|functionBody}

Forexample,youcoulddefineamaxfunctionandcallitlikethis:

ExpressionEvaluator.GetValue(null,"(#max={|x,y|$x>$y?$x:$y};#max(5,25))"

Page 267: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

As you can see, any arguments defined for the expression can be referencedwithinthefunctionbodyusingalocalvariablesyntax,$varName.Invocationofthe function defined using lambda expression is as simple as specifying thecomma-separated list of function arguments in parentheses, after the functionname.Lambda expressions can be recursive, which means that you can invoke thefunctionwithinitsownbody:

ExpressionEvaluator.GetValue(null,"(#fact={|n|$n<=1?1:$n*#fact($n-1)};#fact(5))"

Notice that in both examples above we had to specify a variablesparameterfortheGetValuemethod.Thisisbecauselambdaexpressionsareactually nothing more than parameterized variables and we need variablesdictionaryinordertostorethem.Ifyoudon'tspecifyavalidIDictionaryinstanceforthevariablesparameter,youwillgetaruntimeexception.Also,inbothexamplesaboveweusedanexpressionlistinordertodefineandinvokeafunctioninasingleexpression.However,morelikelythannot,youwillwant to define your functions once and then use them within as manyexpressionsasyouneed.Spring.NETprovidesaneasywaytopre-registeryourlambda expressions by exposing a staticExpression.RegisterFunction method, which takes functionname, lambda expression and variables dictionary to register function in asparameters:

IDictionaryvars=newHashtable();

Expression.RegisterFunction("sqrt","{|n|Math.Sqrt($n)}",vars);

Expression.RegisterFunction("fact","{|n|$n<=1?1:$n*#fact($n-1)}"

Once the function registration is done, you can simply evaluate an expressionthatusesthesefunctions,makingsurethat thevarsdictionary ispassedasaparametertoexpressionevaluationengine:

ExpressionEvaluator.GetValue(null,"#fact(5)",vars)//120

ExpressionEvaluator.GetValue(null,"#sqrt(9)",vars)//3

Finally, because lambda expressions are treated as variables, they can be

Page 268: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

assignedtoothervariablesorpassedasparameterstootherlambdaexpressions.In the following example we are defining a delegate function that acceptsfunctionfasthefirstargumentandparameternthatwillbepassedtofunctionf as the second. Then we invoke the functions registered in the previousexample,aswellasthelambdaexpressiondefinedinline,throughourdelegate:

Expression.RegisterFunction("delegate","{|f,n|$f($n)}",vars);

ExpressionEvaluator.GetValue(null,"#delegate(#sqrt,4)",vars)

ExpressionEvaluator.GetValue(null,"#delegate(#fact,5)",vars)

ExpressionEvaluator.GetValue(null,"#delegate({|n|$n^2},5)"

Whilethisparticularexampleisnotparticularlyuseful,itdoesdemonstratethatlambda expressions are indeed treated as nothing more than parameterizedvariables,whichisimportanttoremember.

11.3.16.DelegateExpressionsDelegate expressions allow you to refer to .NET delegateswhich can then beusedwithinyourexpressionsjustlikeanyotherfunctionormethod.Forexample,youcandefineamaxdelegateandcallitlikethis

privatedelegatedoubleDoubleFunctionTwoArgs(doublearg1,double

privatedoubleMax(doublearg1,doublearg2)

{

returnMath.Max(arg1,arg2);

}

publicvoidDoWork()

{

Hashtablevars=newHashtable();

vars["max"]=newDoubleFunctionTwoArgs(Max);

doubleresult=(double)ExpressionEvaluator.GetValue(null

}

11.3.17.NullContextIf you do not specify a root object, i.e. pass in null, then the expressionsevaluatedeitherhavetobeliteralvalues,i.e.ExpressionEvaluator.GetValue(null,

Page 269: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

"2 + 3.14"), refer to classes that have static methods or properties, i.e.ExpressionEvaluator.GetValue(null,"DateTime.Today"),createnewinstancesofobjects, i.e. ExpressionEvaluator.GetValue(null, "newDateTime(2004, 8, 14)")or refer to other objects such as those in the variable dictionary or in the IoCcontainer.Thelattertwousageswillbediscussedlater.

Page 270: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

11.4.ClassesusedintheexamplesThe following simple classes are used to demonstrate the functionality of theexpressionlanguage.

publicclassInventor

{

publicstringName;

publicstringNationality;

publicstring[]Inventions;

privateDateTimedob;

privatePlacepob;

publicInventor():this(null,DateTime.MinValue,null)

{}

publicInventor(stringname,DateTimedateOfBirth,string

{

this.Name=name;

this.dob=dateOfBirth;

this.Nationality=nationality;

this.pob=newPlace();

}

publicDateTimeDOB

{

get{returndob;}

set{dob=value;}

}

publicPlacePlaceOfBirth

{

get{returnpob;}

}

publicintGetAge(DateTimeon)

{

//notveryaccurate,butitwilldothejob;-)

returnon.Year-dob.Year;

}

}

Page 271: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassPlace

{

publicstringCity;

publicstringCountry;

}

publicclassSociety

{

publicstringName;

publicstaticstringAdvisors="advisors";

publicstaticstringPresident="president";

privateIListmembers=newArrayList();

privateIDictionaryofficers=newHashtable();

publicIListMembers

{

get{returnmembers;}

}

publicIDictionaryOfficers

{

get{returnofficers;}

}

publicboolIsMember(stringname)

{

boolfound=false;

foreach(Inventorinventorinmembers)

{

if(inventor.Name==name)

{

found=true;

break;

}

}

returnfound;

}

}

The code listings in this chapter use instances of the data populated with thefollowinginformation.

Page 272: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Inventortesla=newInventor("NikolaTesla",newDateTime(1856,7,9),

tesla.Inventions=newstring[]

{

"Telephonerepeater","Rotatingmagneticfieldprinciple"

"Polyphasealternating-currentsystem","Inductionmotor"

"Alternating-currentpowertransmission","Teslacoiltransformer"

"Wirelesscommunication","Radio","Fluorescentlights"

};

tesla.PlaceOfBirth.City="Smiljan";

Inventorpupin=newInventor("MihajloPupin",newDateTime(1854,10,9),

pupin.Inventions=newstring[]{"Longdistancetelephony&telegraphy"

pupin.PlaceOfBirth.City="Idvor";

pupin.PlaceOfBirth.Country="Serbia";

Societyieee=newSociety();

ieee.Members.Add(tesla);

ieee.Members.Add(pupin);

ieee.Officers["president"]=pupin;

ieee.Officers["advisors"]=newInventor[]{tesla,pupin};

Page 273: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter12.ValidationFramework

Page 274: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.1.IntroductionDatavalidationisaveryimportantpartofanyenterpriseapplication.ASP.NEThasavalidationframeworkbutitisverylimitedinscopeandstartsfallingapartassoonasyouneedtoperformmorecomplexvalidations.ProblemswiththeoutoftheboxASP.NETvalidationframeworkarewelldocumentedbyPeterBlumonhiswebsite,sowearenotgoingtorepeatthemhere.Peterhasalsobuiltanicereplacement for the standard ASP.NET validation framework, which is worthlooking into if you prefer the standardASP.NETvalidationmechanism to theoneofferedbySpring.NETforsomereason.Bothframeworkswillallowyoutoperform very complex validations butwe designed the Spring.NET validationframeworkdifferentlyforthereasonsdescribedbelow.On theWindows Forms side the situation is evenworse.Out of the box datavalidationfeaturesarecompletelyinadequateaspointedoutbyIanGriffiths inthis article. One of themajor problemswe saw inmost validation frameworksavailable today, both open source and commercial, is that they are tied to aspecific presentation technology. The ASP.NET validation framework usesASP.NETcontrolstodefinevalidationrules,sotheserulesendupintheHTMLmarkupofyourpages.PeterBlum'sframeworkusesthesameapproach.Inouropinion,validationisnotapplicableonlytothepresentationlayersothereisnoreasontotieittoanyparticulartechnology.Assuch,theSpring.NETValidationFramework is designed in a way that enables data validation in differentapplicationlayersusingthesamevalidationrules.Thegoalsofthevalidationframeworkarethefollowing:

1. Allow for the validation of any object, whether it is a UI control or adomainobject.

2. Allowthesamevalidationframework tobeused inbothWindowsFormsand ASP.NET applications, as well as in the service layer (to validateparameterspassedtotheservice,forexample).

3. Allowcompositionofthevalidationrulessoarbitrarilycomplexvalidationrulesetscanbeconstructed.

4. Allow validators to be conditional so they only execute if a specificconditionismet.

The following sections will describe in more detail how these goals wereachieved and show you how to use the Spring.NETValidation Framework in

Page 275: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

yourapplications.

Page 276: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.2.ExampleUsageDecoupling validation from presentationwas themajor goal that significantlyinfluenceddesignofthevalidationframework.Wewantedtobeabletodefineasetofvalidationrulesthatarecompletelyindependentfromthepresentationsowe can reuse them (or at least have the ability to reuse them) in differentapplication layers.Thismeant that the approach takenbyMicrosoftASP.NETteamwould notwork and custom validation controlswere not an option. Theapproach taken was to configure validation rules just like any other objectmanagedbySpring -within the application context.However, due to possiblecomplexity of the validation rules we decided not to use the standardSpring.NETconfigurationschemaforvalidatordefinitionsbuttoinsteadprovideamore specific and easier to use custom configuration schema for validation.NotethatthevalidationframeworkisnottiedtotheuseofXML,youcanuseitsAPIProgramatically.ThefollowingexampleshowsvalidationrulesdefinedfortheTripobjectintheSpringAirsampleapplication:

<objectsxmlns="http://www.springframework.net"xmlns:v="http://www.springframework.net/validation"

<objecttype="TripForm.aspx"parent="standardPage">

<propertyname="TripValidator"ref="tripValidator"/>

</object>

<v:groupid="tripValidator">

<v:requiredid="departureAirportValidator"test="StartingFrom.AirportCode"

<v:messageid="error.departureAirport.required"providers

</v:required>

<v:groupid="destinationAirportValidator">

<v:requiredtest="ReturningFrom.AirportCode">

<v:messageid="error.destinationAirport.required"

</v:required>

<v:conditiontest="ReturningFrom.AirportCode!=StartingFrom.AirportCode"

<v:messageid="error.destinationAirport.sameAsDeparture"

</v:condition>

</v:group>

<v:groupid="departureDateValidator">

<v:requiredtest="StartingFrom.Date">

Page 277: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<v:messageid="error.departureDate.required"providers

</v:required>

<v:conditiontest="StartingFrom.Date>=DateTime.Today"

<v:messageid="error.departureDate.inThePast"providers

</v:condition>

</v:group>

<v:groupid="returnDateValidator"when="Mode=='RoundTrip'"

<v:requiredtest="ReturningFrom.Date">

<v:messageid="error.returnDate.required"providers

</v:required>

<v:conditiontest="ReturningFrom.Date>=StartingFrom.Date"

<v:messageid="error.returnDate.beforeDeparture"

</v:condition>

</v:group>

</v:group>

</objects>

Thereareafewthingstonoteintheexampleabove:

You need to reference the validation schema by adding axmlns:v="http://www.springframework.net/validation"

namespacedeclarationtotherootelement.

You can mix standard object definitions and validator definitions in thesameconfigurationfileaslongasbothschemasarereferenced.

The Validator defined in the configuration file is identified by and idattributeandcanbereferencedinthestandardSpringway,i.e.theinjectionoftripValidatorintoTripForm.aspxpagedefinitioninthefirst<object>tagabove.

The validation framework uses Spring's powerful expression evaluationenginetoevaluatebothvalidationrulesandapplicabilityconditionsforthevalidator.Assuch,anyvalidSpringexpressioncanbespecifiedwithinthetestandwhenattributesofanyvalidator.

The example above shows many of the features of the framework, so let'sdiscussthemonebyoneinthefollowingsections.

Page 278: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.3.ValidatorGroupsValidatorscanbegroupedtogether.This is importantformanyreasonsbut themosttypicalusagescenarioistogroupmultiplevalidationrulesthatapplytothesame value. In the example above there is a validator group for almost everypropertyoftheTripinstance.Thereisalsoatop-levelgroupfortheTripobjectitselfthatgroupsallothervalidators.Therearethreetypesofvalidatorgroupseachwithadifferentbehavior:Whilethefirsttype(AND)isdefinitelythemostuseful,theothertwoallowyouto implement some specific validation scenarios in a very simpleway, so youshouldkeeptheminmindwhendesigningyourvalidationrules.

Table12.1.ValidatorGroupsType XMLTag BehaviorAND group Returnstrueonlyifallcontainedvalidatorsreturntrue.Thisisthe

mostcommonlyusedvalidatorgroup.

OR any Returnstrueifoneormoreofthecontainedvalidatorsreturntrue.

XOR exclusive Returnstrueifonlyoneofthecontainedvalidatorsreturntrue.

Onethingtorememberisthatavalidatorgroupisavalidatorlikeanyotherandcanbeusedanywherevalidator is expected.Youcannest groupswithinothergroupsandreferencethemusingvalidatorreferencesyntax(describedlater),sotheyreallyallowyoutostructureyourvalidationrulesinthemostreusableway.

Page 279: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.4.ValidatorsUltimately,youwillhaveoneormorevalidatordefinitionsforeachpieceofdatathat you want to validate. Spring.NET has several built-in validators that aresufficient for most validations, even fairly complex ones. The framework isextensible so you can write your own custom validators and use them in thesamewayasthebuilt-inones.

12.4.1.ConditionValidatorThe condition validator evaluates any logical expression that is supported bySpring'sevaluationengine.Thesyntaxis

<v:conditionid="id"test="testCondition"when="applicabilityCondition"

actions

</v:condition>

Anexampleisshownbelow

<v:conditiontest="StartingFrom.Date>=DateTime.Today"when

<v:messageid="error.departureDate.inThePast"providers="departureDateErrors,validationSummary"

</v:condition>

InthisexampletheStartingFrompropertyoftheTripobjectiscomparedtoseeifitislaterthanthecurrentdate,i.e.DateTimebutonlywhenthedatehasbeenset(theinitialvalueofStartingFrom.DatewassettoDateTime.MinValue).Theconditionvalidatorcouldbeconsidered"themotherofallvalidators".Youcan use it to achieve almost anything that can be achieved by using othervalidator types, but in some cases the test expressionmight be very complex,whichiswhyyoushouldusemorespecificvalidatortypeifpossible.However,conditionvalidatorisstillyourbestbetifyouneedtocheckwhetherparticularvaluebelongstoaparticularrange,orperformasimilartest,asthoseconditionsarefairlyeasytowrite.

Note

KeepinmindthatSpring.NETValidationFrameworktypicallyworkswithdomainobjects.Thisisafterdatabindingfromthecontrolshasbeenperformedsothattheobjectbeingvalidatedisstronglytyped.Thismeansthatyoucaneasilycomparenumbersand

Page 280: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

dateswithouthavingtoworryifthestringrepresentationiscomparable.

12.4.2.RequiredValidatorThisvalidatorensuresthatthespecifiedtestvalueisnotempty.Thesyntaxis

<v:requiredid="id"test="requiredValue"when="applicabilityCondition"

actions

</v:required>

Anexampleisshownbelow

<v:requiredtest="ReturningFrom.AirportCode">

<v:messageid="error.destinationAirport.required"providers

</v:required>

Thespecifictestsdonetodetermineiftherequiredvalueissetislistedbelow

Table12.2.RulestodetermineifrequiredvalueisvalidSystem.Type Test

System.Type Typeexists

System.String notnulloranemptystring

system.DateTimeNotSystem.DateTime.MinValueandnotsystem.DateTime.MaxValue

Oneofthenumbertypes. notzero

System.CharNotSystem.Char.MinValueorwhitespace.

AnyreferencetypeotherthanSystem.String notnull

Page 281: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Requiredvalidatorisalsooneofthemostcommonlyusedones,anditismuchmore powerful than the ASP.NET Required validator, because it works withmany other data types other than strings. For example, it will allow you tovalidateDateTime instances (bothMinValue andMaxValue returnfalse),integeranddecimalnumbers,aswellasanyreferencetype,inwhichcaseitreturnstrueforanon-nullvalueandfalsefor{{null}}s.Thetestattributefor therequiredvalidatorwill typicallyspecifyanexpressionthat resolves to a property of a domain object, but it could be any validexpressionthatreturnsavalue,includingamethodcall.

12.4.3.RegularExpressionValidatorThesyntaxis

<v:regexid="id"test="valueToEvaluate"when="applicabilityCondition"

<v:propertyname="Expression"value="regularExpressionToMatch"

<v:propertyname="Options"value="regexOptions"/>

actions

</v:regex>

Anexampleisshownbelow

<v:regextest="ReturningFrom.AirportCode">

<v:propertyname="Expression"value="[A-Z][A-Z][A-Z]"/>

<v:messageid="error.destinationAirport.threeCharacters"

</v:regex>

Regularexpressionvalidator isveryusefulwhenvalidatingvaluesthatneedtoconform to some predefined format, such as telephone numbers, emailaddresses,URLs,etc.Onemajordifferenceoftheregularexpressionvalidatorcomparedtootherbuilt-invalidatortypesisthatyouneedtosetarequiredExpressionpropertytoaregularexpressiontomatchagainst.

Page 282: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.4.4.GenericValidatorThesyntaxis

<v:validatorid="id"test="requiredValue"when="applicabilityCondition"

actions

</v:validator>

Anexampleisshownbelow

<v:validatortest="ReturningFrom.AirportCode"type="MyNamespace.MyAirportCodeValidator,MyAssembly"

<v:messageid="error.destinationAirport.invalid"providers

</v:required>

Genericvalidatorallowsyoutopluginyourcustomvalidatorbyspecifying itstype name. Custom validators are very simple to implement, because all youneedtodoisextendBaseValidatorclassandimplementabstractboolValidate(object objectToValidate) method. Yourimplementation simply needs to return true if it determines that object isvalid,orfalseotherwise

12.4.5.ConditionalValidatorExecutionAsyoucansee fromtheexamplesabove,eachvalidator (andvalidatorgroup)allowsyoutodefineitsapplicabilityconditionbyspecifyingalogicalexpressionasthevalueofthewhenattribute.Thisfeatureisveryusefulandisoneofthemajor deficiencies in the standardASP.NET validation framework, because inmanycasesspecificvalidatorsneedtobeturnedonoroffbasedonthevaluesoftheobjectbeingvalidated.Forexample,whenvalidatingaTripobjectweneedtovalidatereturndateonlyiftheTrip.ModepropertyissettotheTripMode.RoundTripenumvalue.Inordertoachievethatwecreatedfollowingvalidatordefinition:

<v:groupid="returnDateValidator"when="Mode=='RoundTrip'"

//nestedvalidators

</v:group>

Validatorswithinthisgroupwillonlybeevaluatedforroundtrips.

Page 283: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Note

Youshouldalsonotethatyoucancompareenumsusingthestringvalueoftheenumeration.Youcanalsousefullyqualifiedenumname,suchas:Mode==TripMode.RoundTrip

However,inthiscaseyouneedtomakesurethataliasfortheTripModeenumtypeisregisteredusingSpring'sstandardtypealiasingmechanism.

Page 284: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.5.ValidatorActionsValidationactionsareexecutedeverytimethecontainingvalidatorisexecuted.Theyallowyoutodoanythingyouwantbasedontheresultofthevalidation.Byfar the most common use of the validation action is to add validation errormessage to the errors collection, but theoretically you could do anything youwant.Becauseaddingvalidationerrormessagestotheerrorscollectionissuchacommon scenario, Spring.NETvalidation schema defines a separateXML tagforthistypeofvalidationaction.

12.5.1.ErrorMessageActionThesyntaxis

<v:messageid="messageId"providers="errorProviderList"when

<v:paramvalue="paramExpression"/>

</v:message>

Anexampleisshownbelow

<v:messageid="error.departureDate.inThePast"providers="departureDateErrors,validationSummary"

<v:paramvalue="StartingFrom.Date.ToString('D')"/>

<v:paramvalue="DateTime.Today.ToString('D')"/>

</v:message>

Thereare several things thatyouhave tobeawareofwhendealingwitherrormessages:

id is used to look up the error message in the appropriate Spring.NETmessagesource.

providers specifies a comma separated list of "error buckets"particularerrormessageshouldbeaddedto.These"buckets"will laterbeused by the particular presentation technology in order to display errormessagesasnecessary.

a message can have zero or more parameters. Each parameter is anexpression that will be resolved using current validation context and theresolved values will be passed as parameters toIMessageSource.GetMessage method, which will return the

Page 285: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

fullyresolvedmessage.

12.5.2.GenericActionsThesyntaxis

<v:actiontype="actionType"when="actionApplicabilityCondition"

properties

</v:action>

Anexampleisshownbelow

<v:actiontype="Spring.Validation.Actions.ExpressionAction,Spring.Core"

<v:propertyname="Valid"value="#page.myPanel.Visible=true"

<v:propertyname="Invalid"value="#page.myPanel.Visible=false"

</v:action>

Genericactionscanbeusedtoperformallkindsofvalidationactions.Insimplecases,suchasintheexampleabovewhereweturncontrol'svisibilityonoroffdepending on the validation result, you can use the built-inExpressionActionclassandsimplyspecifyexpressionstobeevaluatedbasedonthevalidatorresult.In other situations you may want to create your own action implementation,which is fairly simple thing to do – all you need to do is implementIValidationActioninterface:

publicinterfaceIValidationAction

{

///<summary>

///Executestheaction.

///</summary>

///<paramname="isValid">Whetherassociatedvalidatorisvalidornot.</param>

///<paramname="validationContext">Validationcontext.</param>

///<paramname="contextParams">Additionalcontextparameters.</param>

///<paramname="errors">Validationerrorscontainer.</param>

voidExecute(boolisValid,objectvalidationContext,IDictionarycontextParams,ValidationErrorserrors);

}

Page 286: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.6.ValidatorReferencesSometimesitisnotpossible(ordesirable)tonestallthevalidationruleswithinasingletop-levelvalidatorgroup.Forexample,ifyouhaveanobjectgraphwherebothObjectAandObjectBhaveareferencetoObjectC,youmightwanttosetupvalidation rules forObjectConlyonceand reference them from thevalidationrules for both ObjectA and ObjectB, instead of duplicating them within bothdefinitions.Thesyntaxisshownbelow

<v:refname="referencedValidatorId"context="validationContextForTheReferencedValidator"

Anexampleisshownbelow

<v:groupid="objectA.validator">

<v:refname="objectC.validator"context="MyObjectC"/>

//othervalidatorsforObjectA

</v:group>

<v:groupid="objectB.validator">

<v:refname="objectC.validator"context="ObjectCProperty"

//othervalidatorsforObjectB

</v:group>

<v:groupid="objectC.Validator">

//validatorsforObjectC

</v:group>

Itisassimpleasthat—youdefinevalidationrulesforObjectCseparatelyandreference them fromwithin other validation groups. Important thing to realizethatinmostcasesyouwillalsowantto"narrow"thecontextforthereferencedvalidator,typicallybyspecifyingthenameofthepropertythatholdsreferencedobject. In the example above, ObjectA.MyObjectC andObjectB.ObjectCProperty are both of type ObjectC, which objectC.validatorexpectstoreceiveasthevalidationcontext.

Page 287: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.7.ProgammaticusageYoucanalsocreateValidatorsprogrammaticallyusing theAPI.Anexample isshownbelow

UserInfouserInfo=newUserInfo();//hasNameandPasswordprops

ValidatorGroupuserInfoValidator=newValidatorGroup();

userInfoValidator.Validators

.Add(newRequiredValidator("Name",null));

userInfoValidator.Validators

.Add(newRequiredValidator("Password",null

ValidationErrorserrors=newValidationErrors();

booluserInfoIsValid=userInfoValidator.Validate(userInfo,errors);

Nomatter ifyoucreateyourvalidatorsprogrammaticallyordeclaratively,youcaninvoketheminservicesidecodeviathe'Validate'methodshownaboveandthenhandleerrorconditions.SpringprovidesAOPparametervalidationadviceaspartofitheaspectlibrarywhichmayalsobeusefulforperformingserver-sidevalidation.

Page 288: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

12.8.UsagetipswithinASP.NETNowthatyouknowhowtoconfigurevalidationrules,let'sseewhatittakestoevaluate those rules within your typical ASP.NET application and to displayerrormessages.The first thing you need to do is inject validators you want to use into yourASP.NETpage,asshownintheexamplebelow:

<objectsxmlns="http://www.springframework.net"xmlns:v="http://www.springframework.net/validation"

<objecttype="TripForm.aspx"parent="standardPage">

<propertyname="TripValidator"ref="tripValidator"/>

</object>

<v:groupid="tripValidator">

//ourvalidationrules

</v:group>

</objects>

Once that's done, you need to perform validation in one ormore of the pageeventhandlers,whichtypicallylookssimilartothis:

publicvoidSearchForFlights(objectsender,EventArgse)

{

if(Validate(Controller.Trip,tripValidator))

{

Process.SetView(Controller.SearchForFlights());

}

}

Note

KeepinmindthatyourASP.NETpageneedstoextendSpring.Web.UI.Pageinorderforthecodeabovetowork.

Finally, you need to define where validation errors should be displayed byadding one or more <spring:validationError/> and<spring:validationSummary/>controlstotheASP.NETform:

Page 289: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<%@PageLanguage="c#"MasterPageFile="~/Web/StandardTemplate.master"

<%@RegisterTagPrefix="spring"Namespace="Spring.Web.UI.Controls"

<asp:ContentID="head"ContentPlaceHolderID="head"runat="server"

<scriptlanguage="javascript"type="text/javascript">

<!--

functionshowReturnCalendar(isVisible)

{

document.getElementById('<%=returningOnDate.ClientID%>').style.visibility=isVisible?'':'hidden';

document.getElementById('returningOnCalendar').style.visibility=isVisible?'':'hidden';

}

-->

</script>

</asp:Content>

<asp:ContentID="body"ContentPlaceHolderID="body"runat="server"

<divstyle="text-align:center">

<h4><asp:LabelID="caption"runat="server"></asp:Label>

<spring:ValidationSummaryID="validationSummary"runat

<table>

<trclass="formLabel">

<td>&nbsp;</td>

<tdcolspan="3">

<spring:RadioButtonGroupID="tripMode"runat

<asp:RadioButtonID="OneWay"onclick

<asp:RadioButtonID="RoundTrip"onclick

</spring:RadioButtonGroup>

</td>

</tr>

<tr>

<tdclass="formLabel"align="right">

<asp:LabelID="leavingFrom"runat="server"

<tdnowrap="nowrap">

<asp:DropDownListID="leavingFromAirportCode"

<spring:ValidationErrorid="departureAirportErrors"

</td>

<tdclass="formLabel"align="right">

<asp:LabelID="goingTo"runat="server"/>

<tdnowrap="nowrap">

<asp:DropDownListID="goingToAirportCode"

Page 290: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<spring:ValidationErrorid="destinationAirportErrors"

</td>

</tr>

<tr>

<tdclass="formLabel"align="right">

<asp:LabelID="leavingOn"runat="server"

<tdnowrap="nowrap">

<spring:CalendarID="leavingFromDate"runat

<spring:ValidationErrorid="departureDateErrors"

</td>

<tdclass="formLabel"align="right">

<asp:LabelID="returningOn"runat="server"

<tdnowrap="nowrap">

<divid="returningOnCalendar">

<spring:CalendarID="returningOnDate"

<spring:ValidationErrorid="returnDateErrors"

</div>

</td>

</tr>

<tr>

<tdclass="buttonBar"colspan="4">

<br/>

<asp:ButtonID="findFlights"runat="server"

</tr>

</table>

</div>

<scriptlanguage="javascript"type="text/javascript">

if(document.getElementById('<%=tripMode.ClientID

showReturnCalendar(false);

else

showReturnCalendar(true);

</script>

</asp:Content>

12.8.1.RenderingValidationErrorsSpring.NET allows you to render validation errors within the page in severaldifferentways, and if none of them suits your needs you can implement yourown validation errors renderer. Implementations of the

Page 291: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Spring.Web.Validation.IValidationErrorsRenderer

thatshipwiththeframeworkare:

Table12.3.ValidationRenderersName Class

Block Spring.Web.Validation.DivValidationErrorsRenderer

Inline Spring.Web.Validation.SpanValidationErrorsRenderer

Icon Spring.Web.Validation.IconValidationErrorsRenderer

Thesethreeerrorrenderersshouldbesufficientformostapplications,butincaseyouwanttodisplayerrorsinsomeotherwayyoucanwriteyourownrendererby implementingSpring.Web.Validation.IValidationErrorsRenderer

interface:

namespaceSpring.Web.Validation

{

///<summary>

///Thisinterfaceshouldbeimplementedbyallvalidationerrorsrenderers.

///</summary>

///<remarks>

///<para>

///Validationerrorsrenderersareusedtodecouplerenderingbehaviorfromthe

///validationerrorscontrolssuchas<seecref="ValidationError"/>and

///<seecref="ValidationSummary"/>.

///</para>

///<para>

Page 292: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

///Thisallowsuserstochangehowvalidationerrorsarerenderedbysimplypluggingin

///appropriaterendererimplementationintothevalidationerrorscontrolsusing

///Spring.NETdependencyinjection.

///</para>

///</remarks>

publicinterfaceIValidationErrorsRenderer

{

///<summary>

///Rendersvalidationerrorsusingspecified<seecref="HtmlTextWriter"/>.

///</summary>

///<paramname="page">Webforminstance.</param>

///<paramname="writer">AnHTMLwritertouse.</param>

///<paramname="errors">Thelistofvalidationerrors.</param>

voidRenderErrors(Pagepage,HtmlTextWriterwriter,IListerrors);

}

}

12.8.1.1.ConfiguringwhichErrorRenderertouse.Thebestpartoftheerrorsrenderermechanismisthatyoucaneasilychangeitacross the application by modifying configuration templates for<spring:validationSummary> and<spring:validationError>controls:

<!--Validationerrorsrendererconfiguration-->

<objectid="Spring.Web.UI.Controls.ValidationError"abstract

<propertyname="Renderer">

<objecttype="Spring.Web.Validation.IconValidationErrorsRenderer,Spring.Web"

<propertyname="IconSrc"value="validation-error.gif"/>

</object>

</property>

</object>

<objectid="Spring.Web.UI.Controls.ValidationSummary"abstract

<propertyname="Renderer">

<objecttype="Spring.Web.Validation.DivValidationErrorsRenderer,Spring.Web"

<propertyname="CssClass"value="validationError"/>

</object>

</property>

</object>

Page 293: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

It'sassimpleasthat!

Page 294: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter13.AspectOrientedProgrammingwithSpring.NET

Page 295: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.1.IntroductionAspect-OrientedProgramming (AOP) complementsOOPbyprovidinganotherwayofthinkingaboutprogramstructure.WhereasOOdecomposesapplicationsintoahierarchyofobjects,AOPdecomposesprogramsintoaspectsorconcerns.This enables the modularization of concerns such as transaction managementthatwouldotherwisecutacrossmultipleobjects(suchconcernsareoftentermedcrosscuttingconcerns).One of the key components of Spring.NET is theAOP framework.While theSpring.NETIoCcontainerdoesnotdependonAOP,meaningyoudon'tneedtouseAOPifyoudon'twantto,AOPcomplementsSpring.NETIoCtoprovideaverycapablemiddlewaresolution.AOPisusedinSpring.NET:

Toprovidedeclarativeenterprise services, especiallyasa replacement forCOM+declarativeservices.Themostimportantsuchserviceisdeclarativetransaction management, which builds on Spring.NET's transactionabstraction. This functionality is planed for an upcoming release ofSpring.NET

To allow users to implement custom aspects, complementing their useofOOPwithAOP.

Thus you can view Spring.NET AOP as either an enabling technology thatallows Spring.NET to provide declarative transaction management withoutCOM+;orusethefullpoweroftheSpring.NETAOPframeworktoimplementcustomaspects.For thosewhowouldliketohit thegroundrunningandstartexploringhowtouseSpring'sAOPfunctionality,headonovertoChapter34,AOPGuide.

13.1.1.AOPconceptsLet us begin by defining some central AOP concepts. These terms are notSpring.NET-specific. Unfortunately, AOP terminology is not particularlyintuitive.However,itwouldbeevenmoreconfusingifSpring.NETuseditsownterminology.

Aspect:Amodularizationofaconcernforwhichtheimplementationmightotherwise cut acrossmultiple objects. Transactionmanagement is a goodexample of a crosscutting concern in enterprise applications. Aspects are

Page 296: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

implementedusingSpring.NETasAdvisorsorinterceptors.

Joinpoint: Point during the execution of a program, such as a methodinvocationoraparticularexceptionbeingthrown.

Advice: Action taken by the AOP framework at a particular joinpoint.Different typesofadvice include"around," "before" and "throws" advice.Advice types are discussed below. Many AOP frameworks, includingSpring.NET, model an advice as an interceptor, maintaining a chain ofinterceptors"around"thejoinpoint.

Pointcut: A set of joinpoints specifying when an advice should fire. AnAOPframeworkmustallowdevelopers to specifypointcuts: forexample,usingregularexpressions.

Introduction: Adding methods or fields to an advised class. Spring.NETallowsyoutointroducenewinterfacestoanyadvisedobject.Forexample,you could use an introduction to make any object implement anIAuditable interface, to simplify the tracking of changes to anobject'sstate.

Targetobject:Objectcontaining the joinpoint.Also referred toasadvisedorproxiedobject.

AOP proxy: Object created by the AOP framework, including advice. InSpring.NET,anAOPproxyisadynamicproxythatusesILcodegeneratedatruntime.

Weaving:Assemblingaspectstocreateanadvisedobject.Thiscanbedoneatcompiletime(usingtheGripper-Loom.NETcompiler,forexample),oratruntime.Spring.NETperformsweavingatruntime.

Differentadvicetypesinclude:

Around advice: Advice that surrounds a joinpoint such as a methodinvocation.This is themost powerful kindof advice.Aroundadvicewillperformcustombehaviourbeforeandafterthemethodinvocation.Theyareresponsibleforchoosingwhethertoproceedtothejoinpointortoshortcutexecutingbyreturningtheirownreturnvalueorthrowinganexception.

Beforeadvice:Advicethatexecutesbeforeajoinpoint,butwhichdoesnothave the ability to prevent execution flow proceeding to the joinpoint(unlessitthrowsanexception).

Page 297: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Throws advice: Advice to be executed if a method throws an exception.Spring.NETprovidesstronglytypedthrowsadvice,soyoucanwritecodethat catches the exception (and subclasses) you're interested in, withoutneedingtocastfromException.

After returningadvice:Advice to be executed after a joinpoint completesnormally:forexample,ifamethodreturnswithoutthrowinganexception.

Spring.NETprovidesafullrangeofadvicetypes.Werecommendthatyouusethe least powerful advice type that can implement the requiredbehaviour.Forexample,ifyouneedonlytoupdateacachewiththereturnvalueofamethod,youarebetteroffimplementinganafterreturningadvicethananaroundadvice,although an around advice can accomplish the same thing. Using the mostspecificadvicetypeprovidesasimplerprogrammingmodelwith lesspotentialforerrors.Forexample,youdon'tneedtoinvoketheproceed()methodontheIMethodInvocationusedforaroundadvice,andhencecan'tfailtoinvokeit.The pointcut concept is the key to AOP, distinguishing AOP from oldertechnologies offering interception. Pointcuts enable advice to be targetedindependently of the OO hierarchy. For example, an around advice providingdeclarativetransactionmanagementcanbeappliedtoasetofmethodsspanningmultipleobjects.ThuspointcutsprovidethestructuralelementofAOP.

13.1.2.Spring.NETAOPcapabilitiesSpring.NET AOP is implemented in pure C#. There is no need for a specialcompilationprocess-allweavingisdoneatruntime.Spring.NETAOPdoesnotneed tocontrolormodify theway inwhichassembliesare loaded,nordoes itrelyonunmanagedAPIs,andisthussuitableforuseinanyCLRenvironment.Spring.NET currently supports interception of method invocations. Fieldinterceptionisnotimplemented,althoughsupportforfieldinterceptioncouldbeaddedwithoutbreakingthecoreSpring.NETAOPAPIs.Field interception arguably violates OO encapsulation. We don't believe it iswiseinapplicationdevelopment.Spring.NETprovides classes to represent pointcuts and different advice types.Spring.NETusesthetermadvisorforanobjectrepresentinganaspect,includingbothanadviceandapointcuttargetingittospecificjoinpoints.

Page 298: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Different advice types are IMethodInterceptor (from the AOPAlliance interception API); and the advice interfaces defined in theSpring.Aop namespace. All advices must implement theAopAlliance.Aop.IAdvicetaginterface.Advicessupportedoutthebox are IMethodInterceptor ; IThrowsAdvice;IBeforeAdvice; and IAfterReturningAdvice. We'll discussadvicetypesindetailbelow.Spring.NET provides a .NET translation of the Java interfaces defined by theAOP Alliance . Around advice must implement the AOP AllianceAopAlliance.Interceptr.IMethodInterceptor interface.Whilst there is wide support for the AOP Alliance in Java, Spring.NET iscurrentlytheonly .NETAOPframeworkthatmakesuseof theseinterfaces. Intheshortterm,thiswillprovideaconsistentprogrammingmodelforthosedoingdevelopmentinboth.NETandJava,andinthelongerterm,wehopetoseemore.NETprojectsadopttheAOPAllianceinterfaces.The aim of Spring.NET AOP support is not to provide a comprehensive AOPimplementation on par with the functionality available in AspectJ. However,Spring.NET AOP provides an excellent solution to most problems in .NETapplicationsthatareamenabletoAOP.Thus, it iscommon to seeSpring.NET'sAOP functionalityused inconjunctionwithaSpring.NETIoCcontainer.AOPadvice isspecifiedusingnormalobjectdefinition syntax (although this allows powerful "autoproxying" capabilities);adviceandpointcutsarethemselvesmanagedbySpring.NETIoC.

13.1.3.AOPProxiesinSpring.NETSpring.NET generates AOP proxies at runtime using classes from theSystem.Reflection.Emit namespace to create necessary IL code for the proxyclass. This results in proxies that are very efficient and do not impose anyrestrictionsontheinheritancehierarchy.Another common approach to AOP proxy implementation in .NET is to useContextBoundObject and the .NET remoting infrastructure as an interceptionmechanism.Wearenotvery fondofContextBoundObjectapproachbecause itrequiresclassesthatneedtobeproxiedtoinheritfromtheContextBoundObjecteither directly or indirectly. In our opinion this an unnecessary restriction thatinfluenceshowyoushoulddesignyourobjectmodelandalsoexcludesapplying

Page 299: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AOPto"3rdparty"classesthatarenotunderyourdirectcontrol.Context-boundproxiesarealsoanorderofmagnitudeslowerthanIL-generatedproxies,duetotheoverheadofthecontextswitchingand.NETremotinginfrastructure.Spring.NETAOPproxiesarealso"smart"-inthatbecauseproxyconfigurationis known during proxy generation, the generated proxy can be optimized toinvoke targetmethods via reflection onlywhen necessary (i.e. when there areadvicesappliedtothetargetmethod).Inallothercasesthetargetmethodwillbecalled directly, thus avoiding performance hit caused by the reflectiveinvocation.Finally,Spring.NETAOPproxieswillnever returna raw reference to a targetobject.Wheneveratargetmethodreturnsarawreferencetoatargetobject(i.e."return this;"),AOP proxywill recognizewhat happened andwill replace thereturnvaluewithareferencetoitselfinstead.ThecurrentimplementationoftheAOPproxygeneratorusesobjectcompositionto delegate calls from the proxy to a target object, similar to how youwouldimplementaclassicDecoratorpattern.Thismeans that classes thatneed tobeproxiedhaveto implementoneormoreinterfaces,whichis inouropinionnotonly a less-intruding requirement than ContextBoundObject inheritancerequirements,butalsoagoodpractice that shouldbe followedanyway for theserviceclassesthataremostcommontargetsforAOPproxies.Inafuturereleasewewillimplementproxiesusinginheritance,whichwillallowyou to proxy classes without interfaces as well and will remove some of theremaining raw reference issues that cannot be solvedusing composition-basedproxies.

Page 300: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.2.PointcutAPIinSpring.NETLet'slookathowSpring.NEThandlesthecrucialpointcutconcept.

13.2.1.ConceptsSpring.NET's pointcut model enables pointcut reuse independent of advicetypes.It'spossibletotargetdifferentadviceusingthesamepointcut.TheSpring.Aop.IPointcut interfaceis thecentralinterface,usedtotargetadvicestoparticulartypesandmethods.Thecompleteinterfaceisshownbelow:

publicinterfaceIPointcut

{

ITypeFilterTypeFilter{get;}

IMethodMatcherMethodMatcher{get;}

}

Splitting theIPointcut interface into two parts allows reuse of type andmethod matching parts, and fine-grained composition operations (such asperforminga"union"withanothermethodmatcher).TheITypeFilterinterfaceisusedtorestrictthepointcuttoagivensetoftargetclasses.IftheMatches()methodalwaysreturnstrue,alltargettypeswillbematched:

publicinterfaceITypeFilter

{

boolMatches(Typetype);

}

TheIMethodMatcherinterfaceisnormallymoreimportant.Thecompleteinterfaceisshownbelow:

publicinterfaceIMethodMatcher

{

boolIsRuntime{get;}

boolMatches(MethodInfomethod,TypetargetType);

Page 301: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

boolMatches(MethodInfomethod,TypetargetType,object[]args);

}

TheMatches(MethodInfo,Type)methodisusedtotestwhetherthispointcutwill evermatchagivenmethodona target type.ThisevaluationcanbeperformedwhenanAOPproxyiscreated,toavoidtheneedforatestoneverymethod invocation. If the2-argumentmatchesmethod returns true for agivenmethod,andtheIsRuntimepropertyfortheIMethodMatcherreturns true, the3-argumentmatchesmethodwillbe invokedoneverymethodinvocation. This enables a pointcut to look at the arguments passed to themethodinvocationimmediatelybeforethetargetadviceistoexecute.Most IMethodMatchers are static, meaning that their IsRuntimeproperty returns false. In this case, the 3-argument Matches method willneverbeinvoked.Wheneverpossible,trytomakepointcutsstatic...thisallowstheAOPframeworktocachetheresultsofpointcutevaluationwhenanAOPproxyiscreated.

13.2.2.OperationsonpointcutsSpring.NETsupportsoperationsonpointcuts:notably,unionandintersection.Unionmeansthemethodsthateitherpointcutmatches.Intersectionmeansthemethodsthatbothpointcutsmatch.Unionisusuallymoreuseful.Pointcuts can be composed using the static methods in theSpring.Aop.Support.Pointcuts class, or using theComposablePointcut class inthesamenamespace.

13.2.3.ConveniencepointcutimplementationsSpring.NETprovidesseveralconvenientpointcutimplementations.Somecanbeusedoutofthebox;othersareintendedtobesubclassedinapplication-specificpointcuts.

13.2.3.1.StaticpointcutsStatic pointcuts are based on method and target class, and cannot take intoaccount the method's arguments. Static pointcuts are sufficient--and best--for

Page 302: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

mostusages.It'spossibleforSpring.NETtoevaluateastaticpointcutonlyonce,when a method is first invoked: after that, there is no need to evaluate thepointcutagainwitheachmethodinvocation.Let'sconsidersomestaticpointcutimplementationsincludedwithSpring.NET.

13.2.3.1.1.Regularexpressionpointcuts

Oneobviouswaytospecifystaticpointcutsisusingregularexpressions.SeveralAOP frameworks besides Spring.NET make this possible. TheSpring.Aop.Support.SdkRegularExpressionMethodPointcut

class is a generic regular expression pointcut, that uses the regular expressionclassesfromthe.NETBCL.Using this class, you canprovide a list of patternStrings. If any of these is amatch,thepointcutwillevaluatetotrue(sotheresultiseffectivelytheunionofthesepointcuts.).Thematching isdoneagainst the full classnamesoyoucanuse this pointcut if you would like to apply advice to all the classes in aparticularnamespace.Theusageisshownbelow:

<objectid="settersAndAbsquatulatePointcut"

type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut,Spring.Aop"

<propertyname="patterns">

<list>

<value>.*set.*</value>

<value>.*absquatulate</value>

</list>

</property>

</object>

As a convenience, Spring provides theRegularExpressionMethodPointcutAdvisor class thatallowsus to referenceanIAdvice instanceaswellasdefining thepointcutrules (remember that an IAdvice instance can be an interceptor, beforeadvice, throws advice etc.) This simplifieswiring, as the one object serves asbothpointcutandadvisor,asshownbelow:

Page 303: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="settersAndAbsquatulateAdvisor"

type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor,Spring.Aop"

<propertyname="advice">

<reflocal="objectNameOfAopAllianceInterceptor"/>

</property>

<propertyname="patterns">

<list>

<value>.*set.*</value>

<value>.*absquatulate</value>

</list>

</property>

</object>

TheRegularExpressionMethodPointcutAdvisor class canbeusedwithanyAdvicetype.

Ifyouonlyhaveonepatternyoucanusethepropertynamepatternand specify a single value instead of using the property namepatternsandspecifyingalist.You may also specify a Regex object from theSystem.Text.RegularExpressions namespace. The built inRegexConverterclasswillperformtheconversion.SeeSection6.4,“Built-inTypeConverters” for more information on Spring's build in type converters. TheRegexobject iscreatedasanyotherobjectwithin the IoCcontainer.Usinganinner-objectdefinitionfortheRegexobjectisahandywaytokeepthedefinitionclose to the PointcutAdvisor declaration. Note that the classSdkRegularExpressionMethodPointcut has aDefaultOptionspropertytosettheregularexpressionoptionsiftheyarenotexplicitlyspecifiedintheconstructor.

13.2.3.1.2.Attributepointcuts

Pointcutscanbespecifiedbymatchinganattributetypethatisassociatedwithamethod. Advice associated with this pointcut can then read the metadataassociated with the attribute to configure itself. The classAttributeMatchMethodPointcut provides this functionality.

Page 304: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Sample usage that will match all methods that have the attributeSpring.Attributes.CacheAttributeisshownbelow.

<objectid="cachePointcut"type="Spring.Aop.Support.AttributeMatchMethodPointcut,Spring.Aop"

<propertyname="Attribute"value="Spring.Attributes.CacheAttribute,Spring.Core"

</object>

ThiscanbeusedwithaDefaultPointcutAdvisorasshownbelow

<objectid="cacheAspect"type="Spring.Aop.Support.DefaultPointcutAdvisor,Spring.Aop"

<propertyname="Pointcut">

<objecttype="Spring.Aop.Support.AttributeMatchMethodPointcut,Spring.Aop"

<propertyname="Attribute"value="Spring.Attributes.CacheAttribute,Spring.Core"

</object>

</property>

<propertyname="Advice"ref="aspNetCacheAdvice"/>

</object>

where aspNetCacheAdvice is an implementation of anIMethodInterceptor that cachesmethod return values. See the SDKdocsforSpring.Aop.Advice.CacheAdviceformoreinformationonthisparticularadvice.As a convenience the classAttributeMatchMethodPointcutAdvisor is provided todefining an attributebasedAdvisor as a somewhat shorter alternative to usingthegenericDefaultPointcutAdvisor.Anexampleisshownbelow.

<objectid="AspNetCacheAdvice"type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor,Spring.Aop"

<propertyname="advice">

<objecttype="Aspect.AspNetCacheAdvice,Aspect"/>

</property>

<propertyname="attribute"value="Framework.AspNetCacheAttribute,Framework"

</object>

13.2.3.2.DynamicPointcutsDynamicpointcutsarecostlier toevaluate thanstaticpointcuts.They take intoaccountmethodarguments, aswellas static information.Thismeans that they

Page 305: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

mustbeevaluatedwitheverymethodinvocation;theresultcannotbecached,asargumentswillvary.Themainexampleisthecontrolflowpointcut.

13.2.3.2.1.ControlFlowPointcuts

Spring.NET control flow pointcuts are conceptually similar to AspectJ cflowpointcuts, although lesspowerful. (There is currently noway to specify that apointcutexecutesbelowanotherpointcut.).Acontrol flowpointcut isdynamicbecauseitisevaluatedagainstthecurrentcallstackforeachmethodinvocation.For example, if method ClassA.A() calls ClassB.B() then the execution ofClassB.B() has occurred inClassA.A()'s control flow.A control flow pointcutallowsadvicetobeappliedtothemethodClassA.A()butonlywhencalledfromClassB.B() and not when ClassA.A() is executed from another call stack.Control flow pointcuts are specified using theSpring.Aop.Support.ControlFlowPointcutclass.

Note

Controlflowpointcutsaresignificantlymoreexpensivetoevaluateatruntimethanevenotherdynamicpointcuts.

Whenusingcontrolflowpointcutssomeattentionshouldbepaidtothefactthatat runtime the JIT compiler can inline the methods, typically for increasedperformance,butwiththeconsequencethatthemethodnolongerappearsinthecurrentcallstack.Thisisbecauseinliningtakesthecallee'sILcodeandinsertsitinto thecaller's ILcodeeffectivelyremoving themethodcall.The informationreturned from System.Diagnostics.StackTrace, used in theimplementation of ControlFlowPointcut is subject to theseoptimizationsandthereforeacontrolflowpointcutwillnotmatchifthemethodhasbeeninlined.Generallyspeaking,amethodwillbeacandidate for inliningwhen its code is'small', justafewlinesofcode(lessthan32bytesofIL).ForsomeinterestingreadingonthisprocessreadDavidNotario'sblogentries(JITOptimizationsIandJITOptimizations II). Additionally, when an assembly is compiled with a Releaseconfiguration the assembly metadata instructs the CLR to enable JIT

Page 306: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

optimizations.WhencompiledwithaDebugconfigurationtheCLRwilldisable(some?) these optimizations. Empirically, method inlining is turned off in aDebugconfiguration.The way to ensure that your control flow pointcut will not be overlookedbecause of method inlining is to apply theSystem.Runtime.CompilerServices.MethodImplAttribute

attributewith thevalueMethodImplOptions.NoInlining. In this(somewhatartificial)simpleexample,ifthecodeiscompiledinreleasemodeitwillnotmatchacontrolflowpointcutforthemethod"GetAge".

publicintGetAge(IPersonperson)

{

returnperson.GetAge();

}

However,applyingtheattributesasshownbelowwillpreventthemethodfrombeinginlinedeveninareleasebuild.

[MethodImpl(MethodImplOptions.NoInlining)]

publicintGetAge(IPersonperson)

{

returnperson.GetAge();

}

13.2.4.CustompointcutsBecausepointcutsinSpring.NETare.NETtypes,ratherthanlanguagefeatures(as in AspectJ) it is possible to declare custom pointcuts, whether static ordynamic. However, there is no support out of the box for the sophisticatedpointcutexpressionsthatcanbecodedintheAspectJsyntax.However,custompointcutsinSpring.NETcanbeasarbitrarilycomplexasanyobjectmodel.Spring.NETprovidesusefulpointcutsuperclassestohelpyoutoimplementyourownpointcuts.Because static pointcuts are the most common and generally useful pointcuttype,you'llprobablysubclassStaticMethodMatcherPointcut,asshownbelow.Thisrequiresyoutoimplementjustoneabstractmethod(althoughitispossibletooverrideothermethodstocustomizebehaviour):

Page 307: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassTestStaticPointcut:StaticMethodMatcherPointcut{

publicoverrideboolMatches(MethodInfomethod,TypetargetType){

//returntrueifcustomcriteriamatch

}

}

Page 308: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.3.AdviceAPIinSpring.NETLet'snowlookathowSpring.NETAOPhandlesadvice.

13.3.1.AdviceLifecycleSpring.NETadvicescanbesharedacrossalladvisedobjects,oruniquetoeachadvisedobject.Thiscorrespondstoper-classorper-instanceadvice.Per-classadviceisusedmostoften.Itisappropriateforgenericadvicesuchastransactionadvisors.Thesedonotdependonthestateof theproxiedobjectoraddnewstate;theymerelyactonthemethodandarguments.Per-instance advice is appropriate for introductions, to supportmixins. In thiscase,theadviceaddsstatetotheproxiedobject.It's possible to use amix of shared and per-instance advice in the sameAOPproxy.

13.3.2.AdvicetypesSpring.NETprovides several advice types out of the box, and is extensible tosupport arbitrary advice types. Let us look at the basic concepts and standardadvicetypes.

13.3.2.1.InterceptionAroundAdviceThemostfundamentaladvicetypeinSpring.NETisinterceptionaroundadvice.Spring.NET is compliant with the AOP Alliance interface for around adviceusingmethod interception.Around advice is implemented using the followinginterface:

publicinterfaceIMethodInterceptor:IInterceptor

{

objectInvoke(IMethodInvocationinvocation);

}

TheIMethodInvocationargumenttotheInvoke()methodexposesthe method being invoked; the target joinpoint; the AOP proxy; and thearguments to the method. The Invoke() method should return theinvocation'sresult:thereturnvalueofthejoinpoint.

Page 309: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AsimpleIMethodInterceptorimplementationlooksasfollows:

publicclassDebugInterceptor:IMethodInterceptor{

publicobjectInvoke(IMethodInvocationinvocation){

Console.WriteLine("Before:invocation=[{0}]",invocation);

objectrval=invocation.Proceed();

Console.WriteLine("Invocationreturned");

returnrval;

}

}

NotethecalltotheIMethodInvocation'sProceed()method.Thisproceedsdowntheinterceptorchaintowardsthejoinpoint.Mostinterceptorswillinvokethismethod, and return its return value.However, an IMethodInterceptor, likeanyaroundadvice,canreturnadifferentvalueorthrowanexceptionratherthaninvoketheProceed()method.However,youdon'twanttodothiswithoutgoodreason!

13.3.2.2.BeforeadviceA simpler advice type is a before advice. This does not need anIMethodInvocationobject,sinceitwillonlybecalledbeforeenteringthemethod.Themain advantage of a before advice is that there is no need to invoke theProceed()method, and therefore no possibility of inadvertently failing toproceeddowntheinterceptorchain.TheIMethodBeforeAdviceinterfaceisshownbelow.

publicinterfaceIMethodBeforeAdvice:IBeforeAdvice

{

voidBefore(MethodInfomethod,object[]args,objecttarget);

}

Notethereturntypeisvoid.Beforeadvicecaninsertcustombehaviourbeforethe joinpoint executes, but cannot change the return value. If a before advicethrows an exception, thiswill abort further execution of the interceptor chain.Theexceptionwillpropagatebackuptheinterceptorchain.Ifitisunchecked,or

Page 310: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

onthesignatureof the invokedmethod, itwillbepasseddirectly to theclient;otherwiseitwillbewrappedinanuncheckedexceptionbytheAOPproxy.An example of a before advice in Spring.NET,which counts allmethods thatreturnnormally:

publicclassCountingBeforeAdvice:IMethodBeforeAdvice{

privateintcount;

publicvoidBefore(MethodInfomethod,object[]args,object

++count;

}

publicintCount{

get{returncount;}

}

}

Beforeadvicecanbeusedwithanypointcut.

13.3.2.3.ThrowsadviceThrowsadviceisinvokedafterthereturnofthejoinpointifthejoinpointthrewan exception. TheSpring.Aop.IThrowsAdvice interface does notcontain any methods: it is a tag interface identifying that the implementingadvice object implements one or more typed throws advice methods. Thesethrowsadvicemethodsmustbeoftheform:

AfterThrowing([MethodInfomethod,Object[]args,Objecttarget],Exceptionsubclass)

Throws-advice methods must be named'AfterThrowing'. The returnvalue will be ignored by the Spring.NET AOP framework, so it is typicallyvoid.Withregardtothemethodarguments,onlythelastargumentisrequired.Thusthereareexactlyoneorfourarguments,dependingonwhethertheadvicemethodisinterestedinthemethod,methodargumentsandthetargetobject.Thefollowingmethodsnippetsshowexamplesofthrowsadvice.This advice will be invoked if a RemotingException is thrown(includingsubclasses):

Page 311: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassRemoteThrowsAdvice:IThrowsAdvice{

publicvoidAfterThrowing(RemotingExceptionex){

//Dosomethingwithremotingexception

}

}

ThefollowingadviceisinvokedifaSqlExceptionisthrown.Unliketheabove advice, it declares 4 arguments, so that it has access to the invokedmethod,methodargumentsandtargetobject:

publicclassSqlExceptionThrowsAdviceWithArguments:IThrowsAdvice{

publicvoidAfterThrowing(MethodInfomethod,object[]args,

//Dosomethingwillallarguments

}

}

Thefinalexample illustrateshowthese twomethodscouldbeused inasingleclass, which handles both RemotingException andSqlException.Anynumberofthrowsadvicemethodscanbecombinedinasingleclass,ascanbeseeninthefollowingexample.

publicclassCombinedThrowsAdvice:IThrowsAdvice{

publicvoidAfterThrowing(RemotingExceptionex){

//Dosomethingwithremotingexception

}

publicvoidAfterThrowing(MethodInfomethod,object[]args,

//Dosomethingwillallarguments

}

}

Finally, it is worth stating that throws advice is only applied to the actualexceptionbeingthrown.Whatdoes thismean?Well, itmeans that ifyouhavedefined some throws advice that handles RemotingExceptions, theapplicableAfterThrowingmethodwillonlybeinvokedifthetypeofthethrown exception is RemotingException... if a

Page 312: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

RemotingExceptionhasbeenthrownandsubsequentlywrappedinsideanother exception before the exception bubbles up to the throws adviceinterceptor, then the throws advice that handlesRemotingExceptionswill never be called. Consider a business method that is advised by throwsadvice that handles RemotingExceptions; if during the course of amethod invocation said business method throws a RemoteException... andsubsequentlywrapssaidRemotingExceptioninsideabusiness-specificBadConnectionException (see the code snippet below) beforethrowingtheexception,thenthethrowsadvicewillneverbeabletorespondtothe RemotingException... because all the throws advice sees is aBadConnectionException. The fact that theRemotingException is wrapped up inside theBadConnectionExceptionisimmaterial.

publicvoidBusinessMethod()

{

try

{

//dosomebusinessoperation...

}

catch(RemotingExceptionex)

{

thrownewBadConnectionException("Couldn'tconnect."

}

}

NotePleasenotethatthrowsadvicecanbeusedwithanypointcut.

13.3.2.4.AfterReturningadviceAn after returning advice in Spring.NET must implement theSpring.Aop.IAfterReturningAdviceinterface,shownbelow:

publicinterfaceIAfterReturningAdvice:IAdvice

{

voidAfterReturning(objectreturnValue,MethodBasemethod,

Page 313: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

Anafterreturningadvicehasaccesstothereturnvalue(whichitcannotmodify),invokedmethod,methodsargumentsandtarget.The following after returning advice counts all successfulmethod invocationsthathavenotthrownexceptions:

publicclassCountingAfterReturningAdvice:IAfterReturningAdvice{

privateintcount;

publicvoidAfterReturning(objectreturnValue,MethodBasem,

++count;

}

publicintCount{

get{returncount;}

}

}

Thisadvicedoesn'tchangetheexecutionpath.Ifitthrowsanexception,thiswillbethrownuptheinterceptorchaininsteadofthereturnvalue.

NotePleasenotethatafter-returningadvicecanbeusedwithanypointcut.

13.3.2.5.AdviceOrderingWhen multiple pieces of advice want to run on the same joinpoint theprecedenceisdeterminedbyhavingtheadviceimplementtheIOrderedinterfaceorbyspecifyingorderinformationonanadvisor.

13.3.2.6.IntroductionadviceSpring.NETallowsyoutoaddnewmethodsandpropertiestoanadvisedclass.This would typically be done when the functionality you wish to add is acrosscuttingconcernandwanttointroducethisfunctionalityasachangetothestaticstructureoftheclasshierarchy.Forexample,youmaywanttocastobjectsto the introduction interface in your code. Introductions are also a means toemulatemultipleinheritance.

Page 314: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Introduction advice is defined by using a normal interface declaration thatimplementsthetaginterfaceIAdvice.

NoteTheneedforimplementingthismarkerinterfacewilllikelyberemovedinfutureversions.

Asan example, consider the interfaceIAuditable that describes the lastmodifiedtimeofanobject.

publicinterfaceIAuditable:IAdvice

{

DateTimeLastModifiedDate

{

get;

set;

}

}

where

publicinterfaceIAdvice

{

}

Access to the advised object can be obtained by implementing the interfaceITargetAware

publicinterfaceITargetAware

{

IAopProxyTargetProxy

{

set;

}

}

withtheIAopProxyreferenceprovidingalayerofindirectionthroughwhichtheadvisedobjectcanbeaccessed.

Page 315: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicinterfaceIAopProxy

{

objectGetProxy();

}

Asimpleclassthatdemonstratesthisfunctionalityisshownbelow.

publicinterfaceIAuditable:IAdvice,ITargetAware

{

DateTimeLastModifiedDate

{

get;

set;

}

}

Aclassthatimplementsthisinterfaceisshownbelow.

publicclassAuditableMixin:IAuditable

{

privateDateTimedate;

privateIAopProxytargetProxy;

publicAuditableMixin()

{

date=newDateTime();

}

publicDateTimeLastModifiedDate

{

get{returndate;}

set{date=value;}

}

publicIAopProxyTargetProxy

{

set{targetProxy=value;}

}

}

Introductionadviceisnotassociatedwithapointcut,sinceitappliesattheclass

Page 316: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

andnot themethod level.Assuch, introductionsuse theirownsubclassof theinterface IAdvisor, namely IIntroductionAdvisor, to specifythetypesthattheintroductioncanbeappliedto.

publicinterfaceIIntroductionAdvisor:IAdvisor

{

ITypeFilterTypeFilter{get;}

Type[]Interfaces{get;}

voidValidateInterfaces();

}

TheTypeFilter property returns the filter that determines which targetclassesthisintroductionshouldapplyto.TheInterfacespropertyreturnstheinterfacesintroducedbythisadvisor.

TheValidateInterfaces() method is used internally to see if theintroducedinterfacescanbeimplementedbytheintroductionadvice.Spring.NET provides a default implementation of this interface (theDefaultIntroductionAdvisor class) that shouldbe sufficient forthemajorityofsituationswhenyouneedtouseintroductions.Themostsimpleimplementationofanintroductionadvisorisasubclassthatsimplypassesanewinstancethebaseconstructor.Passinganewinstanceisimportantsincewewantanewinstanceofthemixinclassedusedforeachadvisedobject.

publicclassAuditableAdvisor:DefaultIntroductionAdvisor

{

publicAuditableAdvisor():base(newAuditableMixin())

{

}

}

Otherconstructorsletyouexplicitlyspecifytheinterfacesoftheclassthatwillbeintroduced.SeetheSDKdocumentationformoredetails.We can apply this advisor Programatically, using theIAdvised.AddIntroduction(), method, or (the recommendedway)inXMLconfigurationusingtheIntroductionNamespropertyon

Page 317: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ProxyFactoryObject,whichwillbediscussedlater.UnliketheAOPimplementationintheSpringFrameworkforJava,introductionadvice in Spring.NET is not implemented as a specialized type of interceptionadvice.Theadvantageofthisapproachisthatintroductionsarenotkeptintheinterceptor chain, which allows some significant performance optimizations.Whenamethodiscalledthathasnointerceptors,adirectcallisusedinsteadofreflectionregardlessofwhetherthetargetmethodisonthetargetobjectitselforoneoftheintroductions.Thismeansthatintroducedmethodsperformthesameastargetobjectmethods,whichcouldbeusefulforaddingintroductionstofinegrainedobjects.Thedisadvantageisthatifthemixinfunctionalitywouldbenefitfromhavingaccesstothecallingstack,itisnotavailable.IntroductionswiththisfunctionalitywillbeaddressedinafutureversionofSpring.NETAOP.

Page 318: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.4.AdvisorAPIinSpring.NETInSpring.NET,anadvisor isamodularizationofanaspect.Advisors typicallyincorporatebothanadviceandapointcut.Apartfromthespecialcaseof introductions,anyadvisorcanbeusedwithanyadvice. TheSpring.Aop.Support.DefaultPointcutAdvisor class isthemost commonlyusedadvisor implementation.Forexample, it canbeusedwith a IMethodInterceptor, IBeforeAdvice orIThrowsAdviceandanypointcutdefinition.Other convenience implementations provided are:AttributeMatchMethodPointcutAdvisor shown in usagepreviously in Section 13.2.3.1.2, “Attribute pointcuts” for use with attribute basedpointcuts.RegularExpressionMethodPointcutAdvisor thatwill apply pointcuts based on the matching a regular expression to methodnames.It ispossible tomixadvisorandadvicetypes inSpring.NETinthesameAOPproxy.Forexample,youcoulduseainterceptionaroundadvice,throwsadviceand before advice in one proxy configuration: Spring.NET will automaticallycreatethenecessaryinterceptorchain.

Page 319: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.5.UsingtheProxyFactoryObjecttocreateAOPproxiesIf you're using the Spring.NET IoC container for your business objects -generallyagoodidea-youwillwanttouseoneofSpring.NET'sAOP-specificIFactoryObject implementations (remember that a factory objectintroducesalayerofindirection,enablingittocreateobjectsofadifferenttype-Section5.3.9,“Settingareferenceusingthemembersofotherobjectsandclasses.”).The basic way to create an AOP proxy in Spring.NET is to use theSpring.Aop.Framework.ProxyFactoryObject class. Thisgivescompletecontroloverorderingandapplicationofthepointcutsandadvicethatwillapplytoyourbusinessobjects.However,therearesimpleroptionsthatarepreferableifyoudon'tneedsuchcontrol.

13.5.1.BasicsThe ProxyFactoryObject, like other Spring.NETIFactoryObject implementations, introduces a level of indirection. Ifyou define a ProxyFactoryObject with name foo, what objectsreferencingfoo see is not theProxyFactoryObject instance itself,but anobject created by theProxyFactoryObject's implementationof the GetObject() method. This method will create an AOP proxywrappingatargetobject.OneofthemostimportantbenefitsofusingaProxyFactoryObjectorotherIoC-awareclassesthatcreateAOPproxies,isthatitmeansthatadviceandpointcuts can also be managed by IoC. This is a powerful feature, enablingcertain approaches that are hard to achieve with other AOP frameworks. Forexample,anadvicemay itself referenceapplicationobjects (besides the target,which should be available in any AOP framework), benefiting from all thepluggabilityprovidedbyDependencyInjection.

13.5.2.ProxyFactoryObjectPropertiesLikemostIFactoryObjectimplementationsprovidedwithSpring.NET,theProxyFactoryObjectisitselfaSpring.NETconfigurableobject.Itspropertiesareusedto:

Specifythetargetobjectthatistobeproxied.

Page 320: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Specifytheadvicethatistobeappliedtotheproxy.Some key properties are inherited from theSpring.Aop.Framework.ProxyConfig class: this class is thesuperclass for all AOP proxy factories in Spring.NET. Some of the keypropertiesinclude:

ProxyTargetType:abooleanvaluethatshouldbeset to trueif thetarget class is to be proxied directly, as opposed to just proxying theinterfacesexposedonthetargetclass.

Optimize:whethertoapplyaggressiveoptimizationtocreatedproxies.Don'tuse this settingunlessyouunderstandhow the relevantAOPproxyhandles optimization. The exact meaning of this flag will differ betweenproxy implementations and will generally result in a trade off betweenproxy creation time and runtime performance. Optimizations may beignored by certain proxy implementations and may be disabled silentlybasedonthevalueofotherpropertiessuchasExposeProxy.

IsFrozen:whetheradvicechangesshouldbedisallowedoncetheproxyfactoryhasbeenconfigured.Thedefaultisfalse.

ExposeProxy: whether the current proxy should be exposed via theAopContextsothatitcanbeaccessedbythetarget.(It'savailableviathe IMethodInvocation without the need for theAopContext.) If a target needs to obtain the proxy andExposeProxy is true, the target can use theAopContext.CurrentProxyproperty.

AopProxyFactory: the implementation ofIAopProxyFactorytousewhengeneratingaproxy.Offersawayofcustomizingwhether to use remoting proxies, IL generation or any otherproxystrategy.ThedefaultimplementationwilluseILgenerationtocreatecomposition-basedproxies.

OtherpropertiesspecifictotheProxyFactoryObjectclassinclude:

ProxyInterfaces: the array of string interface names we'reproxying.

InterceptorNames:string array ofIAdvisor, interceptor

Page 321: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

or other advice names to apply.Ordering is significant... first come, firstservedthatis.Thefirstinterceptorinthelistwillbethefirsttobeable tointerceptor the invocation (assuming it concerns a regularMethodInterceptororBeforeAdvice).Thenamesareobjectnamesinthecurrentcontainer,includingobjectnamesfromcontainerhierarchies.Youcan'tmentionobjectreferencesheresincedoing so would result in theProxyFactoryObject ignoring thesingletonsettingoftheadvise.

IntroductionNames: The names of objects in the container thatwillbeusedasintroductionstothetargetobject.Iftheobjectreferredtobynamedoesnot implement theIIntroductionAdvisor itwillbepassed to the default constructor ofDefaultIntroductionAdvisor and all of the objectsinterfaces will be added to the target object. Objects that implement theIIntroductionAdvisorinterfacewillbeusedasis,givingyouafinerlevelofcontroloverwhatinterfacesyoumaywanttoexposeandthetypesforwhichtheywillbematchedagainst.

IsSingleton:whetherornotthefactoryshouldreturnasingleproxyobject, no matter how often the GetObject() method is called.SeveralIFactoryObjectimplementationsoffersuchamethod.Thedefaultvalue istrue. Ifyouwould like tobeable toapplyadviceonaper-proxy object basis, use aIsSingleton value offalse and aIsFrozen value of false. If you want to use stateful advice--forexample, for stateful mixins--use prototype advices along with aIsSingletonvalueoffalse.

13.5.3.ProxyingInterfacesLet'slookatasimpleexampleofProxyFactoryObjectinaction.Thisexampleinvolves:

A target object that will be proxied. This is the "personTarget" objectdefinitionintheexamplebelow.

AnIAdvisorandanIInterceptorusedtoprovideadvice.

An AOP proxy object definition specifying the target object (the

Page 322: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

personTargetobject)andtheinterfacestoproxy,alongwiththeadvices toapply.

<objectid="personTarget"type="MyCompany.MyApp.Person,MyCompany"

<propertyname="name"value="Tony"/>

<propertyname="age"value="51"/>

</object>

<objectid="myCustomInterceptor"type="MyCompany.MyApp.MyCustomInterceptor,MyCompany"

<propertyname="customProperty"value="configurationstring"

</object>

<objectid="debugInterceptor"type="Spring.Aop.Advice.DebugAdvice,Spring.Aop"

</object>

<objectid="person"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="proxyInterfaces"value="MyCompany.MyApp.IPerson"

<propertyname="target"ref="personTarget"/>

<propertyname="interceptorNames">

<list>

<value>debugInterceptor</value>

<value>myCustomInterceptor</value>

</list>

</property>

</object>

NotethattheInterceptorNamespropertytakesalistofstrings:theobject names of the interceptor or advisors in the current context. Advisors,interceptors,before,afterreturningandthrowsadviceobjectscanbeused.Theorderingofadvisorsissignificant.Youmightbewonderingwhythelistdoesn'tholdobjectreferences.ThereasonforthisisthatiftheProxyFactoryObject'ssingletonpropertyissetto false, it must be able to return independent proxy instances. If any of theadvisorsisitselfaprototype,anindependentinstancewouldneedtobereturned,so it's necessary to be able to obtain an instance of the prototype from thecontext;holdingareferenceisn'tsufficient.

Page 323: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The "person" object definition above can be used in place of anIPersonimplementation,asfollows:

IPersonperson=(IPerson)factory.GetObject("person");

OtherobjectsinthesameIoCcontextcanexpressastronglytypeddependencyonit,aswithanordinary.NETobject:

<objectid="personUser"type="MyCompany.MyApp.PersonUser,MyCompany"

<propertyname="person"ref="person"/>

</object>

ThePersonUser class in this example would expose a property of typeIPerson.Asfarasit'sconcerned,theAOPproxycanbeusedtransparentlyinplaceofa"real"personimplementation.However,itstypewouldbeaproxytype. It would be possible to cast it to theIAdvised interface (discussedbelow).It's possible to conceal the distinction between target and proxy using ananonymousinlineobject,asfollows.(formoreinformationoninlineobjectsseeSection5.3.2.3,“Inlineobjects”.)OnlytheProxyFactoryObjectdefinitionisdifferent;theadviceisincludedonlyforcompleteness:

<objectid="myCustomInterceptor"type="MyCompany.MyApp.MyCustomInterceptor,MyCompany"

<propertyname="customProperty"value="configurationstring"

</object>

<objectid="debugInterceptor"type="Spring.Aop.Advice.DebugAdvice,Spring.Aop"

</object>

<objectid="person"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="proxyInterfaces"value="MyCompany.MyApp.IPerson"

<propertyname="target">

<!--Insteadofusingareferencetotarget,justuseaninlineobject-->

<objecttype="MyCompany.MyApp.Person,MyCompany">

<propertyname="name"value="Tony"/>

<propertyname="age"value="51"/>

</object>

Page 324: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</property>

<propertyname="interceptorNames">

<list>

<value>debugInterceptor</value>

<value>myCustomInterceptor</value>

</list>

</property>

</object>

Thishastheadvantagethatthere'sonlyoneobjectoftypePerson:useful ifwewanttopreventusersoftheapplicationcontextobtainingareferencetotheun-advisedobject,orneedtoavoidanyambiguitywithSpringIoCautowiring.There'salsoarguablyanadvantageinthat theProxyFactoryObjectdefinitionisself-contained. However, there are times when being able to obtain the un-advisedtargetfromthefactorymightactuallybeanadvantage:forexample,incertaintestscenarios.

13.5.1.Applyingadviceonaper-proxybasis.Let's look at an example of configuring the proxy objects retrieved fromProxyFactoryObject.

<!--createtheobjecttoreference-->

<objectid="RealObjectTarget"type="MyRealObject"

<!--createtheproxiedobjectforeveryonetouse-->

<objectid="MyObject"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="proxyInterfaces"value="MyInterface"

<propertyname="isSingleton"value="false"/>

<propertyname="targetName"value="RealObjectTarget"

</object>

If you are using a prototype as the target you must set theTargetNameproperty with the name/object id of your object and not use the propertyTargetwithareferencetothatobject.Thiswillthenallowanewproxytobecreatedaroundanewprototypetargetinstance.Consider the above Spring.Net object configuration. Notice that the

Page 325: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

IsSingletonpropertyoftheProxyFactoryObjectinstanceissetto false. This means that each proxy object will be unique. Thus, you canconfigure each proxy object with its' own individual advice(s) using thefollowingsyntax

//Willreturnun-advisedinstanceofproxyobject

MyInterfacemyProxyObject1=(MyInterface)ctx.GetObject("MyObject"

//myProxyObject1instancenowhasanadviceattachedtoit.

IAdvisedadvised=(IAdvised)myProxyObject1;

advised.AddAdvice(newDebugAdvice());

//Willreturnanew,un-advisedinstanceofproxyobject

MyInterfacemyProxyObject2=(MyInterface)ctx.GetObject("MyObject"

13.5.4.ProxyingClassesWhatifyouneedtoproxyaclass,ratherthanoneormoreinterfaces?Imagine that inour example above, therewasnoIPerson interface, ratherweneededtoadviseaclasscalledPersonthatdidn'timplementanybusinessinterface. In this case theProxyFactoryObject will proxy all publicvirtualmethods andproperties if no interfaces are explicitly specifiedor if nointerfaces are found to be present on the target object. One can configureSpring.NET to force the use of class proxies, rather than interface proxies, bysetting the ProxyTargetType property on theProxyFactoryObjectabovetotrue.Class proxyingworks by generating a subclass of the target class at runtime.Spring.NETconfigures this generated subclass to delegatemethod calls to theoriginaltarget:thesubclassisusedtoimplementtheDecoratorpattern,weavingintheadvice.Class proxying should generally be transparent to users.However, there is animportantissuetoconsider:Non-virtualmethodscan'tbeadvised,astheycan'tbeoverridden.Thismaybealimitingfactorwhenusingexistingcodeasithasbeencommonpracticenottodeclaremethodsasvirtualbydefault.

13.5.5.Conciseproxydefinitions

Page 326: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Especiallywhendefining transactional proxies, if you do notmake use of thetransaction namespace, youmay end up withmany similar proxy definitions.The use of parent and child object definitions, along with inner objectdefinitions,canresultinmuchcleanerandmoreconciseproxydefinitions.Firstaparent,template,objectdefinitioniscreatedfortheproxy:

<objectid="txProxyTemplate"abstract="true"

type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject,Spring.Data"

<propertyname="PlatformTransactionManager"ref="adoTransactionManager"

<propertyname="TransactionAttributes">

<name-values>

<addkey="*"value="PROPAGATION_REQUIRED"/>

</name-values>

</property>

</object>

Thiswillneverbeinstantiateditself,somayactuallybeincomplete.Theneachproxywhichneedstobecreatedisjustachildobjectdefinition,whichwrapsthetargetof theproxyasan innerobject definition, since the targetwill neverbeusedonitsownanyway.

<objectname="testObjectManager"parent="txProxyTemplate">

<propertyname="Target">

<objecttype="Spring.Data.TestObjectManager,Spring.Data.Integration.Tests"

<propertyname="TestObjectDao"ref="testObjectDao"

</object>

</property>

</object>

Itisofcoursepossibletooverridepropertiesfromtheparenttemplate,suchasinthiscase,thetransactionpropagationsettings:

<objectname="testObjectManager"parent="txProxyTemplate">

<propertyname="Target">

<objecttype="Spring.Data.TestObjectManager,Spring.Data.Integration.Tests"

<propertyname="TestObjectDao"ref="testObjectDao"

</object>

</property>

<propertyname="TransactionAttributes">

Page 327: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<name-values>

<addkey="Save*"value="PROPAGATION_REQUIRED"

<addkey="Delete*"value="PROPAGATION_REQUIRED"

<addkey="Find*"value="PROPAGATION_REQUIRED,readonly"

</name-values>

</property>

</object>

Note that in the example above, we have explicitly marked the parent objectdefinitionasabstractbyusingtheabstractattribute,asdescribedpreviously,sothatitmaynotactuallyeverbeinstantiated.Applicationcontexts(butnotsimpleobject factories) will by default pre-instantiate all singletons. It is thereforeimportant (at least for singleton object) that if you have a (parent) objectdefinition which you intend to use only as a template, and this definitionspecifies a class, you must make sure to set the abstract attribute to true,otherwisetheapplicationcontextwillactuallytrytopre-instantiateit.

Page 328: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.6.ProxyingmechanismsSpringcreatesAOPproxiesbuiltatruntimethroughtheuseoftheTypeBuilderAPI.Twotypesofproxiescanbecreated,compositionbasedorinheritancebased.Ifthe target object implements at least one interface then a composition basedproxywillbecreated,otherwiseaninheritancebasedproxywillbecreated.Thecompositionbasedproxyisimplementedbycreatingatypethatimplementsall the interfaces specified on the target object. The actual class name of thisdynamic type is 'GUID' like. A private field holds the target object and thedynamic type implementation will first execute any advice before or aftermakingthetargetobjectmethodcallonthetargetobject.The inheritance based mechanism creates a dynamic type where that inheritsfromthetargettype.Thisletsyoudowncasttothetargettypeifneeded.Pleasenotethatinbothcasesatargetmethodimplementationthatcallsothermethodsonthetargetobjectwillnotbeadvised.Toforceinheritancebasedproxiesyoushould either set the ProxyTargetType to true property of aProxyFactoryorset theXMLnamespaceelementproxy-target-type=truewhenusinganAOPschemabasedconfiguration.

Note

Animportantalternativeapproachtoinheritancebasedproxiesisdisucssedinthenextsection.

In .NET2.0youcandefine theassembly levelattribute, InternalsVisibleTo, toallowaccessofinternalinterfaces/classestospecified'friend'assemblies.Ifyouneed to create anAOP proxy on an internal class/interface add the followingcode, [assembly: InternalsVisibleTo("Spring.Proxy")] and [assembly:InternalsVisibleTo("Spring.DynamicReflection")]toyourtoAssemblyInfofile.

13.6.1.InheritanceBasedAopConfigurerThere is an important limitation in the inheritance based proxy as describedabove,allmethodsthatmanipulatethestateoftheobjectshouldbedeclaredasvirtual.Otherwise somemethod invocations get directed to the private 'target'fieldmember and others to the base class.Winform object are an example ofcasewherethisapproachdoesnotapply.Toaddressthislimitation,anewpost-

Page 329: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

processingmechanismwas introduced in version 1.2 that creates a proxy typewithout the private 'target' field. Interception advice is added directly in themethodbodybeforeinvokingthebaseclassmethod.Tousethisnewinheritancebasedproxydescribedinthenoteabove,declareaninstance of the InheritanceBasedAopConfigurer, andIObjectFactoryPostProcessor,inyoruconfiguraitonfile.Hereisanexample.

<objecttype="Spring.Aop.Framework.AutoProxy.InheritanceBasedAopConfigurer,Spring.Aop"

<propertyname="ObjectNames">

<list>

<value>Form*</value>

<value>Control*</value>

</list>

</property>

<propertyname="InterceptorNames">

<list>

<value>debugInterceptor</value>

</list>

</property>

</object>

<objectid="debugInterceptor"type="AopPlay.DebugInterceptor,AopPlay"

Thisconfiguraitonstyleissimilartotheautoproxybynameapproachdescribedhereandisparticuarlyappropriatewhenyouwant toapplyadvice toWinFormclasses.

Page 330: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.7. Creating AOP Proxies Programatically with theProxyFactoryIt'seasytocreateAOPproxiesProgramaticallyusingSpring.NET.ThisenablesyoutouseSpring.NETAOPwithoutdependencyonSpring.NETIoC.The following listing shows creation of a proxy for a target object, with oneinterceptorandoneadvisor.Theinterfacesimplementedbythetargetobjectwillautomaticallybeproxied:

ProxyFactoryfactory=newProxyFactory(myBusinessInterfaceImpl);

factory.AddAdvice(myMethodInterceptor);

factory.AddAdvisor(myAdvisor);

IBusinessInterfacetb=(IBusinessInterface)factory.GetProxy();

The first step is to construct an object of typeSpring.Aop.Framework.ProxyFactory. You can create thiswith a target object, as in the above example, or specify the interfaces to beproxiedinanalternateconstructor.You can add interceptors or advisors, andmanipulate them for the life of theProxyFactory.

There are also convenience methods on ProxyFactory (inherited fromAdvisedSupport)allowingyoutoaddotheradvicetypessuchasbeforeand throws advice. AdvisedSupport is the superclass of bothProxyFactoryandProxyFactoryObject.

NoteIntegratingAOPproxycreationwiththeIoCframeworkisbestpracticeinmostapplications.Werecommendthatyouexternalizeconfigurationfrom.NETcodewithAOP,asingeneral.

Page 331: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.8.ManipulatingAdvisedObjectsHowever you create AOP proxies, you can manipulate them using theSpring.Aop.Framework.IAdvisedinterface.AnyAOPproxycanbecasttothisinterface,whateverotherinterfacesit implements.Thisinterfaceincludesthefollowingmethodsandproperties:

publicinterfaceIAdvised

{

IAdvisor[]Advisors{ get;}

IIntroductionAdvisor[]Introductions{get;}

voidAddInterceptor(IInterceptorinterceptor);

voidAddInterceptor(intpos,IInterceptorinterceptor);

voidAddAdvisor(IAdvisoradvisor);

voidAddAdvisor(intpos,IAdvisoradvisor);

voidAddIntroduction(IIntroductionAdvisoradvisor);

voidAddIntroduction(intpos,IIntroductionAdvisoradvisor);

intIndexOf(IAdvisoradvisor);

intIndexOf(IIntroductionAdvisoradvisor);

boolRemoveAdvisor(IAdvisoradvisor);

voidRemoveAdvisor(intindex);

boolRemoveInterceptor(IInterceptorinterceptor);

boolRemoveIntroduction(IIntroductionAdvisoradvisor);

voidRemoveIntroduction(intindex);

voidReplaceIntroduction(intindex,IIntroductionAdvisoradvisor);

Page 332: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

boolReplaceAdvisor(IAdvisora,IAdvisorb);

}

The Advisors property will return an IAdvisor for every advisor,interceptororotheradvicetypethathasbeenaddedtothefactory.IfyouaddedanIAdvisor, the returnedadvisorat this indexwillbe theobject thatyouadded. Ifyouaddedan interceptororotheradvice type,Spring.NETwillhavewrapped this in an advisorwith aIPointcut that always returnstrue.Thus if you added anIMethodInterceptor, the advisor returned forthis index will be a DefaultPointcutAdvisor returning yourIMethodInterceptorandanIPointcutthatmatchesalltypesandmethods.TheAddAdvisor()methodscanbeusedtoaddanyIAdvisor.UsuallythiswillbethegenericDefaultPointcutAdvisor,whichcanbeusedwithanyadviceorpointcut(butnotforintroduction).Bydefault, it'spossible toaddor removeadvisorsor interceptorsevenonce aproxy has been created. The only restriction is that it's impossible to add orremove an introduction advisor, as existing proxies from the factory will notshow the interface change. (You can obtain a new proxy from the factory toavoidthisproblem.)It'squestionablewhetherit'sadvisable(nopunintended)tomodifyadviceonabusiness object in production, although there are no doubt legitimate usagecases.However, it can be very useful in development: for example, in tests. Ihavesometimesfounditveryusefultobeabletoaddtestcodeintheformofaninterceptor or other advice, getting inside amethod invocation Iwant to test.(Forexample,theadvicecanget insidea transactioncreated for thatmethod:forexample,torunSQLtocheckthatadatabasewascorrectlyupdated,beforemarkingthetransactionforrollback.)Dependingonhowyoucreatedtheproxy,youcanusuallysetaFrozenflag,inwhichcase theIAdvisedIsFrozenpropertywill returntrue,andany attempts to modify advice through addition or removal will result in anAopConfigException. The ability to freeze the state of an advisedobjectisusefulinsomecases:Forexample,topreventcallingcoderemovingasecurityinterceptor.

Page 333: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.9.Usingthe"autoproxy"facilitySo far we've considered explicit creation of AOP proxies using aProxyFactoryObject or similar factory objects. For applications thatwouldlikecreatemanyAOPproxies,sayacrossalltheclassesinaservicelayer,thisapproachcanleadtoalengthyconfigurationfile.Tosimplifythecreationofmany AOP proxies Spring provides "autoproxy" capabilities that willautomatically proxy object definitions based on higher level criteria that willgrouptogethermultipleobjectsascandidatestobeproxied.ThisfunctionalityisbuiltonSpring"objectpost-processor"infrastructure,whichenables modification of any object definition as the container loads. Refer toSection5.9.1,“CustomizingobjectswithIObjectPostProcessors”forgeneralinformationonobjectpost-processors.In thismodel, you set up some special object definitions in yourXML objectdefinitionfileconfiguringtheautoproxyinfrastructure.Thisallowsyoujusttodeclare the targets eligible for autoproxying: you don't need to useProxyFactoryObject.

Using an autoproxy creator that refers to specific objects in the currentcontext.

A special case of autoproxy creation that deserves to be consideredseparately;autoproxycreationdrivenbysource-levelattributes.

Autoproxyingingeneralhastheadvantageofmakingitimpossibleforcallersordependencies to obtain an un-advised object. CallingGetObject("MyBusinessObject1")onanApplicationContextwillreturnanAOPproxy,notthetargetbusinessobject.The"inlineobject"idiomshownearlierinSection13.5.3,“ProxyingInterfaces”alsooffersthisbenefit.)

13.9.1.AutoproxyobjectdefinitionsThe namespace Spring.Aop.Framework.AutoProxy providesgeneric autoproxy infrastructure, should you choose to write your ownautoproxy implementations, aswell as severalout-of-the-box implementations.Twoimplementationsareprovided,ObjectNameAutoProxyCreatorandDefaultAdvisorAutoProxyCreator.These are discussed inthefollowingsections.

Page 334: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.9.1.1.ObjectNameAutoProxyCreatorThe ObjectNameAutoProxyCreator automatically creates AOPproxiesforobjectwithnamesmatchingliteralvaluesorwildcards.Thepatternmatching expressions supported are of the form "*name", "name*", and"*name*"andexactnamematching, i.e."name".Thefollowingsimpleclassesareusedtodemonstratethisautoproxyfunctionality.

publicenumLanguage

{

English=1,

Portuguese=2,

Italian=3

}

publicinterfaceIHelloWorldSpeaker

{

voidSayHello();

}

publicclassHelloWorldSpeaker:IHelloWorldSpeaker

{

privateLanguagelanguage;

publicLanguageLanguage

{

set{language=value;}

get{returnlanguage;}

}

publicvoidSayHello()

{

switch(language)

{

caseLanguage.English:

Console.WriteLine("HelloWorld!");

break;

caseLanguage.Portuguese:

Console.WriteLine("OiMundo!");

Page 335: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

break;

caseLanguage.Italian:

Console.WriteLine("CiaoMondo!");

break;

}

}

}

publicclassDebugInterceptor:IMethodInterceptor

{

publicobjectInvoke(IMethodInvocationinvocation)

{

Console.WriteLine("Before:"+invocation.Method.ToString());

objectrval=invocation.Proceed();

Console.WriteLine("After:"+invocation.Method.ToString());

returnrval;

}

}

ThefollowingXMLisusedtoautomaticallycreateanAOPproxyandapplyaDebug interceptor to object definitions whose names match "English*" and"PortugueseSpeaker".

<objectid="ProxyCreator"type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator,Spring.Aop"

<propertyname="ObjectNames">

<list>

<value>English*</value>

<value>PortugeseSpeaker</value>

</list>

</property>

<propertyname="InterceptorNames">

<list>

<value>debugInterceptor</value>

</list>

</property>

</object>

<objectid="debugInterceptor"type="AopPlay.DebugInterceptor,AopPlay"

<objectid="EnglishSpeakerOne"type="AopPlay.HelloWorldSpeaker,AopPlay"

Page 336: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<propertyname="Language"value="English"/>

</object>

<objectid="EnglishSpeakerTwo"type="AopPlay.HelloWorldSpeaker,AopPlay"

<propertyname="Language"value="English"/>

</object>

<objectid="PortugeseSpeaker"type="AopPlay.HelloWorldSpeaker,AopPlay"

<propertyname="Language"value="Portuguese"/>

</object>

<objectid="ItalianSpeakerOne"type="AopPlay.HelloWorldSpeaker,AopPlay"

<propertyname="Language"value="Italian"/>

</object>

AswithProxyFactoryObject, there is an InterceptorNames propertyratherthanalistofinterceptors,toallowcorrectbehaviorforprototypeadvisors.Named"interceptors"canbeadvisorsoranyadvicetype.Thesameadvicewillbeappliedtoallmatchingobjects.Notethatifadvisorsareused(ratherthantheinterceptorintheaboveexample),thepointcutsmayapplydifferentlytodifferentobjects.RunningthefollowingsimpleprogramdemonstratestheapplicationoftheAOPinterceptor.

IApplicationContextctx=ContextRegistry.GetContext();

IDictionaryspeakerDictionary=ctx.GetObjectsOfType(typeof(IHelloWorldSpeaker));

foreach(DictionaryEntryentryinspeakerDictionary)

{

stringname=(string)entry.Key;

IHelloWorldSpeakerworldSpeaker=(IHelloWorldSpeaker)entry.Value;

Console.Write(name+"says;");

worldSpeaker.SayHello();

}

Theoutputisshownbelow

ItalianSpeakerOnesays;CiaoMondo!

EnglishSpeakerTwosays;Before:VoidSayHello()

HelloWorld!

After:VoidSayHello()

Page 337: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PortugeseSpeakersays;Before:VoidSayHello()

OiMundo!

After:VoidSayHello()

EnglishSpeakerOnesays;Before:VoidSayHello()

HelloWorld!

After:VoidSayHello()

13.9.1.2.DefaultAdvisorAutoProxyCreatorA more general and extremely powerful auto proxy creator isDefaultAdvisorAutoProxyCreator. This will automaticallyapply eligible advisors in the current application context, without the need toinclude specific object names in the autoproxy advisor's object definition. ItoffersthesamemeritofconsistentconfigurationandavoidanceofduplicationasObjectNameAutoProxyCreator.Usingthismechanisminvolves:

Specifying a DefaultAdvisorAutoProxyCreator objectdefinition

SpecifyinganynumberofAdvisors in the sameor related contexts.Notethat thesemustbeAdvisors,not just interceptorsorotheradvices.This isnecessary because there must be a pointcut to evaluate, to check theeligibilityofeachadvicetocandidateobjectdefinitions.

The DefaultAdvisorAutoProxyCreator will automaticallyevaluate the pointcut contained in each advisor, to seewhat (if any) advice itshouldapplytoeachobjectdefinedintheapplicationcontext.Thismeans that any number of advisors can be applied automatically to eachbusinessobject. Ifnopointcut inanyof theadvisorsmatchesanymethod inabusinessobject,theobjectwillnotbeproxied.The DefaultAdvisorAutoProxyCreator is very useful if youwanttoapplythesameadviceconsistentlytomanybusinessobjects.Once theinfrastructuredefinitionsareinplace,youcansimplyaddnewbusinessobjectswithoutincludingspecificproxyconfiguration.Youcanalsodropinadditionalaspects very easily--for example, tracing or performance monitoring aspects--withminimalchangetoconfiguration.The following example demonstrates the use of

Page 338: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

DefaultAdvisorAutoProxyCreator. Expanding on the previousexamplecodeused todemonstrateObjectNameAutoProxyCreatorwewilladdanewclass,SpeakerDao,thatactsasaDataAccessObjecttofindandstoreIHelloWorldSpeakerobjects.

publicinterfaceISpeakerDao

{

IListFindAll();

IHelloWorldSpeakerSave(IHelloWorldSpeakerspeaker);

}

publicclassSpeakerDao:ISpeakerDao

{

publicSystem.Collections.IListFindAll()

{

Console.WriteLine("Findingspeakers...");

//justademo...faketheretrieval.

Thread.Sleep(10000);

HelloWorldSpeakerspeaker=newHelloWorldSpeaker();

speaker.Language=Language.Portuguese;

IListlist=newArrayList();

list.Add(speaker);

returnlist;

}

publicIHelloWorldSpeakerSave(IHelloWorldSpeakerspeaker)

{

Console.WriteLine("Savingspeaker...");

//justademo...notreallysaving...

returnspeaker;

}

}

The XML configuration specifies two Advisors, that is, thecombinationofadvice(thebehaviortoadd)andapointcut(wherethebehavior should be applied). ARegularExpressionMethodPointcutAdvisor is used as a

Page 339: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

convenience to specify the pointcut as a regular expression thatmatchesmethodsnames.Otherpointcutsofyourowncreationcouldbe used, inwhich case aDefaultPointcutAdvisorwould beusedtodefinetheAdvisor.Theobjectdefinitionsfor theseadvisors,advice,andSpeakerDaoobjectareshownbelow

<objectid="SpeachAdvisor"type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor,Spring.Aop"

<propertyname="advice"ref="debugInterceptor"/>

<propertyname="patterns">

<list>

<value>.*Say.*</value>

</list>

</property>

</object>

<objectid="AdoAdvisor"type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor,Spring.Aop"

<propertyname="advice"ref="timingInterceptor"/>

<propertyname="patterns">

<list>

<value>.*Find.*</value>

</list>

</property>

</object>

//Advice

<objectid="debugInterceptor"type="AopPlay.DebugInterceptor,AopPlay"

<objectid="timingInterceptor"type="AopPlay.TimingInterceptor,AopPlay"

//SpeakerDAOObject-has'FindAll'Method.

<objectid="speakerDao"type="AopPlay.SpeakerDao,AopPlay"/>

//HelloWorldSpeakerobjectsaspreviouslylisted.

AddinganinstanceofDefaultAdvisorAutoProxyCreatortothe

Page 340: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

configurationfile

<objectid="ProxyCreator"type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator,Spring.Aop"

willapplythedebuginterceptoronallobjectsinthecontextthathaveamethodthat contains the text "Say" and apply the timing interceptor on objects in thecontextthathaveamethodthatcontainsthetext"Find".Runningthefollowingcode demonstrates this behavior. Note that the "Save"method of SpeakerDaodoesnothaveanyadviceappliedtoit.

IApplicationContextctx=ContextRegistry.GetContext();

IDictionaryspeakerDictionary=ctx.GetObjectsOfType(typeof(IHelloWorldSpeaker));

foreach(DictionaryEntryentryinspeakerDictionary)

{

stringname=(string)entry.Key;

IHelloWorldSpeakerworldSpeaker=(IHelloWorldSpeaker)entry.Value;

Console.Write(name+"says;");

worldSpeaker.SayHello();

}

ISpeakerDaodao=(ISpeakerDao)ctx.GetObject("speakerDao");

IListspeakerList=dao.FindAll();

IHelloWorldSpeakerspeaker=dao.Save(newHelloWorldSpeaker());

Thisproducesthefollowingoutput

ItalianSpeakerOnesays;Before:VoidSayHello()

CiaoMondo!

After:VoidSayHello()

EnglishSpeakerTwosays;Before:VoidSayHello()

HelloWorld!

After:VoidSayHello()

PortugeseSpeakersays;Before:VoidSayHello()

OiMundo!

After:VoidSayHello()

EnglishSpeakerOnesays;Before:VoidSayHello()

HelloWorld!

After:VoidSayHello()

Findingspeakers...

Elapsedtime=00:00:10.0154745

Savingspeaker...

Page 341: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The DefaultAdvisorAutoProxyCreator offers support for filtering (using anamingconventionso thatonlycertainadvisorsareevaluated,allowinguseofmultiple,differentlyconfigured,AdvisorAutoProxyCreatorsinthesamefactory)and ordering. Advisors can implement the Spring.Core.IOrderedinterfacetoensurecorrectorderingifthisisanissue.Thedefaultisunordered.

13.9.1.3.PointcutFilteringAutoProxyCreatorAnAutoProxyCreator that identified objects to proxy bymatching a specifiedIPointcut.

13.9.1.4.TypeNameAutoProxyCreatorAn AutoProxyCreator that identifies objects to proxy by matching theirType.FullNameagainstalistofpatterns.

13.9.1.5.AttributeAutoProxyCreatorAn AutoProxyCreator, that identifies objects to be proxied by checking anySystem.Attributedefinedonagiventypeandthattypesinterfaces.

13.9.1.6.AbstractFilteringAutoProxyCreatorThebaseclassforAutoProxyCreatorimplementationsthatmarkobjectseligibleforproxyingbasedonarbitrarycriteria.

13.9.1.7.AbstractAutoProxyCreatorThisisthesuperclassofDefaultAdvisorAutoProxyCreator.Youcancreateyourown autoproxy creators by subclassing this class, in the unlikely event thatadvisor definitions offer insufficient customization to the behavior of theframeworkDefaultAdvisorAutoProxyCreator.

13.9.2.Usingattribute-drivenauto-proxyingA particularly important type of autoproxying is driven by attributes. Theprogramming model is similar to using Enterprise Services withServicedComponents.In thiscase,youuse theDefaultAdvisorAutoProxyCreator, incombinationwithAdvisors that understand attributes. TheAdvisor pointcut isidentified by the presence of .NET attribute in the source code and it is

Page 342: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

configured via the data and/or methods of the attribute. This is a powerfulalternative to identifyingtheadvisorpointcutandadviceconfiguration throughtraditional property configuration, either programmatic or throughXMLbasedconfiguration.Several of the aspect provided with Spring use attribute driven autoproxying.ThemostprominentexampleisTransactionsupport.

Page 343: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.10.UsingAOPNamespaceTheAOPnamespaceallowsyoutodefineanadvisor, i.epointcut+1pieceofadvice, in a more declarative manner. Under the covers theDefaultAdvisorAutoProxyCreatorisbeingused.Hereisanexample,

<objectsxmlns="http://www.springframework.net"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.net/aop"

<aop:config>

<aop:advisorid="getDescriptionAdvisor"pointcut-ref

</aop:config>

<objectid="getDescriptionCalls"

type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut,Spring.Aop"

<propertyname="patterns">

<list>

<value>.*GetDescription.*</value>

</list>

</property>

</object>

<objectid="getDescriptionCounter"type="Spring.Aop.Framework.CountingBeforeAdvice,Spring.Aop.Tests"

<objectname="testObject"type="Spring.Objects.TestObject,Spring.Core.Tests"

</objects>

Inthisexample, theTestObject,whichimplementstheinterfaceITestObject, ishavingAOPadviceappliedtoit.ThemethodGetDescription()isspecifiedasaregular expression pointcut. The aop:config tag and subsequent child tag,aop:advisor,bringstogetherthepointcutwiththeadvice.InordertohaveSpring.NETrecognisetheaopnamespace,youneedtodeclarethe namespace parser in the main Spring.NET configuration section. Forconvenience this is shown below. Please refer to the section titled context

Page 344: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

configurationformoreextensiveinformation..

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Aop.Config.AopNamespaceParser,Spring.Aop"

</parsers>

<context>

<resourceuri="config://spring/objects"/>

</context>

<objectsxmlns="http://www.springframework.net">

...

</objects>

</spring>

</configuration>

Page 345: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.11.UsingTargetSourcesSpring.NET offers the concept of a TargetSource, expressed in theSpring.Aop.ITargetSource interface.This interfaceisresponsiblefor returning the "target object" implementing the joinpoint. TheTargetSourceimplementationisaskedforatargetinstanceeachtimetheAOPproxyhandlesamethodinvocation.Developers usingSpring.NETAOPdon't normally need towork directlywithTargetSources, but this provides a powerfulmeans of supporting pooling, hotswappableandothersophisticatedtargets.Forexample,apoolingTargetSourcecanreturnadifferenttargetinstanceforeachinvocation,usingapooltomanageinstances.IfyoudonotspecifyaTargetSource,adefaultimplementationisusedthatwrapsa local object. The same target is returned for each invocation (as youwouldexpect).Let'slookatthestandardtargetsourcesprovidedwithSpring.NET,andhowyoucanusethem.When using a custom target source, your target will usually need to be aprototype rather than a singleton object definition. This allows Spring.NET tocreateanewtargetinstancewhenrequired.

13.11.1.HotswappabletargetsourcesTheorg.Spring.NETframework.aop.target.HotSwappableTargetSource

existstoallowthetargetofanAOPproxytobeswitchedwhileallowingcallerstokeeptheirreferencestoit.Changing the target source's target takes effect immediately. TheHotSwappableTargetSourceisthreadsafe.

You can change the target via the swap() method onHotSwappableTargetSourceasfollows:

HotSwappableTargetSourceswapper=

(HotSwappableTargetSource)objectFactory.GetObject("swapper"

objectoldTarget=swapper.swap(newTarget);

Page 346: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheXMLdefinitionsrequiredlookasfollows:

<objectid="initialTarget"type="MyCompany.OldTarget,MyCompany"

</object>

<objectid="swapper"

type="Spring.Aop.Target.HotSwappableTargetSource,Spring.Aop"

<constructor-arg><reflocal="initialTarget"/></constructor-arg>

</object>

<objectid="swappable"

type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

>

<propertyname="targetSource">

<reflocal="swapper"/>

</property>

</object>

The aboveswap() call changes the target of the swappable object. Clientswho hold a reference to that object will be unaware of the change, but willimmediatelystarthittingthenewtarget.Although this example doesn't add any advice--and it's not necessary to addadvicetouseaTargetSource--ofcourseanyTargetSourcecanbeusedinconjunctionwitharbitraryadvice.

13.11.2.PoolingtargetsourcesUsingapoolingtargetsourceprovidesaprogrammingmodelinwhichapoolofidenticalinstancesismaintained,withmethodinvocationsgoingtofreeobjectsinthepool.A crucial difference between Spring.NET pooling and pooling in .NETEnterprise Services pooling is that Spring.NET pooling can be applied to anyPONO.(Plainold.NETobject).AswithSpring.NETingeneral,thisservicecanbeappliedinanon-invasiveway.Spring.NET provides out-of-the-box support using a pooling implementationbasedon JakartaCommonsPool1.1,whichprovidesa fairly efficient poolingimplementation. It's also possible to subclassSpring.Aop.Target.AbstractPoolingTargetSource tosupportanyotherpoolingAPI.

Page 347: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Sampleconfigurationisshownbelow:

<objectid="businessObjectTarget"type="MyCompany.MyBusinessObject,MyCompany"

...propertiesomitted

</object>

<objectid="poolTargetSource"type="Spring.Aop.Target.SimplePoolTargetSource,Spring.Aop"

<propertyname="targetObjectName"value="businessObjectTarget"

<propertyname="maxSize"value="25"/>

</object>

<objectid="businessObject"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="targetSource"ref="poolTargetSource"/>

<propertyname="interceptorNames"value="myInterceptor"/>

</object>

Note that the target object--"businessObjectTarget" in the example--must be aprototype. This allows thePoolingTargetSource implementation tocreatenewinstancesof the target togrow thepoolasnecessary.See theSDKdocumentation for AbstractPoolingTargetSource and theconcretesubclassyouwishtouseforinformationaboutit'sproperties:maxSizeisthemostbasic,andalwaysguaranteedtobepresent.Inthiscase,"myInterceptor"isthenameofaninterceptorthatwouldneedtobedefined in the same IoC context. However, it isn't necessary to specifyinterceptorstousepooling.Ifyouwantonlypooling,andnootheradvice,don'tsettheinterceptorNamespropertyatall.It'spossibletoconfigureSpring.NETsoastobeabletocastanypooledobjecttothe Spring.Aop.Target.PoolingConfig interface, whichexposesinformationabouttheconfigurationandcurrentsizeofthepoolthroughanintroduction.You'llneedtodefineanadvisorlikethis:

<objectid="poolConfigAdvisor"

type="Spring.Object.Factory.Config.MethodInvokingFactoryObject,Spring.Aop"

<propertyname="target"ref="poolTargetSource"/>

<propertyname="targetMethod"value="getPoolingConfigMixin"

</object>

This advisor is obtained by calling a convenience method on the

Page 348: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AbstractPoolingTargetSource class, hence the use ofMethodInvokingFactoryObject. This advisor's name('poolConfigAdvisor'here)mustbe in the listof interceptornamesintheProxyFactoryObjectexposingthepooledobject.Thecastwilllookasfollows:

PoolingConfigconf=(PoolingConfig)objectFactory.GetObject(

Console.WriteLine("Maxpoolsizeis"+conf.getMaxSize());

Pooling stateless service objects is not usually necessary. We don't believe itshouldbethedefaultchoice,asmoststatelessobjectsarenaturallythreadsafe,andinstancepoolingisproblematicifresourcesarecached.Simpler pooling is available using autoproxying. It's possible to set theTargetSourcesusedbyanyautoproxycreator.

13.11.3.PrototypetargetsourcesSetting up a "prototype" target source is similar to a poolingTargetSource. Inthis case, a new instance of the target will be created on every methodinvocation.Althoughthecostofcreatinganewobjectmaynotbehigh,thecostof wiring up the new object (satisfying its IoC dependencies) may be moreexpensive.Thusyoushouldn'tusethisapproachwithoutverygoodreason.Todo this, you couldmodify thepoolTargetSource definition shownaboveasfollows.(thenameofthedefinitionhasalsobeenchanged,forclarity.)

<objectid="prototypeTargetSource"

type="Spring.Aop.Target.PrototypeTargetSource,Spring.Aop"

<propertyname="targetObjectName"value="businessObject"

</object>

Thereisonlyoneproperty:thenameofthetargetobject.Inheritanceisusedinthe TargetSource implementations to ensure consistent naming. As with thepoolingtargetsource,thetargetobjectmustbeaprototypeobjectdefinition,thesingletonpropertyofthetargetshouldbesettofalse.

13.11.4.ThreadLocaltargetsourcesThreadLocal target sources are useful if you need an object to be created for

Page 349: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

each incoming request (per thread that is). The concept of a ThreadLocalprovidesafacilitytotransparentlystoreresourcealongsideathread.SettingupaThreadLocalTargetSourceisprettymuchthesameaswasexplainedfortheothertypesoftargetsource:

<objectid="threadlocalTargetSource"

type="Spring.Aop.Target.ThreadLocalTargetSource,Spring.Aop"

<propertyname="targetObjectName"value="businessObject"

</object>

Page 350: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.12.DefiningnewAdvicetypesSpring.NET AOP is designed to be extensible. While the interceptionimplementation strategy is presently used internally, it is possible to supportarbitrary advice types in addition to interception around, before, throws, andafterreturningadvice,whicharesupportedoutofthebox.TheSpring.Aop.Framework.AdapterpackageisanSPI(ServiceProviderInterface)packageallowingsupportfornewcustomadvicetypestobeaddedwithout changing the core framework.The only constraint on a customAdvice type is that it must implement theAopAlliance.Aop.IAdvicetaginterface.

Please refer to the Spring.Aop.Framework.Adapter namespacedocumentationforfurtherinformation.

Page 351: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

13.13.FurtherreadingandresourcesTheSpring.NETteamrecommendstheexcellentAspectJinActionbyRamnivasLaddad(Manning,2003)foranintroductiontoAOP.IfyouareinterestedinmoreadvancedcapabilitiesofSpring.NETAOP, takealook at the test suite as it illustrates advanced features not discussed in thisdocument.

Page 352: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter14.AspectLibrary

Page 353: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

14.1.IntroductionSpringprovidesseveralaspectsinthedistribution.Themostpopularofwhichistransactional advice, located in the Spring.Datamodule.However, the aspectsthat are documented in this section are those containedwithin theSpring.Aopmodule itself. The aspects in within Spring.Aop.dll are Caching, ExceptionHandling, Logging, Retry, and Parameter Validation. Other traditional advicetypessuchasvalidation,security,andthreadmanagement,willbeincludedinafuturerelease.

Page 354: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

14.2.CachingCaching the returnvalueof amethodor thevalueof amethodparameter is acommonapproachtoincreaseapplicationperformance.Applicationperformanceisincreasedwitheffectiveuseofcachingsincelayersintheapplicationthatareclosertotheusercanreturninformationwithintheirownlayerascomparedtomakingmoreexpensivecallstoretrievethatinformationfromalower,andmoreslow,layersuchasadatabaseorawebservice.Cachingalsocanhelpintermsofapplicationscalability,whichisgenerallythemoreimportantconcern.ThecachingsupportinSpring.NETconsistsofbasecacheinterfacesthatcanbeusedtospecifyaspecificstorageimplementationofthecacheandalsoanaspectthatdetermineswheretoapplythecachingfunctionalityanditsconfiguration.The base cache interface that any cache implementation should implement isSpring.Caching.ICache located in Spring.Core. Twoimplementations are provided, Spring.Caching.AspNetCachelocatedinSpring.WebwhichstorescacheentrieswithinanASP.NETcacheand a simple implementation,Spring.Caching.NonExpiringCachethatstorescacheentriesinmemoryandneverexpirestheseentries.Customimplementationsbasedon3rdparty implementations, suchasOracleCoherence,ormemcached, canbeusedbyimplementingtheICacheinterface.

The cache aspect is Spring.Aspects.Cache.CacheAspectlocated in Spring.Aop. It consists of three pieces of functionality, theability to cache return values, method parameters, and explicit eviction of anitemfromthecache.Theaspectcurrentlyreliesonusingattributestospecifythepointcut as well as the behavior, much like the transactional aspect. Futureversionswillallowforexternalconfigurationof thebehaviorsoyoucanapplycachingtoacodebasewithoutneedingtouseattributesinthecode.Thefollowingattributesareavailable

CacheResult-usedtocachethereturnvalue

CacheResultItems - usedwhen returning a collection as a returnvalue

CacheParameter-usedtocacheamethodparameter

Page 355: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

InvalidateCache-usedtoindicateoneormorecacheitemsshouldbeinvalidated.

Each CacheResult, CacheResultItems, andCacheParameterattributesdefinethefollowingproperties.

CacheName-thenameofthecacheimplementationtouse

Key - a string representing a Spring Expression Language (SpEL)expressionusedasthekeyinthecache.

Condition - a SpEL expression that should be evaluated in order todeterminewhethertheitemshouldbecached.

TimeToLive-Theamountoftimeanobjectshouldremaininthecache(inseconds).

TheInvalidateCache attribute has properties for theCacheName, theKeyaswellastheCondition,withthesamemeaningsaslistedpreviously.Each ICache implementation will have properties that are specific to acaching technology. In the case of AspNetCache, the two importantpropertiestoconfigureare:

SlidingExperation - If this property value is set to true, everytime the marked object is accessed it's TimeToLive value is reset to itsoriginalvalue

Priority-thecacheitemprioritycontrollinghowlikelyanobjectistoberemovedfromanassociatedcachewhenthecacheisbeingpurged.

TimeToLive-Theamountoftimeanobjectshouldremaininthecache(inseconds).

ThevaluesofthePriorityenumerationare

Low-lowlikelihoodofdeletionwhencacheispurged.

Normal-defaultpriorityfordeletionwhencacheispurged.

High-highlikelihoodofdeletionwhencacheispurged.

NotRemovable-cacheitemnotdeletedwhencacheispurged.Animportantelementoftheapplyingtheseattributesistheuseoftheexpressionlanguagethatallowsforcallingcontextinformationtodrivethecachingactions.

Page 356: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Here is an example taken from the Spring Air sample application of theAirportDao implementation that implements an interface with the methodGetAirport(longid).

[CacheResult("AspNetCache","'Airport.Id='+#id",TimeToLive=

publicAirportGetAirport(longid)

{

//implementationnotshown...

}

Thefirstparameteristhecachename.Thesecondstringparameteristhecachekey and is a string expression that incorporates the argument passed into themethod,theid.Themethodparameternamesareexposedasvariablestothekeyexpression.Ifyoudonotspecifyakey,thenalltheparametervalueswillbeusedtocachethereturnedvalue.Theexpressionmayalsocallouttootherobjectsinthe Spring container allowing for a more complex key algorithm to beencapsulated. The end result is that theAirport object is cached by id for 60seconds in a cache namedAspNetCache. TheTimetoLive property could alsohavebeenspecifiedontheconfigurationoftheAspNetCacheobject.Theconfigurationtoenablethecachingaspectisshownbelow

<object"id="CacheAspect"type="Spring.Aspects.Cache.CacheAspect,Spring.Aop"

<objectid="AspNetCache"type="Spring.Caching.AspNetCache,Spring.Web"

<propertyname="SlidingExpiration"value="true"/>

<propertyname="Priority"value="Low"/>

<propertyname="TimeToLive"value="00:02:00"/>

</object>

<!--ApplyaspectstoDAOs-->

<objecttype="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator,Spring.Aop"

<propertyname="ObjectNames">

<list>

<value>*Dao</value>

</list>

</property>

<propertyname="InterceptorNames">

<list>

<value>CacheAspect</value>

</list>

Page 357: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</property>

</object>

in this example an ObjectNameAutoProxyCreator was used toapplythecacheaspecttoobjectsthathaveDaointheirname.TheAspNetCachesetting for TimeToLivewill override the TimeToLive value set at the methodlevelviatheattribute.

Page 358: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

14.3.ExceptionHandlingIn some cases existing code can be easily adopted to a simple error handlingstrategythatcanperformoneofthefollowingactions

translations-eitherwrapthethrownexceptioninsideanewoneorreplaceitwithanewexceptiontype(noinnerexceptionisset).

returnvalue-theexceptionisignoredandareturnvalueforthemethodisprovidedinstead

swallow-theexceptionisignored.

execute - Execute an abritrary Spring Expression Language (SpELexpression)

Theapplicabilityofgeneralexceptionhandlingadvicedependsgreatlyonhowtangledthecodeisregardingaccesstolocalvariablesthatmayformpartoftheexception. Once you get familiar with the feature set of Spring declarativeexception handling advice you should evaluate where it may be effectivelyapplied in your code base. It isworth noting that you can still chain togethermultiplepiecesofexceptionhandlingadviceallowingyoutomixthedeclarativeapproachshownin thissectionwith the traditional inheritancebasedapproach,i.e.implementingIThrowsAdviceorIMethodInterceptor.Declarative exception handling is expressed in the form of a mini-languagerelevanttothedomainathand,exceptionhandling.ThiscouldbereferredtoasaDomain Specific Language (DSL). Here is a simple example, which shouldhopefullybeselfexplanatory.

<objectname="exceptionHandlingAdvice"type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice,Spring.Aop"

<propertyname="exceptionHandlers">

<list>

<value>onexceptionnameArithmeticExceptionwrapSystem.InvalidOperationException

</list>

</property>

</object>

What this is instructing the advice to do is the followingbit of codewhen anArithmeticException is thrown, throw newSystem.InvalidOperationException("WrappedArithmeticException",e),whereeis the original ArithmeticException. The default message, "Wrapped

Page 359: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ArithmethicException"isautomaticallyappended.Youmayhoweverspecifythemessageusedinthenewlythrownexceptionasshownbelow

onexceptionnameArithmeticExceptionwrapSystem.InvalidOperationException'MyMessage'

Similarly,ifyouwouldratherreplacetheexception,thatisdonotnestoneinsidetheother,youcanusethefollowingsyntax

onexceptionnameArithmeticExceptionreplaceSystem.InvalidOperationException

or

onexceptionnameArithmeticExceptionreplaceSystem.InvalidOperationException'MyMessage'

Bothwrapandreplacearespecialcasesofthemoregeneraltranslateaction.Anexampleofatranslateexpressionisshownbelow

onexceptionnameArithmeticExceptiontranslatenewSystem.InvalidOperationException('MyMessage,MethodName'+#method.Name,#e)

Whatwe see here after the translate keyword is text that will be passed intoSpring'sexpressionlanguage(SpEL)forevaluation.Refertothechapterontheexpression language for more details. One important feature of the expressionevaluationistheavailabilityofvariablesrelatingtothecallingcontextwhentheexceptionwasthrown.Theseare

method-theMethodInfoobjectcorrespondingtothemethodthatthrewtheexception

args-theargumentarraytothemethodthatthrewtheexception,signatureisobject[]

target-theAOPtargetobjectinstance.

e-thethrownexceptionYoucaninvokemethodsonthesevariables,prefixedbya '#'intheexpression.Thisgivesyoutheflexibilitytocallspecialpurposeconstructors thatcanhaveany piece of information accessible via the above variables, or even otherexternal data through the use ofSpEL's ability to reference objectswithin theSpringcontainer.Youmay also choose to 'swallow' the exception or to return a specific return

Page 360: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

value,forexample

onexceptionnameArithmeticExceptionswallow

or

onexceptionnameArithmeticExceptionreturn12

Youmayalsosimplylogtheexception

onexceptionnameArithmeticException,ArgumentExceptionlog'MyMessage,MethodName'+#method.Name

Hereweseethatacommadelimitedlistofexceptionnamescanbespecified.TheloggingisperformedusingtheCommons.Logginglibrarythatprovidesanabstractionovertheunderlyingloggingimplementation.Loggingiscurrentlyatthe debug level with a logger name of "LogExceptionHandler" The ability tospecify these values will be a future enhancement and likely via a syntaxresemblingaconstructorfortheaction,i.e.log(Debug,"LoggerName").Multiple exception handling statements can be specifiedwithin the list shownabove.Theprocessingflowisonexception,thenameoftheexceptionlistedinthestatementiscomparedtothethrownexceptiontoseeifthereisamatch.Acomma separated list of exceptions can be used to group together the sameactiontakenfordifferentexceptionnames.Iftheactiontotakeislogging,thenthe logging action is performed and the search for other matching exceptionnamescontinues.Forallotheractions,namelytranslate,wrap,replace,swallow,return,onceanexceptionhandler ismatched, those in thechainareno longerevaluated.Note,donotconfusethishandlerchainwiththegeneraladviceAOPadvice chain. For translate, wrap, and replace actions a SpEL expression iscreated and used to instantiate a new exception (in addition to any otherprocessing that may occur when evaluating the expression) which is thenthrown.TheexceptionhandlingDSLalsosupportstheabilitytoprovideaSpELbooleanexpression todetermine if theadvicewill apply insteadof just filteringby theexpression name. For example, the following is the equivalent to the firstexample based on exception names but compares the specific type of the

Page 361: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

exceptionthrown

onexception(#eisT(System.ArithmeticException))wrapSystem.InvalidOperationException

The syntax use is 'on exception (SpEL boolean expression)' and inside theexpressionyouhaveaccesstothevariablesofthecallingcontextlistedbefore,i.e.method,args,target,ande.Thiscanbeusefultoimplementasmallamountof conditional logic, such as checking for a specific error number in anexception, i.e.(#e is T(System.Data.SqlException) &&#e.Errors[0].Numberin{156,170,207,208}), to catchandtranslatebadgrammarcodesinaSqlException.Whiletheexamplesgivenabovearetoyexamples, theycouldjustaseasilybechanged to convert your application specific exceptions. If you find yourselfpushing the limits of using SpEL expressions, you will likely be better offcreatingyourowncustomaspectclassinsteadofascriptingapproach.YoucanalsoconfiguretheeachoftheHandlersindividuallybasedontheactionkeyword. For example, to configure the logging properties on theLogExceptionHandler.

<objectname="logExceptionHandler"type="Spring.Aspects.Exceptions.LogExceptionHandler,Spring.Aop"

<propertyname="LogName"value="Cms.Session.ExceptionHandler"

<propertyname="LogLevel"value="Debug"/>

<propertyname="LogMessageOnly"value="true"/>

</object>

<objectname="exceptionHandlingAdvice"type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice,Spring.Aop"

<propertyname="ExceptionHandlerDictionary">

<dictionary>

<entrykey="log"ref="logExceptionHandler"/>

</dictionary>

</property>

<propertyname="ExceptionHandlers">

<list>

<value>onexceptionnameArithmeticException,ArgumentExceptionlog

</list>

</property>

</object>

Page 362: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

YoucanalsoconfigureExceptionHandlerAdvicetouseaninstanceof IExceptionHandler by specifing it as an entry in theExceptionHandlers list. This gives you complete control over all properties ofthe handler but you must set ConstraintExpressionText andActionExpressionTextwhicharenormallyparsedforyoufromthestring.Tousethe case of configuring the LogExceptionHandler, this approach also lets youspecify advanced logging functionality, but at a cost of some additionalcomplexity.Forexamplesettingthelogginglevelandpasstheexceptionintotheloggingsubsystem

<objectname="exceptionHandlingAdvice"type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice,Spring.Aop"

<propertyname="exceptionHandlers">

<list>

<objecttype="Spring.Aspects.Exceptions.LogExceptionHandler"

<propertyname="LogName"value="Cms.Session.ExceptionHandler"

<propertyname="ConstraintExpressionText"value="#eisT(System.Threading.ThreadAbortException)"

<propertyname="ActionExpressionText"value="#log.Fatal('RequestTimeoutoccured',#e)"

</object>

</list>

</property>

</object>

The configuration of the logger name, level, and weather or not to pass thethrownexceptionasthesecondargumenttothelogmethodwillbesupportedintheDSLstyleinafuturerelease.

14.3.1.LanguageReferenceThegeneralsyntaxofthelanguageison exception name

[ExceptionName1,ExceptionName2,...] [action]

[SpELexpression]

oronexception(SpELbooleanexpression)[action]

[SpELexpression]

Theexceptionnamesarerequiredaswellastheaction.Thevalidactionsare

log

Page 363: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

translate

wrap

replace

return

swallow

executeTheformoftheexpressiondependsontheaction.Forlogging,theentirestringis taken as the SpEL expression to log. Translate expects an exception to bereturnedfromevaluationtheSpELexpression.Wrapandreplaceareshorthandfor the translate action. Forwrap and replace you specify the exception nameand the message to pass into the standard exception constructors (string,exception) and (string).The exceptionnamecanbeapartialor fullyqualifiedname. Spring will attempt to resolve the typename across all referencedassemblies.YoumayalsoregistertypealiasesforusewithSpELinthestandardmannerwithSpring.NETandthosewillbeaccessiblefromwithintheexceptionhandlingexpression.

Page 364: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

14.4.LoggingThe logging advice lets you log the information on method entry, exit andthrownexception (ifany).The implementation isbasedon the logging library,Common.Logging,thatprovidesportabilityacrossdifferentlogginglibraries.Thereareanumberofconfigurationoptionsavailable,listedbelow

LogUniqueIdentifier

LogExecutionTime

LogMethodArguments

LogReturnValue

Separator

LogLevelYou declare the logging advice in IoC container with the following XMLfragment.Alternatively, you can use the classSimpleLoggingAdviceprogramatically.

<objectname="loggingAdvice"type="Spring.Aspects.Logging.SimpleLoggingAdvice,Spring.Aop"

<propertyname="logUniqueIdentifier"value="true"/>

<propertyname="logExecutionTime"value="true"/>

<propertyname="logMethodArguments"value="true"/>

<propertyname="LogReturnValue"value="true"/>

<propertyname="Separator"value=";"/>

<propertyname="LogLevel"value="Info"/>

<propertyname="HideProxyTypeNames"value="true"/>

<propertyname="UseDynamicLogger"value="true"/>

</object>

The default values for LogUniqueIdentifier, LogExecutionTime,LogMethodArguments and LogReturnValue are false. The default separatorvalueis","andthedefaultloglevelisCommon.Logging'sLogLevel.Trace.You can set the name of the logger with the property LoggerName, forexample"DataAccessLayer" fora loggingadvice thatwouldbeappliedacrossthe all the classes in the data access layer. That works well when using a

Page 365: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

'category'styleoflogging.IfyoudonotsettheLoggerNameproperty,thenthetypenameoftheloggingadviceisusedastheloggingname.Anotherapproachtologgingistologbasedonthetypeoftheobjectbeingcalled,thetargettype.Sinceoftenthisisaproxyclasswitharelativelymeaninglessname,thepropertyHideProxyTypeNamescanbesettotruetoshowthetruetargettypeandnottheproxytype.To further extend the functionality of theSimpleLoggingAdviceyoucansubclassSimpleLoggingAdviceandoverridethemethods

string GetEntryMessage(IMethodInvocation

invocation,stringidString)

stringGetExceptionMessage(IMethodInvocation

invocation, Exception e, TimeSpan

executionTimeSpan,stringidString)

string GetExitMessage(IMethodInvocation

invocation, object returnValue, TimeSpan

executionTimeSpan,stringidString)

The default implementation to calculate a unique identifier is to use aGUID.You can alter this behavior by overriding the method string

CreateUniqueIdentifier(). The SimpleLoggingAdviceclass inherits fromAbstractLoggingAdvice, which has the abstractmethod object InvokeUnderLog(IMethodInvocation

invocation, ILog log) and you can also override the methodILog GetLoggerForInvocation(IMethodInvocation

invocation) tocustomize the logger instanceused for logging.Refer tothe SDK documentation for more details on subclassingAbstractLoggingAdvice.AsanexampleoftheLoggingadvice'soutput,addingtheadvicetothemethod

publicintBark(stringmessage,int[]luckyNumbers)

{

return4;

}

AndcallingBark("hello",newint[]{1,2,3}),resultsinthefollowingoutput

Page 366: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

EnteringBark,5d2bad47-62cd-435b-8de7-91f12b7f433e,message=hello;luckyNumbers=System.Int32[]

ExitingBark,5d2bad47-62cd-435b-8de7-91f12b7f433e,30453.125ms,return=4

ThemethodparametersvaluesareobtainedusingtheToString()method.Ifyouwould like tohaveanalternate implementation,say toviewsomevaluesinanarray, override the method stringGetMethodArgumentAsString(IMethodInvocationinvocation).The Spring 1.2 releasewill have an additional logging advice implementationthatleveragestheSpringExpressionLanguagetofurthercustomizethecontentof the logging messages via simple configuration using similar syntax to theretryandexceptionhandlingadvice.

Page 367: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

14.5.RetryWhenmakingadistributedcall it isoftenacommonrequirementtobeabletoretry themethod invocation if therewasanexception.Typically the exceptionwill be due to a communication issue that is intermittent and retrying over aperiodoftimewilllikelyresultinasuccessfulinvocation.Whenapplyingretryadvice it is important to know ifmaking two calls to the remote servicewillcause side effects. Generally speaking, the method being invoked should beidempotent,thatis,itissafetocallmultipletimes.Theretryadviceisspecifiedusingalittlelanguage,i.eaDSL.Asimpleexampleisshownbelow

onexceptionnameArithmeticExceptionretry3xdelay1s

Themeaning is: when an exception that has 'ArithmeticException' in its typename is thrown, retry the invocation up to 3 times and delay for 1 secondbetweeneachretryevent.You can also provide a SpEL (Spring Expression Language) expression thatcalculatesthetimeintervaltosleepbetweeneachretryevent.Thesyntaxforthisisshownbelow

onexceptionnameArithmeticExceptionretry3xrate(1*#n+0.5)

Aswith the exceptionhandling advice, youmay also specify a booleanSpELthatmustevaluatetotrueinorderfortheadvicetoapply.Forexample

onexception(#eisT(System.ArithmeticException))retry3xdelay1s

onexception(#eisT(System.ArithmeticException))retry3xrate(1*#n+0.5)

The time specified after thedelaykeyword is converted to aTimeSpan objectusingSpring'sTimeSpanConverter.Thissupportssettingthetimeasaninteger+time unit. Time units are (d, h, m, s, ms) representing (days, hours, minutes,seconds,andmilliseconds).Forexample;1d=1day,5h=5hoursetc.Youcannot specify a string such as '1d 5h'. The value that is calculated from theexpression after the rate keyword is interpreted as a number of seconds. The

Page 368: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

powerofusingSpELfortherateexpressionisthatyoucaneasilyspecifysomeexponential retry rate (a bigger delay for each retry attempt) or call out to acustomfunctiondevelopedforthispurpose.WhenusingaSpELexpressionforthefilterconditionorfortherateexpression,thefollowingvariableareavailable

method-theMethodInfoobjectcorrespondingtothemethodthatthrewtheexception

args-theargumentarraytothemethodthatthrewtheexception,signatureisobject[]

target-theAOPtargetobjectinstance.

e-thethrownexceptionYou declare the advice in IoC container with the following XML fragment.Alternatively,youcanusetheRetryAdviceclassprogramatically.

<objectname="exceptionHandlingAdvice"type="Spring.Aspects.RetryAdvice,Spring.Aop"

<propertyname="retryExpression"value="onexceptionnameArithmeticExceptionretry3xdelay1s"

</object>

14.5.1.LanguageReferenceThegeneralsyntaxofthelanguageison exception name

[ExceptionName1,ExceptionName2,...] retry

[number of times]x [delay|rate] [delay

time|SpELrateexpression]

oron exception (SpEL boolean expression) retry

[number of times]x [delay|rate] [delay

time|SpELrateexpression]

Page 369: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

14.6.TransactionsThe transaction aspect is more fully described in the section on transactionmanagement.

Page 370: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

14.7.ParameterValidationSpring provides a UI-agnostic validation framework in which you can declarevalidation rules, both progammatically and declaratively, and have those rulesevaluated against an arbitrary .NETobject. Spring provides additional supportfortherenderingofvalidationerrorswithinSpring'sASP.NETframework.(SeethesectiononASP.NET usage tips formore information.)However, validation isnotconfinedtotheUItier.Itisacommontaskthatoccursacrossmost,ifnotall,applicationslayers.ValidationthatisperformedintheUIlayerisoftenrepeatedintheservicelayer,inordertobeproactiveincasenonUI-basedclientsinvoketheservicelayer.ValidationrulescompletelydifferentfromthoseusedintheUIlayermayalsobeusedontheserverside.Toaddresssomeofthecommonneedsforvalidationontheserverside,SpringprovidesparametervalidationadvicesothatappliesSpring'svalidationrulestothemethodparameters.The classParameterValidationAdvice isusedinconjunctionwiththeValidatedattributetospecifywhichvalidationrules are applied to method parameters. For example, to apply parametervalidation to themethodSuggestFlights in theBookingAgentclassused in theSpringAir sample application, you would apply theValidated attribute to themethodparametersasshownbelow.

publicFlightSuggestionsSuggestFlights([Validated("tripValidator"

{

//unmodifiedimplementationgoeshere

}

TheValidatedattributetakesastringnamethatspecifiesthenameofthevalidation rule, i.e. thenameof the IValidatorobject in theSpring applicationcontext. The Validated attribute is located in the namespaceSpring.ValidationoftheSpring.Coreassembly.The configuration of the advice is to simply define the an instance of theParameterValidationAdvice class and apply the advice, forexample based on object names using anObjectNameAutoProxyCreator,asshownbelow,

<objectid="validationAdvice"type="Spring.Aspects.Validation.ParameterValidationAdvice,Spring.Aop"

Page 371: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objecttype="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator,Spring.Aop"

<propertyname="ObjectNames">

<list>

<value>bookingAgent</value>

</list>

</property>

<propertyname="InterceptorNames">

<list>

<value>validationAdvice</value>

</list>

</property>

</object>

When the advised method is invoked first the validation of each methodparameter is performed. If all validation succeeds, then the method body isexecuted. If validation fails an exception of the typeValidationException is thrown and you can retrieve errorsinformation from its property ValidationErrors. See the SDKdocumentationfordetails.

Page 372: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter15.CommonLogging

Page 373: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

15.1.IntroductionSpring uses a simple logging abstraction in order to provide a layer ofindirection between logging calls made by Spring and the specific logginglibraryusedinyourapplication(log4net,EntLiblogging,NLog).Thelibraryisavailable for .NET 1.0, 1.1, and 2.0 with both debug and strongly signedassemblies. Since this need is not specific to Spring, the logging library wasmoved out of the Spring project and into amore general open source projectcalledCommon Infrastructure Libraries for .NET. The logging abstraction within theproject is knownasCommon.Logging.Note that it is not the intention of thislibrarytobeareplacementforthemanyfinelogginglibrariesthatareoutthere.TheAPIisincrediblyminimalandwillverylikelystaythatway.Pleasenotethatthis library is intended only for use where the paramount requirement isportability andyouwill generally bebetter servedbyusing a specific loggingimplementation so that you can leverage its advanced features and extendedAPIstoyouradvantage.You can find online documentation on how to configure Common.Logging isavailableinHTML,PDF,andHTMLHelpformats.

Page 374: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter16.Testing

Page 375: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

16.1.IntroductionTheSpringteamconsidersdevelopertestingtobeanabsolutelyintegralpartofenterprise software development. A thorough treatment of testing in theenterprise is beyond the scope of this chapter; rather, the focus here is on thevalueaddthat theadoptionof theIoCprinciplecanbring tounit testing;andonthebenefitsthattheSpringFrameworkprovidesinintegrationtesting.

Page 376: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

16.2.UnittestingOneofthemainbenefitsofDependencyInjectionisthatyourcodeismuchlesslikely to have any hidden dependencies on the runtime environment or otherconfiguration subsystems.This allows for unit tests to bewritten in amannersuchthattheobjectundertestcanbesimplyinstantiatedwiththenewoperatorandhaveitsdependencessetintheunittestcode.Youcanusemockobjects(inconjunctionwithmany other valuable testing techniques) to test your code inisolation. If you follow the architecture recommendations around Spring youwillfindthattheresultingcleanlayeringandcomponentizationofyourcodebasewillnaturallyfaciliateeasierunittesting.Forexample,youwillbeable to testservicelayerobjectsbystubbingormockingDAOinterfaces,withoutanyneedtoaccesspersistentdatawhilerunningunittests.True unit tests typically will run extremely quickly, as there is no runtimeinfrastructuretosetup,i.e.,database,ORMtool,orwhatever.Thusemphasizingtrue unit tests as part of your development methodology will boost yourproductivity.TheupshotofthisisthatyoudonotneedthissectionofthetestingchaptertohelpyouwriteeffectiveunittestsforyourIoC-basedapplications.

Page 377: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

16.3.IntegrationtestingHowever, it is also important to be able to perform some integration testingenablingyoutotestthingssuchas:

ThecorrectwiringofyourSpringIoCcontainercontexts.

Data access using ADO.NET or an ORM tool. This would include suchthings such as the correctness of SQL statements / or NHibernate XMLmappingfiles.

TheSpringFrameworkprovidesfirstclasssupportforintegrationtestingintheform of the classes that are packaged in theSpring.Testing.NUnit.dll library. Please note that these testclasses are NUnit-specific. Support for mbUnit and VSTS are underconsiderationforfutureversions.

Note

TheSpring.Testing.NUnit.dlllibraryiscompiledagainstNUnit2.4.1.AtthetimeofthiswritingthelatestversionofNUnitis2.4.6.Notethatadd-inhavetheirownversionsofNUnittheyuse.Forexample,ReSharper3.0uses2.2.8.IfyouareusingtheGUI-runnerthatcomeswithNUnitthenyoushouldaddthefollowingtoyour.configfile,(intheformofMyAssembly.dll.config)

<runtime>

<assemblyBindingxmlns="urn:schemas-microsoft-com:asm.v1">

<dependentAssembly>

<assemblyIdentityname="nunit.framework"

publicKeyToken="96d09a1eb7f44a77"

culture="neutral"/>

<bindingRedirectoldVersion="0.0.0.0-65535.65535.65535.65535

newVersion="2.4.6.0"/>

</dependentAssembly>

</assemblyBinding>

</runtime>

The Spring.Testing.NUnit namespace provides valuable NUnit

Page 378: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TestCasesuperclassesforintegrationtestingusingaSpringcontainer.Notethat as of NUnit 2.4 these can be rewritten in terms of custom attributes viaNUnit's new extensibilitymechanism. This will be an additional option in anupcomingreleaseofSpring.NETandisalreadypresentintheJavaversionoftheSpringframework.Thesesuperclassesprovidethefollowingfunctionality:

SpringIoCcontainercachingbetweentestcaseexecution.

Thepretty-much-transparentDependency Injectionof test fixture instances (this isnice).

Transactionmanagementappropriatetointegrationtesting(thisisevennicer).

AnumberofSpring-specific inherited instance variables that are really usefulwhenintegrationtesting.

16.3.1.ContextmanagementandcachingTheSpring.Testing.NUnitpackage provides support for consistentloading of Spring contexts, and caching of loaded contexts. Support for thecachingofloadedcontextsis important,because ifyouareworkingona largeproject, startup time may become an issue - not because of the overhead ofSpring itself, but because the objects instantiated by the Spring containerwillthemselves take time to instantiate. For example, a project with 50-100NHibernatemapping filesmight take10-20seconds to load themapping files,andincurringthatcostbeforerunningeverysingletestcaseineverysingletestfixturewillleadtosloweroveralltestrunsthatcouldreduceproductivity.To address this issue, theAbstractDependencyInjectionSpringContextTests

hasanprotected property that subclassesmust implement to provide thelocationofcontextdefinitionfiles:

protectedabstractstring[]ConfigLocations{get;}

ImplementationsofthismethodmustprovideanarraycontainingtheIResourcelocationsofXMLconfigurationmetadatausedtoconfiguretheapplication.Thiswill be the same, or nearly the same, as the list of configuration locationsspecified in App.config/Web.config or other deployment

Page 379: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

configuration.Bydefault, once loaded, the configuration file setwill be reused for each testcase. Thus the setup cost will be incurred only once (per test fixture), andsubsequenttestexecutionwillbemuchfaster.Intheunlikelycasethatatestmay'dirty' the config location, requiring reloading - for example, by changing anobject definition or the state of an application object - you can call theSetDirty() method onAbstractDependencyInjectionSpringContextTests tocause the test fixture to reload the configurations and rebuild the applicationcontextbeforeexecutingthenexttestcase.

16.3.2.DependencyInjectionoftestfixturesWhenAbstractDependencyInjectionSpringContextTests

(and subclasses) load your application context, they can optionally configureinstancesofyourtestclassesbySetterInjection.Allyouneedtodoistodefineinstance variables and the corresponding setters.AbstractDependencyInjectionSpringContextTests

will automatically locate the corresponding object in the set of configurationfilesspecifiedintheConfigLocationsproperty.

Considerthescenariowherewehaveaclass,HibernateTitleDao,thatperformsdataaccesslogicforsay,theTitledomainobject.Wewanttowriteintegrationteststhattestallofthefollowingareas:

The Spring configuration; basically, is everything related to theconfiguration of the HibernateTitleDao object correct andpresent?

TheHibernatemapping fileconfiguration; iseverythingmappedcorrectlyandarethecorrectlazy-loadingsettingsinplace?

ThelogicoftheHibernateTitleDao;doestheconfiguredinstanceofthisclassperformasanticipated?

Let's lookat thetestclassitself(wewill lookat theconfiguration immediatelyafterwards).

[TestFixture]

Page 380: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassHibernateTitleDaoTests:AbstractDependencyInjectionSpringContextTests{

//thisinstancewillbe(automatically)dependencyinjected

privateHibernateTitleDaotitleDao;

//asettermethodtoenableDIofthe'titleDao'instancevariable

publicHibernateTitleDaoHibernateTitleDao{

set{titleDao=value;}

}

[Test]

publicvoidLoadTitle(){

Titletitle=this.titleDao.LoadTitle(10);

Assert.IsNotNull(title);

}

//specifiestheSpringconfigurationtoloadforthistestfixture

protectedoverridestring[]ConfigLocations{

returnnewString[]{"assembly://MyAssembly/MyNamespace/daos.xml"

}

}

The file referenced by the ConfigLocations method('classpath:com/foo/daos.xml')lookslikethis:

<?xmlversion="1.0"encoding="utf-8"?>

<objectsxmlns="http://www.springframework.net">

<!--thisobjectwillbeinjectedintotheHibernateTitleDaoTests<objectid="titleDao"type="Spring.Samples.HibernateTitleDao,Spring.Samples"

<propertyname="sessionFactory"ref="sessionFactory"

</object>

<objectid="sessionFactory"type="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate"

<!--dependencieselidedforclarity-->

</object>

</objects>

The

Page 381: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AbstractDependencyInjectionSpringContextTests

classesusesautowireby type.Thus ifyouhavemultipleobjectdefinitionsof thesametype,youcannotrelyon thisapproachfor thoseparticularobject. In thatcase,youcanusetheinheritedapplicationContextinstancevariable,and explicit lookup using (for example) an explicit call toapplicationContext.GetObject("titleDao").Ifyoudon'twantdependencyinjectionapplied toyour testcases,simplydon'tdeclare any set properties. Alternatively, you can extend theAbstractSpringContextTests - the rootof theclass hierarchy inthe Spring.Testing.NUnit namespace. It merely containsconvenience methods to load Spring contexts, and performs no DependencyInjectionofthetestfixture.

16.3.2.1.FieldlevelinjectionIf, for whatever reason, you don't fancy having setter properties in your testfixtures,Springcan (in thisonecase) injectdependencies intoprotectedfields. Find below a reworking of the previous example to use field levelinjection (theSpringXML configuration does not need to change,merely thetestfixture).

[TestFixture]

publicclassHibernateTitleDaoTests:AbstractDependencyInjectionSpringContextTests{

publicHibernateTitleDaoTests(){

//switchonfieldlevelinjection

PopulateProtectedVariables=true;

}

//thisinstancewillbe(automatically)dependencyinjected

protectedHibernateTitleDaotitleDao;

[Test]

publicvoidLoadTitle(){

Titletitle=this.titleDao.LoadTitle(10);

Assert.IsNotNull(title);

}

//specifiestheSpringconfigurationtoloadforthistestfixture

Page 382: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

protectedoverridestring[]ConfigLocations{

returnnewString[]{"assembly://MyAssembly/MyNamespace/daos.xml"

}

}

Inthecaseoffieldinjection,thereisnoautowiringgoingon:thenameofyourprotected instancesvariable(s)areusedas the lookupobjectname in theconfiguredSpringcontainer.

16.3.3.TransactionmanagementOnecommonissueinteststhataccessarealdatabaseistheireffectonthestateof the persistence store. Even when you're using a development database,changes to the state may affect future tests. Also, many operations - such asinsertingtoormodifyingpersistentdata-cannotbedone(orverified)outsideatransaction.TheAbstractTransactionalDbProviderSpringContextTests

superclass(andsubclasses)exist tomeet thisneed.Bydefault, theycreateandrollbackatransactionforeachtest.Yousimplywritecodethatcanassumetheexistence of a transaction. If you call transactionally proxied objects in yourtests,theywillbehavecorrectly,accordingtotheirtransactionalsemantics.AbstractTransactionalSpringContextTestsdependsonaIPlatformTransactionManager object being defined in theapplicationcontext.Thenamedoesn'tmatter,duetotheuseofautowirebytype.Typically you will extend the subclass,AbstractTransactionalDbProviderSpringContextTests

This also requires that aDbProvider object definition - again, with anyname-bepresentintheconfigurations.ItcreatesanAdoTemplateinstancevariablethatisuseful forconvenientquerying,andprovideshandymethods todelete the contents of selected tables (remember that the transaction will rollbackbydefault,sothisissafetodo).Ifyouwantatransactiontocommit-unusual,butoccasionallyusefulwhenyouwant a particular test to populate the database - you can call theSetComplete() method inherited from

Page 383: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AbstractTransactionalSpringContextTests. This willcausethetransactiontocommitinsteadofrollback.There is also convenient ability to end a transactionbefore the test case ends,throughcalling theEndTransaction()method.Thiswill rollback thetransaction by default, and commit it only if SetComplete() hadpreviously been called. This functionality is useful if you want to test thebehavior of 'disconnected' data objects, such asHibernate-mappedobjects thatwillbeusedinaweborremotingtieroutsideatransaction.Often,lazyloadingerrors are discovered only through UI testing; if you callEndTransaction()youcanensurecorrectoperationof theUI throughyourNUnittestsuite.

16.3.4.ConveniencevariablesWhen you extend theAbstractTransactionalDbProviderSpringContextTests

classyouwillhaveaccesstothefollowingprotectedinstancevariables:

applicationContext (aIConfigurableApplicationContext): inherited from theAbstractDependencyInjectionSpringContextTests

superclass.Usethistoperformexplicitobjectlookup,ortestthestateofthecontextasawhole.

adoTemplate: inherited fromAbstractTransactionalDbProviderSpringContextTests

Usefulforqueryingtoconfirmstate.Forexample,youmightquerybeforeandaftertestingapplicationcodethatcreatesanobjectandpersistsitusinganORMtool, toverify that thedataappears in thedatabase. (Springwillensure that thequery runs in thescopeof thesame transaction.)YouwillneedtotellyourORMtoolto'flush'itschangesforthistoworkcorrectly,for exampleusing theFlush()methodonNHibernate'sISessioninterface.

Oftenyouwillprovideanapplication-widesuperclass for integration tests thatprovidesfurtherusefulinstancevariablesusedinmanytests

Page 384: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

16.4.FurtherResourcesThissectioncontainslinkstofurtherresourcesabouttestingingeneral.

TheNUnithomepage.TheSpringFramework'sunittestsuiteiswrittenusingNUnitasthetestingframework.

Page 385: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PartII.MiddleTierDataAccessThispartofthereferencedocumentationisconcernedwithothemiddletier,andspecificallythedataaccessresponsibilitiesofsaidtier.Spring's comprehensive transaction management support is covered in somedetail, followed by thorough coverage of the various middle tier data accessframeworksandtechnologiesthattheSpringFrameworkintegrateswith.

Chapter17,Transactionmanagement

Chapter18,DAOsupport

Chapter19,DbProvider

Chapter20,DataaccessusingADO.NET

Chapter21,ObjectRelationalMapping(ORM)dataaccess

Page 387: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter17.Transactionmanagement

Page 388: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.1.IntroductionSpring.NET provides a consistent abstraction for transactionmanagement thatprovidesthefollowingbenefits

ProvidesaconsistentprogrammingmodelacrossdifferenttransactionAPIssuch as ADO.NET, Enterprise Services, System.Transactions, andNHibernate.

Support for declarative transaction management with any of the above dataaccesstechnologies

ProvidesasimpleAPIforprogrammatictransactionmanagement

Integrates with Spring's high level persistence integration APIs such asAdoTemplate.

Thischapter isdividedup intoanumberofsections,eachdetailingoneof thevalue-addsor technologiesof theSpringFramework's transaction support.Thechapter closes with some discussion of best practices surrounding transactionmanagement.

The first section, entitledMotivations describeswhyonewouldwant tousethe Spring Framework's transaction abstraction as opposed to usingSystem.TransactionsoraspecificdataaccesstechnologytransactionAPI.

Thesecondsection,entitledKeyAbstractionsoutlinethecoreclassesaswellashowtoconfigurethem.

Ththirdsection,entitledDeclarativetransactionmanagement,coverssupportfordeclarativetransactionmanagement.

The fourth section, entitled Programmatic transaction management, coverssupportforprogrammatictransactionmanagement.

Page 389: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.2.MotivationsThedataaccesstechnologylandscapeisabroadone,withinthe.NETBCLthereare three APIs for performing transaction management, namely ADO.NET,Enterprise Services, and System.Transactions. Other data access technologiessuch as object relational mappers and result-set mapping libraries are alsogaining in popularity and each come with their own APIs for transactionmanagement.Assuch,codeisoftendirectlytiedtoaparticulartransactionAPIwhich means you must make an up-front decision which API to use in yourapplication. Furthermore, if the need arises to change your approach, it quiteoftenwillnotbea simple refactoring.UsingSpring's transactionAPIyoucankeep the same API across different data access technologies. Changing theunderlying transaction implementation that is used is a simple matter ofconfiguration or a centralized programmatic change as compared to a majoroverhauling.Handinhandwiththevarietyofoptionsavailableistheestablishmentgenerallyagreed upon best practices for data access.Martin Fowler's book, Patterns ofEnterpriseApplicationArchitecture,isanexcellentsourceofapproachestodataaccess that have been successful in the realworld.One approach that is quitecommon is to introduce a data access layer into your architecture. The dataaccess layer is concerned not only with providing some portability betweendifferentdataaccesstechnologiesanddatabasesbutitsscopeisstrictlyrelatedtodataaccess.Asimpledataaccesslayerwouldbenotmuchmorethandataaccessobjects (DAOs)with 'Create/Retrieve/Update/Delete' (CRUD)methods devoidof any business logic. Business logic resides in another application layer, thebusiness service layer, inwhichbusiness logicwill calloneormoreDAOs tofulfillahigherlevelend-userfunction.In order to perform this end-user function with all-or-nothing transactionalsemantics,thetransactioncontextiscontrolledbythebusinessservicelayer(orother'higher'layers).Insuchacommonscenario,animportantimplementationdetailishowtomaketheDAOobjectsawareofthe'outer'transactionstartedinanother layer. A simplistic implementation of a DAOwould perform its ownconnection and transactionmanagement, but thiswouldnot allowgroupingofDAO operations with the same transaction as the DAO is doing its owntransaction/resourcemanagement.Assuchthereneedstobeameanstotransferthe connection/transaction pair managed in the business service layer to the

Page 390: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

DAOs. There are a variety of ways to do this, the most invasive being theexplicitly pass a connection/transaction object as method arguments to yourDAOs.Anotherway is to store the connection/transaction pair in thread localstorage. In either case, if you are using ADO.NET you must invent someinfrastructurecodetoperformthistask.Butwait, doesn't Enterprise Services solve this problem - andwhat about thefunctionalityintheSystem.Transactionsnamespace?Theanswerisyes...andno.Enterprise Services lets you use the 'raw'ADO.NETAPIwithin a transactioncontext such that multiple DAO operations are grouped within the sametransaction. The downside to Enterprise Services is that it always usesdistributed (global) transactions via the Microsoft Distributed TransactionCoordinator (MS-DTC). For most applications this is overkill just to get thisfunctionality as global transactions are significantly less performant than localADO.NETtransactions.Therearesimilarissueswithusingthe'usingTransactionScope'constructwithinthenewSystem.Transactionsnamespace.ThegoalwithTransactionScopeistodefine a,well - transaction scope -within a using statement. PlainADO.NETcodewithinthatusingblockwillthenbealocalADO.NETbasedtransactionifonly a single transactional resource is accessed. However, the 'magic' ofSystem.Transactions (and the database) is that local transactions will bepromoted to distributed transactions when a second transaction resource isdetected. The name that this goes by is Promotable Single Phase Enlistment(PSPE).However, there is a big caveat - opening up a second IDbConnectionobjecttothesamedatabasewiththesamedatabasestringwilltriggerpromotionfrom local to global transactions.As such, if yourDAOs are performing theirownconnectionmanagementyouwillendupbeingbumpeduptoadistributedtransaction. In order to avoid this situation for the common case of anapplicationusingasingledatabase,youmustpassaroundaconnectionobjecttoyourDAOs. It is alsoworth to note thatmany database providers (Oracle forsure) do not yet support PSPE and as such will always use a distributedtransactionevenifthereisonlyasingledatabase.Lastbutnot least is theability tousedeclarative transactionmanagement.Notmanytopicsindatabasetransaction-landgivedevelopersasmuch'bang-for-the-buck'asdeclarativetransactionssincethenoisytediousbitsoftransactionalAPIcode in your application are pushed to the edges, usually in the form ofclass/methodattributes.OnlyEnterpriseServicesoffersthisfeatureintheBCL.

Page 391: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Springfillsthegap-itprovidesdeclarativetransactionmanagement ifyouareusing localADO.NETorSystem.Transactions(themostpopular)orotherdataaccess technologies. Enterprise Services is not without it small warts aswell,such as the need to separate your query/retrieve operations from yourcreate/update/deleteoperationsifyouwanttousedifferentisolationlevelssincedeclarative transaction metadata can only be applied at the class level.Nevertheless,allinall,EnterpriseServices,inparticularwiththenew'ServicesWithout Components' implementation for XP SP2/Server 2003, and hostedwithinthesameprocessasyourapplicationcodeisasgoodasitgetsoutofthe.NETbox.Despitethesepositivepoints,ithasn'tgainedasignificantmindshareinthedevelopmentcommunity.Spring's transaction support aims to relieve these 'pain-points' using the dataaccess technologies within the BCL - and for other third party data accesstechnologies as well. It provides declarative transaction management with aconfigurable means to obtain transaction option metadata - out of the boxattributesandXMLwithinSpring'sIoCconfigurationfilearesupported.Finally,Spring'stransactionsupportletsyoumixdataaccesstechnologieswithinasingletransaction-forexampleADO.NETandNHibernateoperations.Withthislongwindedtouchy/feelymotivationalsectionbehindus,letsmoveontoseethecode.

Page 392: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.3.KeyAbstractionsThe key to the Spring transaction management abstraction is the notion of atransaction strategy. A transaction strategy is defined by theSpring.Transaction.IPlatformTransactionManager

interface,shownbelow:

publicinterfaceIPlatformTransactionManager{

ITransactionStatusGetTransaction(ITransactionDefinitiondefinition);

voidCommit(ITransactionStatustransactionStatus);

voidRollback(ITransactionStatustransactionStatus);

}

This is primarily a 'SPI' (Service Provider Interface), although it can be usedProgramatically.Notethat inkeepingwiththeSpringFramework'sphilosophy,IPlatformTransactionManager is an interface, and can thus beeasily mocked or stubbed as necessary.IPlatformTransactionManager implementationsaredefined likeany other object in the IoC container. The following implementations areprovided

AdoPlatformTransactionManager - localADO.NETbasedtransactions

ServiceDomainPlatformTransactionManager -distributedtransactionmanagerfromEnterpriseServices

TxScopePlatformTransactionManager - local/distributedtransactionmanagerfromSystem.Transactions.

HibernatePlatformTransactionManager - localtransaction manager for use with NHibernate or mixedADO.NET/NHibernatedataaccessoperations.

Under the covers, the following API calls are made. For theAdoPlatformTransactionManager, Transaction.Begin(), Commit(), Rollback().ServiceDomainPlatformTransactionManager uses the 'Services without

Page 393: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Components' update so that your objects do not need to inherit fromServicedComponent or directly call the Enterprise Services APIServiceDomain.Enter(), Leave; ContextUtil.SetAbort().TxScopePlatformTransactionManager calls; new TransactionScope();.Complete(), Dispose(), Transaction.Current.Rollback(). Configurationproperties for each transaction manager are specific to the data accesstechnologyused.Refer to theAPIdocsforcomprehensive informationbut theexamples should give you a good basis for getting started. TheHibernatePlatformTransactionManagerisdescribedmoreinthefollowingsection.The GetTransaction(..) method returns aITransactionStatus object, depending on aITransactionDefinition parameters. The returnedITransactionStatusmightrepresentaneworexistingtransaction(iftherewasamatchingtransactioninthecurrentcallstack-withtheimplicationbeingthataITransactionStatusisassociatedwithalogicalthreadofexecution.TheITransactionDefinitioninterfacespecified

Isolation:thedegreeofisolationthistransactionhasfromtheworkofothertransactions.Forexample,canthistransactionseeuncommittedwritesfromothertransactions?

Propagation:normallyallcodeexecutedwithinatransactionscopewillruninthat transaction.However, thereareseveraloptionsspecifyingbehaviorif a transactional method is executed when a transaction context alreadyexists:forexample,simplycontinuerunningintheexistingtransaction(thecommoncase); or suspending the existing transaction and creating a newtransaction.

Timeout: how long this transaction may run before timing out (andautomatically being rolled back by the underlying transactioninfrastructure).

Read-onlystatus:aread-onlytransactiondoesnotmodifyanydata.Read-onlytransactionscanbeausefuloptimizationinsomecases(suchaswhenusingNHibernate).

Thesesettingsreflectstandardtransactionalconcepts. Ifnecessary,pleaserefer

Page 394: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

to a resource discussing transaction isolation levels and other core transactionconcepts because understanding such core concepts is essential to using theSpringFrameworkorindeedanyothertransactionmanagementsolution.The ITransactionStatus interface provides a simple way fortransactionalcodetocontroltransactionexecutionandquerytransactionstatus.Regardless of whether you opt for declarative or programmatic transactionmanagement in Spring, defining the correctIPlatformTransactionManager implementation is absolutelyessential. In good Spring fashion, this important definition typically is madeusingviaDependencyInjection.IPlatformTransactionManagerimplementationsnormallyrequireknowledgeoftheenvironmentinwhichtheywork,ADO.NET,NHibernate,etc.The following example shows how a standard ADO.NET basedIPlatformTransactionManagercanbedefined.

We must define a Spring IDbProvider and then use Spring'sAdoPlatformTransactionManager, giving it a reference to theIDbProvider.FormoreinformationontheIDbProviderabstractionrefertothenextchapter.

<objectsxmlns='http://www.springframework.net'

xmlns:db="http://www.springframework.net/database">

<db:providerid="DbProvider"

provider="SqlServer-1.1"

connectionString="DataSource=(local);Database=Spring;UserID=springqa;Password=springqa;Trusted_Connection=False"

<objectid="TransactionManager"

type="Spring.Data.AdoPlatformTransactionManager,Spring.Data"

<propertyname="DbProvider"ref="DbProvider"/>

</object>

...otherobjectdefinitions...

</objects>

We can also use a transaction manager based on System.Transactions just as

Page 395: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

easily,asshowninthefollowingexample

<objectid="TransactionManager"

type="Spring.Data.TxScopeTransactionManager,Spring.Data"

</object>

SimilarlyfortheHibernateTransactionManagerasshowninthesectiononORMtransactionmanagement.Notethatinallthesecases,applicationcodewillnotneedtochangeatallsince,dependency injection is a perfect companion to using the strategy pattern.Wecan now change how transactions are managed merely by changingconfiguration, even if that change means moving from local to globaltransactionsorviceversa.

Page 396: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.4.ResourcesynchronizationwithtransactionsHow does application code participate with the resources (i.e.Connection/Transactions/Sessions) that are created/reused/cleanedup via thedifferent transactionmanagers?There are twoapproaches - a high-level and alow-levelapproach

17.4.1.High-levelapproachThepreferredapproachistouseSpring'shighlevelpersistenceintegrationAPIs.ThesedonotreplacenativeAPIs,butinternallyhandleresourcecreation/reuse,cleanup,andoptionaltransactionsynchronization(i.e.eventnotification)oftheresourcesandexceptionmappingso thatuserdataaccesscodedoesn'thave toworryabouttheseconcernsatall,butcanconcentratepurelyonnon-boilerplatepersistencelogic.Generally, thesameinversionofcontrolapproachisusedforallpersistenceAPIs.InthisapproachtheAPIhasacallbackmethodordelegatethat presents the user code with the relevant resource ready to use - i.e. aDbCommandwith its Connection and Transaction properties set based on thetransactionoptionmetadata.Theseclassesgobythenamingscheme'template',examplesofwhichareAdoTemplateandHibernateTemplate.Convenient 'one-liner'helpermethodsinthesetemplateclassesbuilduponthecorecallback/IoCdesignbyprovidingspecificimplementationsofthecallbackinterface.

17.4.2.Low-levelapproachAutilityclasscanbeusedtodirectlyobtainaconnection/transactionpairthatisaware of the transactional calling context and returns a pair suitable for thatcontext. The class ConnectionUtils contains the static methodConnectionTxPair

GetConnectionTxPair(IDbProvider provider) whichservesthispurpose.

Page 397: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.5.DeclarativetransactionmanagementMostSpringuserschoosedeclarative transactionmanagement. It is theoptionwiththeleastimpactonapplicationcode,andhenceismostconsistentwiththeidealsofanon-invasivelightweightcontainer.Spring'sdeclarativetransactionmanagementismadepossiblewithSpringAOP,although,asthetransactionalaspectscodecomeswithSpringandmaybeusedinaboilerplatefashion,AOPconceptsdonotgenerallyhavetobeunderstoodtomakeeffectiveuseofthiscode.Thebasicapproachistospecifytransactionbehavior(orlackofit)downtotheindividualmethodlevel.Itisalsopossibletomarkatransactionforrollbackbysetting the 'RollbackOnly' property on the ITransactionStatus object returnedfromtheIPlatformTransactionManagerwithinatransactioncontextifnecessary.SomeofthehighlightsofSpring'sdeclarativetransactionmanagementare:

Declarative Transaction management works in any environment. It canwork with ADO.NET, System.Transactions, NHibernate etc, withconfigurationchangesonly.

Enablesdeclarativetransactionmanagementtobeappliedtoanyclass,notmerelyspecialclassessuchas those that inherit fromServicedComponentorotherinfrastructurerelatedbaseclasses.

Declarativerollbackrules.Rollbackrulescanbecontroldeclarativelyandallowforonlyspecifiedexceptionsthrownwithinatransactionalcontexttotriggerarollback

Springgivesyouanopportunitytocustomizetransactionalbehavior,usingAOP.Forexample ifyouwant to insert custombehavior in the caseof atransactionrollback,youcan.Youcanalsoaddarbitraryadvice,alongwiththetransactionaladvice.

Spring does not support propagation of transaction context across remotecalls.

NoterollbackrulesasconfiguredfromXMLarestillunderdevelopment.The concept of rollback rules is important: they enable us to specify whichexceptions should cause automatic roll back.We specify this declaratively, inconfiguration,notincode.So,whilewecanstillsetRollbackOnlyontheITransactionStatus object to roll the current transaction back

Page 398: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Programatically,mostoftenwecanspecifyarulethatMyApplicationExceptionmustalwaysresult inrollback.Thishasthesignificantadvantage thatbusinessobjectsdon'tneedtodependonthetransactioninfrastructure.Forexample,theytypically don't need to import any Spring APIs, transaction or other. If youwould like to rollback the transaction programmatically and you are usingdeclarativetransactionmanagement,usetheutilitymethod

TransactionInterceptor.CurrentTransactionStatus.SetRollbackOnly();

Note

PriortoSpring.NET1.2RC1theAPIcallwouldbeTransactionInterceptor.CurrentTransactionStatus.RollbackOnly

=true;

17.5.1. Understanding Spring's declarative transactionimplementationThe aim of this section is to dispel themystique that is sometimes associatedwith the use of declarative transactions. It is all very well for this referencedocumentationtosimplytellyoutoannotateyourclasseswith theTransactionattribute and add some boilerplate XML to your IoC configuration, and thenexpectyou tounderstandhow it allworks.This sectionwill explain the innerworkingsofSpring'sdeclarative transaction infrastructure tohelpyounavigateyour way back upstream to calmer waters in the event of transaction-relatedissues.

Note

LookingattheSpringsourcecodeisagoodwaytogetarealunderstandingofSpring'stransactionsupport.YoushouldfindtheAPIdocumentationinformativeandcomplete.Wesuggestturningthelogginglevelto'DEBUG'inyourSpring-enabledapplication(s)duringdevelopmenttobetterseewhatgoesonunderthehood.

The most important concepts to grasp with regard to Spring's declarativetransactionsupportarethatthissupportisenabledviaAOPproxies,andthatthetransactionaladviceisdrivenbymetadata(currentlyXML-orattribute-based).The combination of a proxywith transactionalmetadata yields anAOPproxythat uses a TransactionInterceptor in conjunction with an

Page 399: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

appropriate IPlatformTransactionManager implementation todrivetransactionsaroundmethodinvocations.

Note

AlthoughknowledgeofAOP(andspecificallySpringAOP)isnotrequiredinordertouseSpring'sdeclarativetransactionsupport,itcanhelp.SpringAOPisthoroughlycoveredintheAOPchapter.

Conceptually,callingamethodonatransactionalproxylookslikethis.

The flowof events is the following.First the set of objects youwould like toapplyAOPtransactionaladvicetoareidentified.Thereareavarietyofwaystoconfigure the Spring IoC container to create proxies for the defined objectdefinitions.ThestandardSpringAOPbasedoptionsare

ProxyFactoryObject. The common properties to set are thereference to the object to proxy (the target object) and a reference to thetransaction advice. SeeSection 13.5, “Using the ProxyFactoryObject to create AOPproxies”formoredetails.

AutoProxy - Defines criteria to select a collection of objects to create atransactionalAOPproxy.

Page 400: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheAutoProxyoptionsare

ObjectNameAutoProxyCreator which specifies acollection of object names based on wildcard matching of objectnames.SeeSection13.9.1.1,“ObjectNameAutoProxyCreator”

DefaultAdvisorAutoProxyCreator which specifiesoneormore"advisors"i.eanobjectrepresentinganaspect, includingboth an advice and a pointcut targeting it to specific joinpoints.SeeSection13.9.1.2,“DefaultAdvisorAutoProxyCreator”

ThereisalsoaconveniencesubclassofProxyFactoryObject,namelyTransactionProxyFactoryObject, that sets some commondefaultvaluesforthespecificcaseofapplyingtransactionaladvice.TheDefaultAdvisorAutoProxyCreator isverypowerfuland isthemeans bywhichSpring can be configured to use attributes to identify thepointcutswheretransactionadviceshouldbeapplied.TheadvisorthatperformsthattaskisTransactionAttributeSourceAdvisor.

Note

Note,thinkoftheword'Attribute'inthisclassnamenotasthe.NETattributebutasthetransaction'options'youwanttospecify.ThisnameisinheritedfromtheJavaversionandthenamewillbechangedintheRC1releasetoavoidconfusionsinceacommonnamingconventionwhencreatingclassesare.NETattributesistoputtheword'Attribute'inthename.

Which one of the many options available should you choose for yourdevelopment?That depends, eachonehas it own set of pro's and con'swhichwillbediscussedinturninthefollowingsections.WiththetransactionalAOPproxynowcreatedwecandiscusstheflowofeventsinthecodeasproxiedmethodsareinvoked.Whenthemethodisinvoked,beforecalling the targetobject'smethod,a transaction is created ifonehasn't alreadybeen created. Then the target method is invoked. If there was an exceptionthrow,thetransactionistypicallyrolledback,butitcanalsobecommittediftheexception typespecified in the transactionoption,NoRollbackFor,matches thethrownexception.Ifnoexceptionwasthrown,thatistakenasasignofsuccessandthetransactioniscommitted.WhenusingotherAOPadvicewiththetransactionaladviceyoucansettheorder

Page 401: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

of the 'interceptor chain' so that, for example, performance monitoring advicealwaysprecedethetransactionaladvice.

17.5.2.AFirstExampleConsiderthefollowinginterface.Theintentistoconveytheconceptstoyousoyou can concentrate on the transaction usage and not have to worry aboutdomain specific details. The ITestObjectManager is a poor-mansbusinessservicelayer-theimplementationofwhichwillmaketwoDAOcalls.Clearly this example is overly simplistic from the service layer perspective asthereisn'tanybusinesslogicatall!.The'service'interfaceisshownbelow.

publicinterfaceITestObjectManager

{

voidSaveTwoTestObjects(TestObjectto1,TestObjectto2);

voidDeleteTwoTestObjects(stringname1,stringname2);

}

TheimplementationofITestObjectManagerisshownbelow

publicclassTestObjectManager:ITestObjectManager

{

//Fields/Propertiesommited

[Transaction()]

publicvoidSaveTwoTestObjects(TestObjectto1,TestObjectto2)

{

TestObjectDao.Create(to1.Name,to1.Age);

TestObjectDao.Create(to2.Name,to1.Age);

}

[Transaction()]

publicvoidDeleteTwoTestObjects(stringname1,stringname2)

{

TestObjectDao.Delete(name1);

TestObjectDao.Delete(name2);

}

}

Page 402: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Note theTransaction attribute on themethods.Other options such as isolationlevel can also be specified but in this example the default settings are used.However,pleasenote that themerepresenceof theTransactionattribute isnotenoughtoactuallyturnonthetransactionalbehavior-theTransactionattributeis simply metadata that can be consumed by something that is Transactionattribute-awareand thatcanuse the saidmetadata toconfigure theappropriateobjectswithtransactionalbehavior.The TestObjectDao property has basic create update delete and findmethod for the 'domain' object TestObject. TestObject in turn has simplepropertieslikenameandage.

publicinterfaceITestObjectDao

{

voidCreate(stringname,intage);

voidUpdate(TestObjectto);

voidDelete(stringname);

TestObjectFindByName(stringname);

IListFindAll();

}

TheCreate andDeletemethod implementation is shownbelow.Note that thisuses theAdoTemplate class discussed in the following chapter. Refer toSection 17.4, “Resource synchronization with transactions” for information on theinteraction between Spring's high level persistence integration APIs andtransactionmanagementfeatures.

publicclassTestObjectDao:AdoDaoSupport,ITestObjectDao

{

publicvoidCreate(stringname,intage)

{

AdoTemplate.ExecuteNonQuery(CommandType.Text,

String.Format("insertintoTestObjects(Age,Name)VALUES({0},'{1}')"

age,name));

}

publicvoidDelete(stringname)

{

AdoTemplate.ExecuteNonQuery(CommandType.Text,

String.Format("deletefromTestObjectswhereName='{0}'"

Page 403: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

name));

}

}

The TestObjectManager is configured with the DAO objects bystandard dependency injection techniques. The client code,which in this casedirectly asks the Spring IoC container for an instance ofITestObjectManager,willreceiveatransactionproxywithtransactionoptions based on the attribute metadata. Note that typically theITestObjectManagerwouldbe set onyet another higher level objectviadependencyinjection,forexampleawebservice.Theclientcallingcodeisshownbelow

IApplicationContextctx=

newXmlApplicationContext("assembly://Spring.Data.Integration.Tests/Spring.Data/autoDeclarativeServices.xml"

ITestObjectManagermgr=ctx["testObjectManager"]asITestObjectManager;

TestObjectto1=newTestObject();

to1.Name="Jack";

to1.Age=7;

TestObjectto2=newTestObject();

to2.Name="Jill";

to2.Age=8;

mgr.SaveTwoTestObjects(to1,to2);

mgr.DeleteTwoTestObjects("Jack","Jill");

Theconfigurationof theobjectdefinitionsof theDAOandmanagerclasses isshownbelow.

<objectsxmlns='http://www.springframework.net'

xmlns:db="http://www.springframework.net/database">

<db:providerid="DbProvider"

provider="SqlServer-1.1"

Page 404: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

connectionString="DataSource=(local);Database=Spring;UserID=springqa;Password=springqa;Trusted_Connection=False"

<objectid="transactionManager"

type="Spring.Data.AdoPlatformTransactionManager,Spring.Data"

<propertyname="DbProvider"ref="DbProvider"/>

</object>

<objectid="adoTemplate"type="Spring.Data.AdoTemplate,Spring.Data"

<propertyname="DbProvider"ref="DbProvider"/>

</object>

<objectid="testObjectDao"type="Spring.Data.TestObjectDao,Spring.Data.Integration.Tests"

<propertyname="AdoTemplate"ref="adoTemplate"/>

</object>

<!--Theobjectthatperformsmultipledataaccessoperations-->

<objectid="testObjectManager"

type="Spring.Data.TestObjectManager,Spring.Data.Integration.Tests"

<propertyname="TestObjectDao"ref="testObjectDao"/>

</object>

</objects>

This is standard Spring configuration and as such provides you with theflexibility to parameterize your connection string and to easily switchimplementations of your DAO objects. The configuration to create atransactionalproxyforthemanagerclassisshownbelow.

<!--Therestoftheconfigfileiscommonnomatterhowmanyobjectsyouadd-->

<!--thatyouwouldliketohavedeclarativetxmanagementappliedto-->

<objectid="autoProxyCreator"

type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator,Spring.Aop"

</object>

<objectid="transactionAdvisor"

type="Spring.Transaction.Interceptor.TransactionAttributeSourceAdvisor,Spring.Data"

<propertyname="TransactionInterceptor"ref="transactionInterceptor"

</object>

Page 405: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--TransactionInterceptor-->

<objectid="transactionInterceptor"

type="Spring.Transaction.Interceptor.TransactionInterceptor,Spring.Data"

<propertyname="TransactionManager"ref="transactionManager"

<propertyname="TransactionAttributeSource"ref="attributeTransactionAttributeSource"

</object>

<objectid="attributeTransactionAttributeSource"

type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource,Spring.Data"

</object>

Grantedthisisabitverboseandhardtogrokatfirstsight-howeveryouonlyneedtogrokthisonceasitis 'boilerplate'XMLyoucanreuseacrossmultipleprojects.WhattheseobjectdefinitionsaredoingistoinstructSpring'stolookforallobjectswithintheIoCconfigurationthathavethe[Transaction]attributeandthen apply the AOP transaction interceptor to them based on the transactionoptionscontainedintheattribute.Theattributeservesbothasapointcutandasthedeclarationoftransactionaloptioninformation.Since thisXMLfragment isnot tied toanyspecificobject referencesitcanbeincludedinitsownfileandthenimportedviathe<import>element.Inexamplesand test code this XML configuration fragment is namedautoDeclarativeServices.xml See Section 5.2.2.1, “Composing XML-based configurationmetadata”formoreinformation.Theclassesandtheirrolesinthisconfigurationfragmentarelistedbelow

TransactionInterceptor is the AOP advice responsible forperformingtransactionmanagementfunctionality.

TransactionAttributeSourceAdvisor is an AOPAdvisor that holds the TransactionInterceptor,which is the advice, and apointcut (where to apply the advice), in the form of aTransactionAttributeSource.

AttributesTransactionAttributeSource is animplementation of the ITransactionAttributeSource

interface that defines where to get the transaction metadata defining thetransactionsemantics(isolationlevel,propagationbehavior,etc)thatshouldbeappliedtospecificmethodsofspecificclasses.Thetransactionmetadata

Page 406: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

is specified via implementations of theITransactionAttributeSource interface. This exampleshows the use of the implementationSpring.Transaction.Interceptor.AttributesTransactionAttributeSource

toobtainthatinformationfromstandard.NETattributes.Bytheverynatureof using standard .NET attributes, the attribute serves double duty inidentifyingthemethodswherethetransactionsemanticsapply.AlternativeimplementationsofITransactionAttributeSourceavailableare MatchAlwaysTransactionAttributeSource,NameMatchTransactionAttributeSource, orMethodMapTransactionAttributeSource.

MatchAlwaysTransactionAttributeSource isconfiguredwitha ITransactionAttribute instance that isapplied toallmethods. The shorthand string representation, i.e.PROPAGATION_REQUIREDcanbeused

AttributesTransactionAttributeSource : Use astandard..NETattributestospecifythetransactionalinformation.SeeTransactionAttributeclassformoreinformation.

NameMatchTransactionAttributeSource allowsITransactionAttributestobematchedbymethodname.TheNameMapIDictionarypropertyisusedtospecifythemapping.Forexample

<objectname="nameMatchTxAttributeSource"type="Spring.Transaction.Interceptor.NameMatchTransactionAttributeSource,Spring.Data"

<propertyname="NameMap">

<dictionary>

<entrykey="Execute"value="PROPAGATION_REQUIRES_NEW,-ApplicationException"

<entrykey="HandleData"value="PROPAGATION_REQUIRED,-DataHandlerException"

<entrykey="Find*"value="ISOLATION_READUNCOMMITTED,-DataHandlerException"

</dictionary>

</property>

</object>

Keyvaluescanbeprefixedand/orsuffixedwithwildcardsaswellasincludethefullnamespaceofthecontainingclass.

MethodMapTransactionAttributeSource : Similar

Page 407: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

toNameMatchTransactionAttributeSourcebutspecifiesthatonlyfullyqualified method names (i.e. type.method, assembly) and wildcardscan be used at the start or end of the method name for matchingmultiplemethods.

DefaultAdvisorAutoProxyCreator: looks for Advisors inthe context, and automatically creates proxy objects which are thetransactionalwrappers

Refer to the following section foramoreconvenientway toachieve thesamegoalofdeclarativetransactionmanagementusingattributes.

17.5.3. Declarative transactions using the transactionnamespaceSpring provides a custom XML schema to simplify the configuration ofdeclarative transaction management. If you would like to perform attributedriventransactionmanagementyoufirstneedtoregisterthecustomnamespaceparser for the transaction namespace. This can be done in the applicationconfigurationfileasshownbelow

<?xmlversion="1.0"encoding="utf-8"?>

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

<!--otherspringconfigsectionslikecontext,typeAliases,etcnotshownforbrevity-->

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Data.Config.DatabaseNamespaceParser,Spring.Data"

<parsertype="Spring.Transaction.Config.TxNamespaceParser,Spring.Data"

<parsertype="Spring.Aop.Config.AopNamespaceParser,Spring.Aop"

</parsers>

Page 408: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</spring>

</configSections>

InsteadofusingtheXMLconfigurationlistedattheendoftheprevioussection(declarativeServices.xml you can use the following. Note that theschemaLocationintheobjectselementisneededonlyifyouhavenotinstalledSpring's schema into the proper VS.NET 2005 location. See the chapter onVS.NETintegrationformoredetails.

<objectsxmlns="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"

xsi:schemaLocation="http://www.springframework.nethttp://www.springframework.net/schema/objects/spring-objects.xsd

http://www.springframework.net/schema/txhttp://www.springframework.net/schema/tx/spring-tx-1.1.xsd"

http://www.springframework.net/schema/dbhttp://www.springframework.net/schema/db/spring-database.xsd">

<db:providerid="DbProvider"

provider="SqlServer-1.1"

connectionString="DataSource=(local);Database=Spring;UserID=springqa;Password=springqa;Trusted_Connection=False"

<objectid="transactionManager"

type="Spring.Data.AdoPlatformTransactionManager,Spring.Data"

<propertyname="DbProvider"ref="DbProvider"/>

</object>

<objectid="adoTemplate"type="Spring.Data.AdoTemplate,Spring.Data"

<propertyname="DbProvider"ref="DbProvider"/>

</object>

<objectid="testObjectDao"type="Spring.Data.TestObjectDao,Spring.Data.Integration.Tests"

<propertyname="AdoTemplate"ref="adoTemplate"/>

</object>

<!--Theobjectthatperformsmultipledataaccessoperations-->

<objectid="testObjectManager"

type="Spring.Data.TestObjectManager,Spring.Data.Integration.Tests"

<propertyname="TestObjectDao"ref="testObjectDao"/>

Page 409: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</object>

<tx:attribute-driventransaction-manager="transactionManager"

</objects>

Tip

Youcanactuallyomitthe'transaction-manager'attributeinthe<tx:attribute-driven/>tagiftheobjectnameoftheIPlatformTransactionManagerthatyouwanttowireinhasthename'transactionManager'.IfthePlatformTransactionManagerobjectthatyouwanttodependencyinjecthasanyothername,thenyouhavetobeexplicitandusethe'transaction-manager'attributeasintheexampleabove.

Thevariousoptionalelementsof the<tx:attribute-driven/> tagaresummarisedinthefollowingtable

Table17.1.<tx:annotation-driven/>settings

Attribute Required? Default Description

transaction-

managerNo transactionManager

Thenameoftransactionmanagertouse.OnlyrequiredifthenameofthetransactionmanagerisnottransactionManager,asintheexampleabove.

proxy-

target-typeNo

Controlswhattypeoftransactionalproxiesarecreatedforclassesannotatedwiththe[Transaction]attribute.If"proxy-target-type"attributeissetto"true",thenclass-basedproxieswillbecreated(proxyinheritsfromtargetclass,howevercallsarestilldelegatedtotargetobjectviacomposition.Thisallowsforcastingtobaseclass.If"proxy-target-type"is"false"oriftheattributeisomitted,thenapurecompositionbasedproxyiscreatedandyoucanonlycasttheproxyto

Page 410: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

implementedinterfaces.(SeethesectionentitledSection13.6,“Proxyingmechanisms”foradetailedexaminationofthedifferentproxytypes.)

order No

Definestheorderofthetransactionadvicethatwillbeappliedtoobjectsannotatedwith[Transaction].MoreontherulesrelatedtoorderingofAOPadvicecanbefoundintheAOPchapter(seesectionSection13.3.2.5,“AdviceOrdering”).NotethatnotspecifyinganyorderingwillleavethedecisionastowhatorderadviceisrunintotheAOPsubsystem.

Note

The"proxy-target-type"attributeonthe<tx:attribute-driven/>elementcontrolswhattypeoftransactionalproxiesarecreatedforclassesannotatedwiththeTransactionattribute.If"proxy-target-type"attributeissetto"true",theninheritance-basedproxieswillbecreated.If"proxy-target-type"is"false"oriftheattributeisomitted,thencompositionbasedproxieswillbecreated.(SeethesectionentitledSection13.6,“Proxyingmechanisms”foradetailedexaminationofthedifferentproxytypes.)

Youcanalsodefine the transactional semanticsyouwant toapply through theuse of a <tx:advice> definition. This lets you define the transactionmetadatasuch as propagation and isolation level aswell as themethods forwhich thatmetadata applies external to the code unlike the case of using the transactionattribute. The <tx:advice> definition creates an instance of aITransactionAttributeSourceduringparsing time.Switching touse<tx:advice>insteadof<tx:attribute-driven/>intheexamplewouldlooklikethefollowing

<tx:adviceid="txAdvice"transaction-manager="transactionManager"

<tx:attributes>

<tx:methodname="Save*"/>

<tx:methodname="Delete*"/>

Page 411: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</tx:attributes>

</tx:advice>

ThissaysthatallmethodsthatstartwithSaveandDeletewouldhaveassociatedwiththemthedefaultsettingsoftransactionmetadata.Thesedefaultvaluesarelistedbelow..Hereisanexampleusingotherelementsofthe<tx:method/>definition

<!--thetransactionaladvice(i.e.what'happens';seethe<aop:advisor/>objectbelow)-->

<tx:adviceid="txAdvice"transaction-manager="transactionManager"

<!--thetransactionalsemantics...-->

<tx:attributes>

<!--allmethodsstartingwith'get'areread-only-->

<tx:methodname="Get*"read-only="true"/>

<!--othermethodsusethedefaulttransactionsettings(seebelow)-->

<tx:methodname="*"/>

</tx:attributes>

</tx:advice>

The<tx:advice/>definitionreadsas“...allmethodsonstartingwith'Get'aretoexecute in the contextof a read-only transaction, and all othermethods are toexecute with the default transaction semantics”. The 'transaction-manager'attribute of the <tx:advice/> tag is set to the name of thePlatformTransactionManager object that is going to actually drive thetransactions(inthiscasethe'transactionManager'object).You can alsouse theAOPnamespace<aop:advisor> element to tie together apointcutandtheabovedefinedadviceasshownbelow.

<objectid="serviceOperation"type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut,Spring.Aop"

<propertyname="pattern"value="Spring.TxQuickStart.Services.*"

</object>

<aop:config>

<aop:advisorpointcut-ref="serviceOperation"advice-ref=

</aop:config>

This is assuming that the service layer class, TestObjectManager, in the

Page 412: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

namespaceSpring.TxQuickStart.Services.The<aop:config/>definitionensuresthatthetransactionaladvicedefinedbythe'txAdvice'objectactuallyexecutesatthe appropriate points in the program. Firstwe define a pointcut thatmatchesanyoperationdefinedonclasses in theSpring.TxQuickStart.Services (youcanbemore selective in your regular expression). Thenwe associate the pointcutwiththe 'txAdvice'usinganadvisor.Intheexample,theresultindicatesthatattheexecutionofa 'SaveTwoTestObjects'and 'DeleteTwoTestObject', theadvicedefinedby'txAdvice'willberun.The various transactional settings that can be specified using the <tx:advice/>tag.Thedefault<tx:advice/>settingsarelistedbelowandarethesameaswhenyouusetheTransactionattribute.

The propagation setting isTransactionPropagation.Required

TheisolationlevelisIsolationLevel.ReadCommitted

Thetransactionisread/write

The transaction timeout defaults to the default timeout of the underlyingtransactionsystem,ornoneiftimeoutsarenotsupported

EnterpriseServicesInteropOption (.NET 2.0 only withTxScopeTransactionManager) - options between transaction created withSystem.TransactionsandtransactionscreatedthroughCOM+

Anyexceptionwilltriggerrollback.These default settings can be changed; the various attributes of the<tx:method/> tags that are nested within <tx:advice/> and<tx:attributes/>tagsaresummarizedbelow:

Table17.2.<tx:method/>settings

Attribute Required? Default

name Yes

Themethodname(s)withwhichthetransactionassociated.Thewildcard(*)charactertransactionattribute'Get*'

propagation No Required Thetransactionpropagationbehavior

No ReadCommitted Thetransactionisolationlevel

Page 413: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

isolation

timeout No -1 Thetransactiontimeoutvalue(inseconds)

read-only No false Isthistransactionread-only?

EnterpriseServicesInteropOption No None InteroperabilityoptionswithCOM+transactions.(.NETTxScopeTransactionManageronly)

rollback-for No TheException(s)example,'MyProduct.MyBusinessException,ValidationException'

no-rollback-for No TheException(s)example,'MyProduct.MyBusinessException,ValidationException'

17.5.4.TransactionattributesettingsTheTransactionattributeismetadatathatspecifiesthataclassormethodmusthavetransactionalsemantics.ThedefaultTransactionattributesettingsare

The propagation setting isTransactionPropagation.Required

TheisolationlevelisIsolationLevel.ReadCommitted

Thetransactionisread/write

The transaction timeout defaults to the default timeout of the underlyingtransactionsystem,ornoneiftimeoutsarenotsupported

EnterpriseServicesInteropOption (.NET 2.0 only withTxScopeTransactionManager) - options between transaction created withSystem.TransactionsandtransactionscreatedthroughCOM+

Anyexceptionwilltriggerrollback.The default settings can, of course, be changed; the various properties of theTransactionattributearesummarisedinthefollowingtable

Table17.3.Transactionattributeproperties

Page 414: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Property Type

TransactionPropagationenumeration,Spring.Transaction.TransactionPropagation

Isolation System.Data.IsolationLevel

ReadOnly boolean

EnterpriseServicesInteropOption enumerationSystem.Transactions.EnterpriseServicesInteropOption

Timeout int(insecondsgranularity)

RollbackFor anarrayofTypeobjects

NoRollbackFor anarrayofTypeobjects

Note that setting the TransactionPropagation to Nested will throw aNestedTransactionNotSupportedException in a case where an actual nestedtransactionoccurs,i.e.notinthecaseofapplyingtheNestedpropagationbutinfactnonestedcallsaremade.Thiswillbe fixed for theSpring1.2 release forSqlServer and Oracle which support nested transactions. Also note, thatchanging of isolation levels on a per-method basis is also scheduled for theSpring 1.2 release since it requires detailed command text metadata for eachdbprovider. Please check the forums for news on when this feature will beintroducedintothenightlybuilds.If you specify an exception type for 'NoRollbackFor' the action taken is tocommit thework thathasbeendone in thedatabaseup to thepointwhere theexceptionoccurred.Theexceptionisstillpropagatedouttothecallingcode.

Page 415: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheReadOnly boolean is a hint to the data access technology to enable read-only optimizations. This currently has no effect in Spring's ADO.NETframework. If youwould like to enable read-only optimizations inADO.NETthisisgenerallydoneviathe'Mode=Read'or'Mode=Read-Only"optionsintheconnection string. Check your database provider formore information. In thecaseofNHibernatetheflushmodeissettoNeverwhenanewSessioniscreatedforthetransaction.Throwing exceptions to indicate failure and assuming success is an easierandless invasive programming model than performing the same taskProgramatically - ContextUtil.MyTransactionVote orTransactionScope.Complete.The rollbackoptionsareameans to influence theoutcome of the transaction based on the exception type which adds an extradegreeofflexibility.Having any exception trigger a rollback has similar behavior as applying theAutoComplete attribute available when using .NET Enterprise Services. ThedifferencewithAutoCompleteisthatusingAutoCompleteisalsocoupledtothelifetimeoftheServicedComponentsinceitsetsContextUtil.DeactivateOnReturnto true.For a statelessDAO layer this is not an issue but it could be in otherscenarios. Spring's transactional aspect does not affect the lifetime of yourobject.

17.5.5.DeclarativeTransactionsusingAutoProxyif you choose not to use the transaction namespace for declarative transactionmanagement then you can use 'lower level' object definitions to configuredeclarativetransactions.Thisapproachwasshowninthefirstexample.TheuseofSpring'sautoproxyfunctionalitydefinescriteriatoselectacollectionofobjectstocreatea transactionalAOPproxy.TherearetwoAutoProxyclassesthatyoucan use, ObjectNameAutoProxyCreator andDefaultAdvisorAutoProxyCreator. If you are using the newtransactionnamespacesupportyoudonotneed toconfigure theseobjectsasaDefaultAdvisorAutoProxyCreatoriscreated'underthecovers'whileparsingthetransactionnamespaceelements

17.5.5.1. Creating transactional proxies withObjectNameAutoProxyCreatorThe ObjectNameAutoProxyCreator is useful when you would like to create

Page 416: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

transactional proxies for many objects. The definitions for theTransactionInterceptor and associated attributes is done once. When you addnewobjectstoyourconfigurationfilethatneedtobeproxiesyouonlyneedtoadd them to the list ofobject referenced in theObjectNameAutoProxyCreator.Here is an example showing its use. Look in the section that useProxyFactoryObjectforthedeclarationofthetransactionInterceptor.

<objectname="autoProxyCreator"

type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator,Spring.Aop"

<propertyname="InterceptorNames"value="transactionInterceptor"

<propertyname="ObjectNames">

<list>

<idreflocal="testObjectManager"/>

</list>

</property>

</object>

17.5.5.2. Creating transactional proxies withDefaultAdvisorAutoProxyCreatorThis is a commonly used way to configure declarative transactions since itenables you to refer to the transaction attribute as the pointcut to use for thetransactional advice for anyobject definition defined in the IoC container.AnexampleofthisconfigurationapproachwasshowninChapter5.

17.5.6. Declarative Transactions usingTransactionProxyFactoryObjectTheTransactionProxyFactoryObject iseasier touse thanaProxyFactoryObjectfor most cases since the transaction interceptor and transaction attributes areproperties of this object. This removes the need to declare them as separateobjects.Also,unlikethecasewiththeProxyFactoryObject,youdonothavetogive fully qualifiedmethod names, just the normal 'short'method name.Wildcardmatchingon themethodname isalsoallowed,which inpracticehelps toenforce a common naming convention for the methods of your DAOs. Theexamplefromchapter5isshownhereusingaTransactionProxyFactoryObject.

<objectid="testObjectManager"

Page 417: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject,Spring.Data"

<propertyname="PlatformTransactionManager"ref="adoTransactionManager"

<propertyname="Target">

<objecttype="Spring.Data.TestObjectManager,Spring.Data.Integration.Tests"

<propertyname="TestObjectDao"ref="testObjectDao"

</object>

</property>

<propertyname="TransactionAttributes">

<name-values>

<addkey="Save*"value="PROPAGATION_REQUIRED"

<addkey="Delete*"value="PROPAGATION_REQUIRED"

</name-values>

</property>

</object>

Note the use of an inner object definition for the target which will make itimpossibletoobtainanunproxiedreferencetotheTestObjectManager.Ascanbeseenintheabovedefinition,theTransactionAttributespropertyholdsacollectionofname/valuepairs.Thekeyofeachpairisamethodormethods(a*wildcardendingisoptional)toapplytransactionalsemanticsto.Notethatthemethod name is not qualified with a package name, but rather is consideredrelativetotheclassofthetargetobjectbeingwrapped.Thevalueportionofthename/valuepairistheTransactionAttributeitselfthatneedstobeapplied.Whenspecifyingitasastringvalueasinthisexample,it'sinStringformatasdefinedbyTransactionAttributeConverter.Thisformatis:PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-

Exception2

Notethattheonlymandatoryportionofthestringisthepropagationsetting.Thedefaulttransactionssemanticswhichapplyareasfollows:

ExceptionHandling:Allexceptionsthrowntriggerarollback.

Transactionsareread/write

IsolationLevel:TransactionDefinition.ISOLATION_DEFAULT

Timeout:TransactionDefinition.TIMEOUT_DEFAULTMultiple rollback rules can be specified here, comma-separated. A - prefix

Page 418: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

forcesrollback;a+prefixspecifiescommit.UnderthecoverstheIDictionaryofname value pairs will be converted to an instance ofNameMatchTransactionAttributeSource

The string used for PROPAGATION_NAME are those defined on theSpring.Transaction.TransactionPropagation enumeration, namely Required,Supports, Mandatory, RequiresNew, NotSupported, Never, Nested. The stringused for ISOLATION_NAME are those defined on theSystem.Data.IsolationLevel enumberateion, namely ReadCommitted,ReadUncommitted,RepeatableRead,Serializable.TheTransactionProxyFactoryObjectallowsyoutosetoptional"pre"and"post"advice, for additional interception behavior, using the "PreInterceptors" and"PostInterceptors" properties.Any number of pre and post advices can be set,and their type may be Advisor (in which case they can contain a pointcut),MethodInterceptor or any advice type supported by the current Springconfiguration (suchasThrowsAdvice,AfterReturningAdviceorBeforeAdvice,whicharesupportedbydefault.)Theseadvicesmustsupportashared-instancemodel.IfyouneedtransactionalproxyingwithadvancedAOPfeaturessuchasstatefulmixins,it'snormallybesttousethegenericProxyFactoryObject,ratherthantheTransactionProxyFactoryObjectconvenienceproxycreator.

17.5.7.ConciseproxydefinitionsUsing abstract object definitions in conjunction with aTransactionProxyFactoryObject provides you a more concise means to reusecommonconfigurationinformationinsteadofduplicatingitoverandoveragainwithadefinitionofaTransactionProxyFactoryObjectperobject.Objectsthataretobeproxied typicallyhave the samepatternofmethodnames,Save*,Find*,etc.Thiscommonalitycanbeplacedinanabstractobjectdefinition,whichotherobjectdefinitionsrefertoandchangeonlytheconfigurationinformationthatisdifferent.Anabstractobjectdefinitionisshownbelow

<objectid="txProxyTemplate"abstract="true"

type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject,Spring.Data"

<propertyname="PlatformTransactionManager"ref="adoTransactionManager"

<propertyname="TransactionAttributes">

<name-values>

Page 419: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<addkey="Save*"value="PROPAGATION_REQUIRED"

<addkey="Delete*"value="PROPAGATION_REQUIRED"

</name-values>

</property>

</object>

Subsequentdefinitionscanrefertothis'base'configurationasshownbelow

<objectid="testObjectManager"parent="txProxyTemplate">

<propertyname="Target">

<objecttype="Spring.Data.TestObjectManager,Spring.Data.Integration.Tests"

<propertyname="TestObjectDao"ref="testObjectDao"

</object>

</property>

</object>

17.5.8.DeclarativeTransactionsusingProxyFactoryObjectUsingthegeneralProxyFactoryObjecttodeclaretransactionsgivesyouagreatdealofcontrolover theproxycreatedsinceyoucanspecifyadditionaladvice,suchasfor loggingorperformance.BasedontheexampleshownpreviouslyasampleconfigurationusingProxyFactoryObjectisshownbelow

<objectid="testObjectManagerTarget"type="Spring.Data.TestObjectManager,Spring.Data.Integration.Tests"

<propertyname="TestObjectDao"ref="testObjectDao"/>

</object>

<objectid="testObjectManager"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="Target"ref="testObjectManagerTarget"

<propertyname="ProxyInterfaces">

<value>Spring.Data.ITestObjectManager</value>

</property>

<propertyname="InterceptorNames">

<value>transactionInterceptor</value>

</property>

</object>

The ProxyFactoryObject will create a proxy for the Target, i.e. a

Page 420: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TestObjectManager instance. An inner object definition could also have beenusedsuch that itwouldmake it impossible toobtainanunproxiedobject fromthecontainer.Theinterceptornamereferstothefollowingdefinition.

<objectid="transactionInterceptor"type="Spring.Transaction.Interceptor.TransactionInterceptor,Spring.Data"

<propertyname="TransactionManager"ref="adoTransactionManager"

<!--notedonothaveconverterfromstringtothispropertytyperegistered-->

<propertyname="TransactionAttributeSource"ref="methodMapTransactionAttributeSource"

</object>

<objectname="methodMapTransactionAttributeSource"

type="Spring.Transaction.Interceptor.MethodMapTransactionAttributeSource,Spring.Data"

<propertyname="MethodMap">

<dictionary>

<entrykey="Spring.Data.TestObjectManager.SaveTwoTestObjects,Spring.Data.Integration.Tests"

value="PROPAGATION_REQUIRED"/>

<entrykey="Spring.Data.TestObjectManager.DeleteTwoTestObjects,Spring.Data.Integration.Tests"

value="PROPAGATION_REQUIRED"/>

</dictionary>

</property>

</object>

The transaction options for each method are specified using a dictionarycontainingtheclassname+methodname,assemblyasthekeyandthevalueisoftheform

<Propagation Behavior>, <Isolation Level>, <ReadOnly>, -Exception,+Exception

Allbut thepropagationbehaviorareoptional.The+and-areused in frontofthenameofanexception.Minusindicatestorollbackiftheexceptionisthrown,thePlusindicatestocommitiftheexceptionisthrown.

Page 421: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.6.ProgrammatictransactionmanagementSpringprovidestwomeansofprogrammatictransactionmanagement:

UsingtheTransactionTemplate

Using a IPlatformTransactionManager implementationdirectly

ThesearelocatedintheSpring.Transaction.Supportnamespace.Ifyouaregoingto use programmatic transaction management, the Spring team generallyrecommendsthefirstapproach(i.e.UsingtheTransactionTemplate)

17.6.1.UsingtheTransactionTemplateThe TransactionTemplate adopts the same approach as other Spring templatessuchasAdoTemplateandHibernateTemplate. Itusesacallbackapproach,tofreeapplicationcodefromhavingtodotheboilerplateacquisitionandreleaseofresources,andresults incodethat is intentiondriven, inthatthecode that iswrittenfocusessolelyonwhat thedeveloperwants todo.GrantedthattheusingconstructofSystem.Transactionalleviatesmuchofthis.Onekeydifference with the approach taken with the TransactionTemplate is that acommitisassumed-throwinganexceptiontriggersarollbackinsteadofusingtheTransactionScopeAPItocommitorrollback.Thisalsoallowsfortheuseofrollbackrules,thatisacommitcanstilloccurforexceptionsofcertaintypes.

Note

Asyouwillimmediatelyseeintheexamplesthatfollow,usingtheTransactionTemplateabsolutelycouplesyoutoSpring'stransactioninfrastructureandAPIs.Whetherornotprogrammatictransactionmanagementissuitableforyourdevelopmentneedsisadecisionthatyouwillhavetomakeyourself.

Applicationcodethatmustexecuteinatransactioncontextlookslikethis.You,as an application developer,willwrite a ITransactionCallback implementation(typicallyexpressedasananonymousdelegate)thatwillcontainallofthecodethatyouneedtohaveexecuteinthecontextofatransaction.Youwillthenpassan instance of your custom ITransactionCallback to the Execute(..) methodexposed on the TransactionTemplate. Note that theITransactionCallbackcanbeusedtoreturnavalue:

Page 422: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassSimpleService:IService

{

privateTransactionTemplatetransactionTemplate;

publicSimpleService(IPlatformTransactionManagertransactionManager)

{

AssertUtils.ArgumentNotNull(transactionManager,"transactionManager"

transactionTemplate=newTransactionTemplate(transactionManager);

}

publicobjectSomeServiceMethod()

{

returntt.Execute(delegate{

UpdateOperation(userId);

returnResultOfUpdateOperation2();

});

}

}

This code example is specific to .NET2.0 since it uses anonymous delegates,which provides a particularly elegant means to invoke a callback function aslocalvariablescanbereferredtoinsidethedelegate,i.e.userId.InthiscasetheITransactionStatus was not exposed in the delegate (delegate caninfer the signature to use), but one could also obtain a reference to theITransactionStatus instance and set the RollbackOnlypropertytotriggerarollback-oralternativelythrowanexception.Thisisshownbelow

tt.Execute(delegate(ITransactionStatusstatus)

{

try{

UpdateOperation1();

UpdateOperation2();

}catch(SomeBusinessExceptionex){

status.RollbackOnly=true;

}

returnnull;

});

Ifyouareusing.NET1.1thenyoushouldprovideanormaldelegate reference

Page 423: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

oraninstanceofaclassthatimplementstheITransactionCallbackinterface.Thisisshownbelow

tt.Execute(newTransactionRollbackTxCallback(amount));

publicclassTransactionRollbackTxCallback:ITransactionCallback

{

privatedecimalamount;

publicTransactionRollbackTxCallback(decimalamount)

{

this.amount=amount

}

publicobjectDoInTransaction(ITransactionStatusstatus)

{

adoTemplate.ExecuteNonQuery(CommandType.Text,"insertintodbo.Debits(DebitAmount)VALUES(@amount)"

//decideyouneedtorollback...

status.RollbackOnly=true;

returnnull;

}

}

Application classes wishing to use the TransactionTemplate musthave access to a IPlatformTransactionManager (which willtypicallybesuppliedtotheclassviadependencyinjection).ItiseasytounittestsuchclasseswithamockorstubIPlatformTransactionManager.

17.6.1.1.SpecifyingtransactionsettingsTransaction settings such as the propagation mode, the isolation level, thetimeout, and so forth can be set on theTransactionTemplate eitherprogrammaticallyorinconfiguration.TransactionTemplateinstancesby default have the default transactional settings. Find below an example ofprogrammatically customizing the transactional settings for a specificTransactionTemplate.

publicclassSimpleService:IService

{

Page 424: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

privateTransactionTemplatetransactionTemplate;

publicSimpleService(IPlatformTransactionManagertransactionManager)

{

AssertUtils.ArgumentNotNull(transactionManager,"transactionManager"

transactionTemplate=newTransactionTemplate(transactionManager);

//thetransactionsettingscanbesethereexplicitlyifsodesired

transactionTemplate.TransactionIsolationLevel=IsolationLevel.ReadUncommitted;

transactionTemplate.TransactionTimeout=30;

//andsoforth...

}

...

}

FindbelowanexampleofdefiningaTransactionTemplatewithsomecustom transactional settings, using Spring XML configuration. The'sharedTransactionTemplate' can then be injected into as manyservicesasarerequired.

<objectid="sharedTransactionTemplate"

type="Spring.Transaction.Support.TransactionTemplate,Sprng.Data"

<propertyname="TransactionIsolationLevel"value="IsolationLevel.ReadUncommitted"

<propertyname="TransactionTimeout"value="30"/>

</object>

Finally,instancesoftheTransactionTemplateclassarethreadsafe,inthat instances do not maintain any conversational state.TransactionTemplate instances do however maintain configurationstate, sowhileanumberofclassesmaychoose to sharea single instanceofaTransactionTemplate, if a class needed to use aTransactionTemplatewithdifferentsettings(forexample,adifferentisolation level), then two distinct TransactionTemplate instanceswouldneedtobecreatedandused.

Page 425: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.6.2.UsingthePlatformTransactionManagerYou can also use the PlatformTransactionManager directly to manage yourtransaction.SimplypasstheimplementationofthePlatformTransactionManageryou'reusingtoyourobjectviaaobjectreferencethroughstandardDependencyInjection techniques. Then, using the TransactionDefinition andITransactionStatusobjects,youcaninitiatetransactions,rollbackandcommit.

DefaultTransactionDefinitiondef=newDefaultTransactionDefinition();

def.PropagationBehavior=TransactionPropagation.Required;

ITransactionStatusstatus=transactionManager.GetTransaction(def);

try

{

//executeyourbusinesslogichere

}catch(Exceptione)

{

transactionManager.Rollback(status);

throw;

}

transactionManager.Commit(status);

Note that a corresponding 'using TransactionManagerScope' class can bemodeledtogetsimilarAPIusagetoSystem.TransactionsTransactionScope.

Page 426: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.7. Choosing between programmatic and declarativetransactionmanagementProgrammatictransactionmanagementisusuallyagoodideaonlyifyouhaveasmall number of transactional operations. For example, if you have a webapplicationthatrequiretransactionsonlyforcertainupdateoperations,youmaynotwanttosetuptransactionalproxiesusingSpringoranyothertechnology.Inthiscase,usingtheTransactionTemplatemaybeagoodapproach.Ontheotherhand, if your application has numerous transactional operations, declarativetransactionmanagementisusuallyworthwhile.Itkeepstransactionmanagementoutofbusinesslogic,andisnotdifficulttoconfigureinSpring.

Page 427: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

17.8.TransactionlifecycleandstatusinformationYou can query the status of the current Spring managed transaction with theclass TransactionSynchronizationManager. Typicalapplicationcodeshouldnotneedtorelyonusingthisclassbutinsomecasesitisconvenienttoreceiveeventsaroundthelifecycleofthetransaction,i.e.beforecommitting, after committing.TransactionSynchronizationManager provides a method toregister a callback object that is informed on all significant stages in thetransaction lifecycle. Note that you can register for lifecycle call backinformation for any of the transactionmanagers you use, be it NHibernate orlocalADO.NETtransactions.The method to register a callback with theTransactionSynchronizationManageris

publicstaticvoidRegisterSynchronization(ITransactionSynchronizationsynchronization)

PleaserefertotheSDKdocsforinformationonothermethodsinthisclass.TheITransactionSynchronizationinterfaceis

publicinterfaceITransactionSynchronization

{

//TypicallyusedbySpringresourcemanagementcode

voidSuspend();

voidResume();

//Transactionlifeycylecallbackmethods

//TypicallyusedbySpringresourcemanagementcodebutmaybeusefulincertaincasestoapplicationcode

voidBeforeCommit(boolreadOnly);

voidAfterCommit();

voidBeforeCompletion();

voidAfterCompletion(TransactionSynchronizationStatusstatus);

}

TheTransactionSynchronizationStatus isanenumwith thevaluesCommitted,Rolledback,andUnknown.

Page 428: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter18.DAOsupport

Page 429: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

18.1.IntroductionSpring promotes the use of data access interfaces in your applicationarchitecture.These interfaces encapsulate the storage and retrieval of data andobjects specific to your business domain without reference to a specificpersistence API. Within a layered architecture, the service layer is typicallyresponsible for coordinating responses to a particular business request and itdelegatesanypersistencerelatedactivities toobjects that implement thesedataaccess interfaces. These objects are commonly referred to as DAOs (DataAccessObjects)andthearchitecturallayerasaDAL(DataAccessLayer).ThebenefitsofusingDAOsinyourapplicationareincreasedportabilityacrosspersistence technology and ease of testing. Testing is more easily facilitatedbecauseamockorstubimplementationofthedataaccessinterfacecanbeeasilycreatedinaNUnit testso thatservice layerfunctionalitycanbetestedwithoutanydependencyonthedatabase.Thisisbeneficialbecauseteststhatrelyonthedatabaseareusuallyhard to setupand teardownandalso are impractical fortestingexceptionalbehavior.TheDataAccessObject(DAO)supportinSpringisaimedatmakingiteasy towork with data access technologies like ADO.NET and NHibernate in astandardizedway. Spring provides two central pieces of functionality tomeetthisgoal.ThefirstisprovidingacommonexceptionhierarchyacrossprovidersandthesecondisprovidingbaseDAOsclassesthatraisethelevelofabstractionwhen performing common ADO.NET operations. This allows one to switchbetween the aforementioned persistence technologies fairly easily and it alsoallowsonetocodewithoutworryingaboutcatchingexceptionsthatarespecifictoeachtechnology.

Page 430: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

18.2.ConsistentexceptionhierarchyDatabaseexceptions in theADO.NETAPIarenotconsistentacrossproviders.The .NET 1.1 BCL did not provide a common base class for ADO.NETexceptions. As such you were required to handle exceptions specific to eachprovider such as System.Data.SqlClient.SqlException orSystem.Data.OracleClient.OracleException. The .NET2.0 BCL improved in this regard by introducing a common base class forexceptions, System.Data.Common.DbException. However thecommonDbExceptionisnotveryportableeitherasitprovidesavendorspecificerrorcodeas theunderlyingpieceof informationas towhatwentwrong.Thiserrorcodeisdifferentacrossprovidersforthesameconceptualerror,suchasaviolationofdataintegrityorprovidingbadSQLgrammar.To promote writing portable and descriptive exception handling code Springprovides a convenient translation from technology specific exceptions likeSystem.Data.SqlClient.SqlException orSystem.Data.OracleClient.OracleException to its ownexceptionhierarchywiththeSpring.Dao.DataAccessExceptionas therootexception.Theseexceptionswrap theoriginalexceptionso there isneveranyriskthatonemightloseanyinformationastowhatmighthavegonewrong.In addition to exceptions from ADO.NET providers, Spring can also wrapNHibernate-specific exceptions.. This allows one to handle most persistenceexceptions,which are non-recoverable, only in the appropriate layers,withoutboilerplate using or catch and throw blocks, and exception declarations. Asmentioned above, ADO.NET exceptions (including database-specific dialects)are also converted to the samehierarchy,meaning that one can perform someoperationswithADO.NETwithinaconsistentprogrammingmodel.Theaboveholds true for the various template-based versions of the ORM accessframework.TheexceptionhierarchythatSpringusesisoutlinedinthefollowingimage:

Page 431: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

(Pleasenote that theclasshierarchydetailed in theabove image showsonlyasubsetofthewhole,rich,DataAccessExceptionhierarchy.)TheexceptiontranslationfunctionalityisinthenamespaceSpring.Data.Supportand is based on the interface IAdoExceptionTranslator shownbelow.

publicinterfaceIAdoExceptionTranslator

{

DataAccessExceptionTranslate(stringtask,stringsql,Exceptionexception);

}

Thearguments to the translatorarea taskstringprovidingadescriptionof thetaskbeingattempted,theSQLqueryorupdatethatcausedtheproblem,andthe'raw'exceptionthrownbytheADO.NETdataprovider.TheadditionaltaskandSQLargumentsallowforveryreadableandclearerrormessages tobecreatedwhenanexceptionoccurs.A default implementation, ErrorCodeExceptionTranslator, isprovided that uses the error codes defined for each data provider in the filedbproviders.xml. Refer to this file, an embedded resource in the Spring.Dataassembly, for the exact mappings of error codes to SpringDataAccessExceptions.A commonneed is tomodify the error codes that aremap onto the exception

Page 432: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

hierarchy.Thereareseveralwaystoaccomplishthistask.One approach is to override the error codes that are defined inassembly://Spring.Data/Spring.Data.Common/dbproviders.xml

By default, the DbProviderFactory will look for additional metadata for the IoCcontaineritusesinternallytodefineandmanagetheDbProvidersinafilenameddbProviders.xmllocatedintherootruntimedirectory.(Youcanchangethislocation,seethedocumentationonDbProviderformoreinformation.)Thisisa standard Spring application context so all features, such asObjectFactoryPostProcessors are available and will be automatically applied.DefiningaPropertyOverrideConfigurerinthisadditionalconfigurationfilewillallowfor you to override specific property values defined in the embedded resourcefile.Asanexample, theadditionaldbProviders.xml file shownbelowwill add the error code 2601 to the list of error codes that map to aDataIntegrityViolationException.

<objectsxmlns='http://www.springframework.net'>

<aliasname='SqlServer-2.0'alias='SqlServer2005'/>

<objectname="appConfigPropertyOverride"type="Spring.Objects.Factory.Config.PropertyOverrideConfigurer,Spring.Core"

<propertyname="Properties">

<name-values>

<addkey="SqlServer2005.DbMetadata.ErrorCodes.DataIntegrityViolationCodes"

value="544,2601,2627,8114,8115"/>

</name-values>

</property>

</object>

</objects>

The reason to define the alias is thatPropertyOverrideConfigurer assumes a period(.)astheseparatortopickouttheobjectnamebutthenamesoftheobjectsindbProviders.xml have periods in them (i.e. SqlServer-2.0 orSystem.Data.SqlClient).Creating an alias that has no periods in thename is aworkaround.Another way to customize the mappings of error codes to exceptions is tosubclass ErrorCodeExceptionTranslator and override the

Page 433: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

method, DataAccessException

TranslateException(string task, string sql,

stringerrorCode,Exceptionexception). This will becalled before referencing the metadata to perform exception translation. Thevendor specific error code provided as a method argument has already beenparsed out of the raw ADO.NET exception. If you create your own specificsubclass, then you should set the propertyExceptionTranslator onAdoTemplate andHibernateTemplate/HibernateTransactionManager torefertoyourcustomimplementation(unlessyouareusingautowiring).The third way is to write an implementation ofIAdoExceptionTranslator and set the propertyFallbackTranslator'onErrorCodeExceptionTranslator.Inthiscaseyouareresponsiblefor parsing our the vendor specific error code from the raw ADO.NETexception.Aswith the case of subclassingErrorCodeExceptionTranslator,youwill need to refer to this custom exception translator when usingAdoTemplate orHibernateTemplate/HibernateTransactionManager.Theorderingof theexceptiontranslationprocessing isasfollows.ThemethodTranslateException iscalledfirst, then thestandardexception translation logic,thentheFallbackTranslator.Note that you can use thisAPI directly in your own Spring independent datalayer.IfyouareusingSpring'sADO.NETabstractionclass,AdoTemplate,or HibernateTemplate, the converted exceptions will be thrownautomatically. Somewhere in between these two cases is using Spring'sdeclarative transaction management features in .NET 2.0 with the rawADO.NET APIs and using IAdoExceptionTranslator in yourexceptionhandling layer (whichmightbe implemented inAOPusingSpring'sexceptiontranslationaspect).Some of themore common data access exceptions are described here. PleaserefertotheAPIdocumentationformoredetails.

Page 434: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Table18.1.CommonDataAccessExceptionsException DescriptionBadSqlGrammarException ExceptionthrownwhenSQLspecifiedisinvalid.

DataIntegrityViolationExceptionExceptionthrownwhenanattempttoinsertorupdatedataresultsinviolationofanintegrityconstraint.Forexample,insertingaduplicatekey.

PermissionDeniedDataAccessExceptionExceptionthrownwhentheunderlingresourcedeniedapermissiontoaccessaspecificelement,suchasaspecificdatabasetable.

DataAccessResourceFailureException Exceptionthrownwhenaresourcefailscompletely,forexample,ifwecan'tconnecttoadatabase.

ConcurrentyFailureException

Exceptionthrownwhenaconcurrencyerroroccurs.OptimisticLockingFailureExceptionandPessimisticLockingFailureExceptionaresubclasses.Thisisausefulexceptiontocatchandtoretrythetransactionagain.SeeSpring'sRetryAspectforanAOPbasedsolution.

OptimisticLockingFailureException

Exceptionthrownwhenthereanoptimisticlockingfailureoccurs.ThesubclassObjectOptimisticLockingFailureExceptioncanbeusedtoexaminetheTypeandtheIDoftheobjectthatfailedtheoptimisticlocking.

PessimisticLockingFailure

Exceptionthrownwhenapessimisticlockingfailureoccures.SubclassesofthisexceptionareCannotAcquireLockException,CannotSerializeTransactionException,andDeadlockLoserDataAccessException.

CannotAcquireLockException Exceptionthrownwhenalockcannotbeacquired,forexampleduringanupdate,i..easelectforupdate

CannotSerializeTransactionException Exceptionthrownwhenatransactioncannotbeserialized.

Page 435: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

18.3.ConsistentabstractclassesforDAOsupportTomake it easier to work with a variety of data access technologies such asADO.NET,NHibernate,andiBatis.NETinaconsistentway,Springprovidesaset of abstract DAO classes that one can extend. These abstract classes havemethodsforprovidingthedatasourceandanyotherconfigurationsettingsthatarespecifictothetechnologyoneiscurrentlyusing.DAOsupportclasses:

AdoDaoSupport - super class for ADO.NET data access objects.Requires aDbProvider to beprovided; in turn, this classprovidesaAdoTemplate instance initialized from the suppliedDbProviderto subclasses. See the documentation for AdoTemplate for moreinformation.

HibernateDaoSupport - super class for NHibernate data accessobjects.Requires aISessionFactory to be provided; in turn, thisclassprovidesaHibernateTemplate instance initialized from thesupplied SessionFactory to subclasses. Can alternatively beinitializeddirectly via aHibernateTemplate, to reuse the latter'ssettingslikeSessionFactory,flushmode,exceptiontranslator,etc.This is contained in a download separate from the main Spring.NETdistribution.

Page 436: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter19.DbProvider

Page 437: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

19.1.IntroductionSpringprovidesageneric factory forcreatingADO.NETAPIartifacts such asIDbConnectionandIDbCommand.ThefactoryAPIisverysimilar tothe one introduced in .NET 2.0 but adds extrametadata needed by Spring tosupportfeaturesprovidedbyitsDAO/ADO.NETframeworksuchaserrorcodetranslation to a DAO exception hierarchy. The factory itself is configured byusingastandardSpringXMLbasedconfigurationfilethoughitisunlikelyyouwill need tomodify those settings yourself, you only need be concernedwithusingthefactory.Outoftheboxseveralpopulardatabasesaresupportedandanextension mechanism is available for defining new database providers ormodifyingexistingones.AcustomdatabasenamespaceforconfigurationaidsinmakingterseXMLbaseddeclarationsofSpring'sdatabaseobjectsyouwish touse.ThedownsideofSpring'sfactoryascomparedtotheonein.NET2.0isthatthetypes returned are lower level interfaces and not the abstract base classes inSystem.Data.Common.However, there are still 'holes' in the current .NET2.0providerclassesthatare'plugged'withSpring'sproviderimplementation.OneofthemostprominentisthethatthetoplevelDbExceptionexposestheHRESULToftheremoteprocedurecall,whichisnotwhatyouarecommonlylookingforwhenthingsgowrong.AssuchSpring'sproviderfactoryexposesthevendorsqlerrorcodeandalsomapsthaterrorcodeontoaconsistentdataaccessexceptionhierarchy. This makes writing portable exception handlers much easier. Inaddition, theDbParameter class doesn't provide themost common convenientmethods youwould expect as when using say the SqlServer provider. If youneed to access the BCL provider abstraction, you still can through Spring'sproviderclass.Furthermore,asmallwrapperaroundthestandardBCLproviderabstraction allows for integration with Spring's transaction managementfacilities, allowing you to create a DbCommand with its connection andtransactionpropertiesalreadysetbasedonthetransactioncallingcontext.

Page 438: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

19.2.IDbProviderandDbProviderFactoryTheIDbProviderAPIisshownbelowandshouldlookfamiliartoanyoneusing.NET2.0dataproviders.NotethatSpring'sDbProviderabstractioncanbeusedon.NET1.1inadditionto.NET2.0

publicinterfaceIDbProvider

{

IDbCommandCreateCommand();

objectCreateCommandBuilder();

IDbConnectionCreateConnection();

IDbDataAdapterCreateDataAdapter();

IDbDataParameterCreateParameter();

stringCreateParameterName(stringname);

stringCreateParameterNameForCollection(stringname);

IDbMetadataDbMetadata

{

get;

}

stringConnectionString

{

set;

get;

}

stringExtractError(Exceptione);

boolIsDataAccessException(Exceptione);

}

ExtractError is used to return an error string for translation into a DAOexception.On.NET1.1themethodIsDataAccessExceptionisusedtodetermine

Page 439: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

if the thrownexception is related todataaccesssince in .NET1.1 there isn'tacommon base class for database exceptions. CreateParameterName is used tocreate the string for parameters used in a CommandText object whileCreateParameterNameForCollection is used to create the string for aIDataParameter.ParameterName, typically contained inside aIDataParameterCollection.The classDbProviderFactory creates IDbProvider instances given aprovider name. The connection string property will be used to set theIDbConnection returned by the factory if present. The provider names, andcorrespondingdatabase,currentlyconfiguredarelistedbelow.

SqlServer-1.1 - Microsoft SQL Server, provider V1.0.5000.0 inframework.NETV1.1

SqlServer-2.0 (aliased to System.Data.SqlClient) -MicrosoftSQLServer,providerV2.0.0.0inframework.NETV2.0

SqlServerCe-3.1 - Microsoft SQL Server Compact Edition,providerV9.0.242.0

SqlServerCe-3.5.1 (aliased toSystem.Data.SqlServerCe) -Microsoft SQLServerCompactEdition,providerV3.5.1.0

OleDb-1.1-OleDb,providerV1.0.5000.0inframework.NETV1.1

OleDb-2.0(aliasedtoSystem.Data.OleDb)-OleDb,providerV2.0.0.0inframework.NETV2.0

OracleClient-2.0 (aliased toSystem.Data.OracleClient) - Oracle, Microsoft providerV2.0.0.0

OracleODP-2.0(aliasedtoSystem.DataAccess.Client)-Oracle,OracleproviderV2.102.2.20

MySql-MySQL,MySQLprovider1.0.10.1

MySql-1.0.9-MySQL,MySQLprovider1.0.9

MySql-5.0-MySQL,MySQLprovider5.0.7.0

MySql-5.0.8.1-MySQL,MySQLprovider5.0.8.1

Page 440: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

MySql-5.1-MySQL,MySQLprovider5.1.2.2

MySql-5.1.4-MySQL,MySQLprovider5.1.2.2

MySql-5.2.3 (aliased to MySql.Data.MySqlClient)MySQL,MySQLprovider5.2.3.0

Npgsql-1.0 - Postgresql provider 1.0.0.0 (and 1.0.0.1 - were buildwithsameversioninfo)

Npgsql-2.0-beta1-Postgresqlprovider1.98.1.0beta1

Npgsql-2.0-Postgresqlprovider2.0.0.0

DB2-9.0.0-1.1 - IBM DB2 Data Provider 9.0.0 for .NETFramework1.1

DB2-9.0.0-2.0-(aliasedtoIBM.Data.DB2)-IBMDB2DataProvider9.0.0for.NETFramework2.0

DB2-9.1.0-1.1 - IBM DB2 Data Provider 9.1.0 for .NETFramework1.1

DB2-9.1.0.2-(aliasedtoIBM.Data.DB2.9.1.0)-IBMDB2DataProvider9.1.0for.NETFramework2.0

SQLite-1.0.43SQLiteprovider1.0.43for.NETFramework2.0

SQLite-1.0.47 - (aliased to System.Data.SQLite) - SQLiteprovider1.0.43for.NETFramework2.0

SybaseAse-12-SybaseASEproviderforASE12.x

SybaseAse-15-SybaseASEproviderforASE15.x

SybaseAse-AdoNet2 - Sybase ADO.NET 2.0 provider for ASE12.xand15.x

Odbc-1.1-ODBCproviderV1.0.5000.0inframework.NETV1.1

Odbc-2.0-ODBCproviderV2.0.0.0inframework.NETV2

Note

Ifyourexactversionofthedatabaseproviderisnotlisted,youcanpickthegeneralprovidername,i.e.MySql.Data.MySqlClient,andthenperformanassemblyredirectinApp.config.Thiswilloftenbesufficienttoupgradetonewerversions.Asshownbelow

Page 441: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<runtime>

<assemblyBindingxmlns="urn:schemas-microsoft-com:asm.v1">

<dependentAssembly>

<assemblyIdentityname="Npgsql"

publicKeyToken="5d8b90d52f46fda7"

culture="neutral"/>

<bindingRedirectoldVersion="0.0.0.0-65535.65535.65535.65535

newVersion="2.0.0.0"/>

</dependentAssembly>

</assemblyBinding>

</runtime>

AnexampleusingDbProviderFactoryisshownbelow

IDbProviderdbProvider=DbProviderFactory.GetDbProvider("System.Data.SqlClient"

Thedefaultdefinitionsof theprovidersarecontained in theassemblyresourceassembly://Spring.Data/Spring.Data.Common/dbproviders.xml

Futureadditionstoroundoutthedatabasecoverageareforthcoming.Thecurrentcrudemechanism to add additional providers, or to apply any standard SpringIApplicationContextfunctionality,suchasapplyingAOPadvice, isto set the public static propertyDBPROVIDER_ADDITIONAL_RESOURCE_NAME inDbProviderFactorytoaSpringresourcelocation.Thedefaultvalueisfile://dbProviders.xml.(Thatisn'tatypo,thereisadifferenceincase with the name of the embedded resource). This crude mechanism willeventually be replaced with one based on a custom configuration section inApp.config/Web.config.Itmayhappenthattheversionnumberofanassemblyyouhavedownloadedisdifferent than the one listed above. If it is a point release, i.e. theAPI hasn'tchanged in anyway that is material to your application, you should add anassemblyredirectoftheformshownbelow.

<dependentAssembly>

Page 442: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<assemblyIdentityname="MySql.Data"

publicKeyToken="c5687fc88969c44d"

culture="neutral"/>

<bindingRedirectoldVersion="0.0.0.0-65535.65535.65535.65535"

newVersion="1.0.10.1"/>

</dependentAssembly>

ThisredirectsanyreferencetoanolderversionoftheassemblyMySql.Datatotheversion1.0.10.1.

Page 443: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

19.3.XMLbasedconfigurationCreatingaDbProviderinSpring'sXMLconfigurationfileisshownbelowinthetypicalcaseofusingittospecifytheDbProviderpropertyonanAdoTemplate.

<objectsxmlns='http://www.springframework.net'

xmlns:db="http://www.springframework.net/database">

<db:providerid="DbProvider"

provider="System.Data.SqlClient"

connectionString="DataSource=(local);Database=Spring;UserID=springqa;Password=springqa;Trusted_Connection=False"

<objectid="adoTemplate"type="Spring.Data.AdoTemplate,Spring.Data"

<propertyname="DbProvider"ref="DbProvider"/>

</object>

</objects>

Acustomnamespaceshouldberegisteredinthemainapplicationconfigurationfiletousethissyntax.Thisconfiguration,onlyfortheparsers,isshownbelow.Additional section handlers are needed to specify the rest of the Springconfigurationlocationsasdescribedinpreviouschapters.

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Data.Config.DatabaseNamespaceParser,Spring.Data"

</parsers>

</spring>

</configuration>

Page 444: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

19.4.ConnectionStringmanagementThereareafewoptionsavailabletohelpmanageyourconnectionstrings.ThefirstoptionistoleveragetheSpringpropertyreplacementfunctionality,asdescribedinSection5.9.2.1, “Example:ThePropertyPlaceholderConfigurer”.ThisletsyouinsertvariablenamesasplaceholdersforvaluesinaSpringconfigurationfile.Inthe following example specific parts of a connection string have beenparameterizedbutyoucanalsouseavariabletosettheentireconnectionstring.Anexampleofsuchasettingisshownbelow

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname='context'type='Spring.Context.Support.ContextHandler,Spring.Core'

</sectionGroup>

<sectionname="databaseSettings"type="System.Configuration.NameValueSectionHandler,System,Version=1.0.5000.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"

</configSections>

<spring>

<context>

<resourceuri="Aspects.xml"/>

<resourceuri="Services.xml"/>

<resourceuri="Dao.xml"/>

</context>

</spring>

<!--ThesepropertiesarereferencedinDao.xml-->

<databaseSettings>

<addkey="db.datasource"value="(local)"/>

<addkey="db.user"value="springqa"/>

<addkey="db.password"value="springqa"/>

<addkey="db.database"value="Northwind"/>

</databaseSettings>

</configuration>

WhereDao.xmlhasaconnectionstringasshownbelow

Page 445: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectsxmlns='http://www.springframework.net'

xmlns:db="http://www.springframework.net/database">

<db:providerid="DbProvider"

provider="System.Data.SqlClient"

connectionString="${db.datasource};Database=${db.database};UserID=${db.user};Password=${db.password};Trusted_Connection=False"

<objectid="adoTemplate"type="Spring.Data.AdoTemplate,Spring.Data"

<propertyname="DbProvider"ref="DbProvider"/>

</object>

<!--configurationofwhatvaluestosubstitutefor${}variableslistedabove-->

<objectname="appConfigPropertyHolder"

type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer,Spring.Core"

<propertyname="configSections"value="DatabaseConfiguration"

</object>

</objects>

PleaserefertotheSectionSection5.9.2.1, “Example:ThePropertyPlaceholderConfigurer”formoreinformation.

Page 446: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

19.5.AdditionalIDbProviderimplementationsSpringprovidessomeconvenientimplementationsoftheIDbProviderinterfacethataddaddtionalbehaviorontopofthestandardimplementation.

19.5.1.UserCredentialsDbProviderThisUserCredentialsDbProvider will allow you to change theusernameandpasswordofadatabaseconnectionatruntime.TheAPIcontainsthe propertiesUsername andPassword which are used as the defaultstringsrepresentingtheuserandpasswordintheconnectionstring.Youcanthenchange the value of these properties in the connection string by calling themethodSetCredentialsForCurrentThreadandfallback to thedefault values by calling the methodRemoveCredentialsFromCurrentThread. You call theSetCredentialsForCurrentThread method at runtime, beforeanydataaccessoccurs,todeterminewhichdatabaseusershouldbeusedforthecurrentuser-case.Whichuser toselect isup toyou.Youmayretrieve theuserinformation from an HTTP session for example. Example configuration andusageisshownbelow

<objectid="DbProvider"type="Spring.Data.Common.UserCredentialsDbProvider,Spring.Data"

<propertyname="TargetDbProvider"ref="targetDbProvider"/>

<propertyname="Username"value="UserID=defaultName"/>

<propertyname="Password"value="Password=defaultPass"/>

</object>

<db:providerid="targetDbProvider"provider="SqlServer-2.0"

connectionString="DataSource=MARKT60\SQL2005;Database=Spring;Trusted_Connection=False"

IfyouusedependencyinjectiontoconfigureaclasswithapropertyofthetypeIDbProvider,youwillneedtodowncasttothesubtypeoryoucanchangeyour class to have a property of the typeUserCredentialsDbProviderinsteadofIDbProvider.

userCredentialsDbProvider.SetCredentialsForCurrentThread("UserID=springqa"

UserCredentialsDbProvider's has a base class,

Page 447: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

DelegatingDbProvider, and is intended for you to use in your ownimplementationsthatdelegatecallstoatargetIDbProviderinstance.Thisclassinmeanttobesubclassedwithsubclassesoverridingonlythosemethods,such asCreateConnection(), that should not simply delegate to thetargetIDbProvider.

19.5.2.MultiDelegatingDbProviderThere are use-cases inwhich therewill need to be a runtime selection of thedatabase toconnect toamongmanypossiblecandidates.This isoften thecasewhere the same schema is installed in separate databases for different clients.The MultiDelegatingDbProvider implements theIDbProvider interface and provides an abstraction to the multipledatabasesandcanbeusedinDAOlayersuchthattheDAOlayerisunawareofthe switching between databases. MultiDelegatingDbProviderdoesitsjobbylookingintothreadlocalstorageunderthekeydbProviderName.This storage location stores the name of the dbProvider that is to be used forprocessingtherequest.MultiDelegatingDbProviderisconfiguredusing the dictionary property TargetDbProviders. The key of thisdictionary contains the name of a dbProvider and its value is a dbProviderobject.(Youcanalsoprovidethisdictionaryasaconstructorargument.)During requestprocessing,onceyouhavedeterminedwhich targetdbProvidershouldbeuse,inthisexampledatabase1ProviderName,youshouldexecutethefollowingcodeisyouareusingSpring1.2M1orlater

//Spring1.2M1orlater

LogicalThreadContext.SetData(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME,

andthefollowingocdeifyouareusingearlierversions

//PriortoSpring1.2M1

LogicalThreadContext.SetData("dbProviderName","database1ProviderName"

andthencallthedataaccesslayer.Here is a sample configuration to build up an object definition forMultiDelegatingDbProvider.

Page 448: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<db:providerid="CreditAndDebitsDbProvider"

provider="System.Data.SqlClient"

connectionString="DataSource=MARKT60\SQL2005;InitialCatalog=CreditsAndDebits;UserID=springqa;Password=springqa"

<db:providerid="CreditDbProvider"

provider="System.Data.SqlClient"

connectionString="DataSource=MARKT60\SQL2005;InitialCatalog=Credits;UserID=springqa;Password=springqa"

<objectid="dbProviderDictionary"type="Spring.Collections.SynchronizedHashtable,Spring.Core"

<propertyname="['DbProvider1']"ref="CreditAndDebitsDbProvider"

<propertyname="['DbProvider2']"ref="CreditDbProvider"/>

</object>

<objectid="DbProvider"type="Spring.Data.MultiDelegatingDbProvider,Spring.Data"

<propertyname="TargetDbProviders"ref="dbProviderDictionary"

</object>

Page 449: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter20.DataaccessusingADO.NET

Page 450: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.1.IntroductionSpringprovidesanabstraction fordataaccessviaADO.NETthatprovides thefollowingbenefitsandfeatures

Consistent andcomprehensivedatabaseprovider interfaces forboth .NET1.1and2.0

IntegrationwithSpring'stransactionmanagementfeatures.

TemplatestyleuseofDbCommandthat removes theneedtowrite typicalADO.NETboiler-platecode.

'One-liner' implementations for themostcommondatabaseusagepatternsletsyoufocusonthe'meat'ofyourADO.NETcode.

Easydatabaseparametercreation/management

ProviderindependentexceptionswithdatabaseerrorcodesandhigherlevelDAOexceptionhierarchy.

Centralizedresourcemanagementforconnections,commands,datareaders,etc.

SimpleDataReadertoObjectmappingframework.ThischapterisdividedupintoanumberofsectionsthatdescribethemajorareasoffunctionalitywithinSpring'sADO.NETsupport.

Motivations-describeswhyoneshouldconsiderusingSpring'sADO.NETfeaturesascomparedtousing'raw'ADO.NETAPI.

ProviderAbstraction-aquickoverviewofSpring'sproviderabstraction.

Approaches to ADO.NET Data Access - Discusses the two styles ofSpring'sADO.NETdataaccessclasses-templateandobjectbased.

IntroductiontoAdoTemplate-IntroductiontothedesignandcoremethodsofthecentralclassinSpring'sADO.NETsupport.

Exception Translation - Describes the features of Spring's data accessexceptions

Parameter Management - Convenience classes and methods for easyparametermanagement.

Custom IDataReader implementations - Strategy for providing custom

Page 451: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

implementations of IDataReader. This can be used to centralized andtransparently map DBNull values to CLR types when accessing anIDataReader or to provide extended mapping functionality in sub-interfaces.

Basic data access operations - Usage of AdoTemplate for IDbCommand'ExecuteScalar'and'ExecuteNonScalar'functionality

Queries and Lightweight Object Mapping - Using AdoTemplate to mapresultsetsintoobjects

DataSetandDataTableoperations-UsingAdoTemplatewithDataSetsandDataTables

Modeling ADO.NET operations as .NET objects - An object-orientedapproachtodataaccessoperations.

Page 452: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

.MotivationsThereareavarietyofmotivationstocreateahigherlevelADO.NETpersistenceAPI.Encapsulation of common 'boiler plate' taskswhen coding directly against theADO.NETAPI.Forexamplehere isa listof the tasks typicallyrequired tobecoded forprocessinga result setquery.Note that thecodeneededwhenusingSpring'sADO.NETframeworkisinitalics.

1. Defineconnectionparameters2. Opentheconnection3. Specifythecommandtypeandtext4. Prepareandexecutethestatement5. Setupthelooptoiteratethroughtheresults(ifany)6. Dotheworkforeachiteration7. Processanyexception8. Displayorrollbackonwarnings9. Handletransactions10. ClosetheconnectionSpringtakescareofthelow-leveltasksandletsyoufocusonspecifyingtheSQLanddoingtherealworkofextractingdata.Thisstandardboilerplatepatternisencapsulated in a class,AdoTemplate.Thename 'Template' is used because ifyou look at the typical code workflow for the above listing, you wouldessentiallyliketo'template'it,thatisstickinthecodethatisdoingtherealworkinthemidstoftheresource,transaction,exceptionmanagement.AnotherveryimportantmotivationistoprovideaneasymeanstogroupmultipleADO.NET operations within a single transaction while at the same timeadhering to aDAOstyle design inwhich transactions are initiatedoutside theDAOs, typically inabusiness service layer.Using the 'raw'ADO.NETAPI toimplement this design often results in explicitly passing around of aTransaction/Connection pair toDAO objects. This infrastructure task distractsfromthemaindatabasetaskathandandisfrequentlydoneinanad-hocmanner.Integratingwith Spring's transactionmanagement features provides an elegant

Page 453: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

means to achieve this common design goal. There aremany other benefits tointegration with Spring's transaction management features, see Chapter 17,Transactionmanagementformoreinformation.ProviderIndependentCode:In.NET1.1writingproviderindependentcodewasdifficultforavarietyofreasons.Themostprominentwasthelackofalackofacentral factory for creating interface based references to the core ADO.NETclassessuchasIDbConnection,IDbCommand,DbParameteretc.Inaddition,theAPIsexposedbymanyoftheseinterfaceswereminimalorincomplete-makingfor tediouscode thatwouldotherwisebemore easilydevelopedwithproviderspecific subclasses. Lastly, there was no common base class for data accessexceptionsacrosstheproviders..NET2.0mademanychangesforthebetter inthat regard across all these areas of concern - and Spring only plugs smallerholesinthatregardtohelpintheportabilityofyourdataaccesscode.Resource Management: The 'using' block is the heart of elegant resourcemanagement in .NETfromtheAPIperspective.However,despite itselegance,writing2-3nestedusingstatementsforeachdataaccessmethodalsostartstobetedious,whichintroducestheriskofforgettingtodotherightthingallthetimein terms of both direct coding and 'cut-n-paste' errors. Spring centralizes thisresourcemanagementinonespotsoyouneverforgetormakeamistakeandrelyonitalwaysbeingdonecorrectly.Parameter management: Frequently much of data access code is related tocreating appropriate parameters. To alleviate this boiler plate code Springprovidesaparameter'builder'classthatallowsforsuccinctcreationofparametercollections.Also, for thecaseof storedprocedures, parameters canbederivedfromthedatabaseitselfwhichreducesparametercreationcodetojustoneline.Frequently result set data is converted into objects. Spring provides a simpleframework to organize that mapping task and allows you to reuse mappingartifactsacrossyourapplication.Exceptions: The standard course of actionwhen an exception is thrown fromADO.NETcodeistolookuptheerrorcodeandthenre-runtheapplicationtosetabreakpointwheretheexceptionoccurredsoastoseewhatthecommandtextand data values were that caused the exception. Spring provides exceptionstranslation from these error codes (across database vendors) to aDataAccessObjectexceptionhierarchy.Thisallowsyoutoquicklyunderstandthecategoryoftheerrorthatoccurredandalsothe'bad'datawhichleadtotheexception.Warnings: A common means to extract warning from the database, and to

Page 454: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

optionallytreatthosewarningsasareasontorollbackisnotdirectlysupportedwiththenewSystem.Data.CommonAPIPortability: Where possible, increase the portability of code across databaseproviderinthehigherlevelAPI.Theneedaddingofaparameterprefix,i.e.@forSqlServeror':'fororacleisonesuchexampleofanareawhereahigherlevelAPIcanoffersomehelpinmakingyourcodemoreportable.NotethatSpring'sADO.NETframeworkisjust 'slightly'abovetherawAPI. Itdoesnottrytocompetewithotherhigherlevelpersistenceabstractionssuchasresultsetmappers(iBATIS.NET)orotherORMtools(NHibernate).(Apologiesif your favorite is left out of that short list). As always, pick and choose theappropriatelevelofabstractionforthetaskathand.Asasidenote,Springdoesoffer integration with higher level persistence abstractions (currentlyNHibernate) providing such features as integration with Spring's transactionmanagementfeaturesaswellasmixingorm/ado.netoperationswithinthesametransaction.

Page 455: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.3.ProviderAbstractionBefore you get started executing queries against the database you need toconnecttoit.Chapter19,DbProvidercoversthistopicindetailsoweonlydiscussthebasicideaofhowtointeractwiththedatabaseinthissection.Oneimportantingredient that increases theportabilityofwritingADO.NETapplications is torefertothebaseADO.NETinterfaces,suchasIDbCommandorIDbParameterinyourcode.However,Inthe.NET1.1BCLtheonlymeanstoobtainreferencestoinstances of these interfaces is to directly instantiate the classes, i.e. forSqlServerthiswouldbe

IDbCommandcommand=newSqlCommand();

OneoftheclassiccreationalpatternsintheGoFDesignPatternsbookaddressesthissituationdirectly,theAbstractFactorypattern.Thisapproachwasappliedinthe .NET BCL with the introduction of the DbProviderFactory class whichcontains various factory methods that create the various objects used inADO.NET programming. In addition, .NET 2.0 introduced new abstract baseclasses that all ADO.NET providers must inherit from. These base classesprovidemorecore functionalityanduniformityacross thevariousprovidersascomparedtotheoriginalADO.NETinterfaces.Spring's database provider abstractionhas a similarAPI to that of .ADO.NET2.0'sDbProviderFactory.ThecentralinterfaceisIDbProviderandithasfactorymethodsthatareanalogoustothoseintheDbProviderFactoryclassexceptthatthey return references to the base ADO.NET interfaces. Note that in keepingwith theSpringFramework's philosophy, IDbProvider is an interface, and canthus be easily mocked or stubbed as necessary. Another key element of thisinterface is the ConnectionString property that specifies the specific runtimeinformation necessary to connect to the provider. The interface also has aIDbMetadata property that contains minimal database metadata informationneededtosupportthefunctionalityinrestoftheSpringADO.NETframework.Itis unlikely you will need to use the DatabaseMetadata class directly in yourapplication.For more information on configuring a Spring database provider refer toChapter19,DbProvider

20.3.1.CreatinganinstanceofIDbProvider

Page 456: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Each database vendor is associated with a particular implementation of theIDbProvider interfaces.Avarietyof implementationsareprovidedwithSpringsuch asSqlServer,Oracle andMySql.Refer to the documentation onSpring'sDbProvider for creating a configuration for database that is not yet provided.TheprogrammaticwaytocreateanIDbProviderisshownbelow

IDbProviderdbProvider=DbProviderFactory.GetDbProvider("System.Data.SqlClient"

Please refer to the Chapter 19, DbProvider for information on how to create aIDbProviderinSpring'sXMLconfigurationfile.

Page 457: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.4.NamespacesTheADO.NETframeworkconsistsofa fewnamespaces,namelySpring.Data,Spring.Data.Generic, Spring.Data.Common, Spring.Data.Support, andSpring.Data.Object.TheSpring.Datanamespacecontains themajorityof the classes and interfacesyouwilldealwithonadaytodaybasis.TheSpring.Data.Genericnamespacesaddgenericversionsofsomeclassesandinterfacesandyouwillalsolikelydealwiththisonadaytodaybasisifyouareusing.NET2.0TheSpring.Data.CommonnamespacescontainsSpring'sDbProviderabstractioninadditiontoutilityclassesforparametercreation.The Spring.Data.Object namespaces contains classes that represent RDBMSqueries,updates,andstoredproceduresasthreadsafe,reusableobjects.Finally theSpring.Data.Support namespace is where you find theIAdoExceptionTransactortranslationfunctionalityandsomeutilityclasses.

Page 458: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.5.ApproachestoDataAccessSpringprovides two styles to interactwithADO.NET.The first is a 'template'basedapproachinwhichyoucreateansingleinstanceofAdoTemplatetobeusedbyallyourDAOimplementations.YourDAOmethodsare frequentlyimplementedasasinglemethodcallonthetemplateclassasdescribedindetailinthefollowingsection.Theotherapproachamoreobject-orientedmannerthatmodels database operations as objects. For example, one can encapsulate thefunctionality of a database query via an AdoQuery class and acreate/update/delete operation as aAdoNonQuery class. Stored proceduresarealsomodelledinthismannerviatheclassStoredProcedure.Tousetheseclassesyouinheritfromthemanddefinethedetailsoftheoperationintheconstructor and implement an abstract method. This reads very cleanly whenlookingatDAOmethodimplementationasyoucangenerallyseeallthedetailsofwhatisgoingon.Generallyspeaking,experiencehasshownthattheAdoTemplateapproachreadsverycleanlywhenlookingatDAOmethodimplementationasyoucangenerallyseeallthedetailsofwhatisgoingonascomparedtotheobjectbasedapproach.Theobjectbasedapproachhowever,offerssomeadvantageswhencallingstoredprocedures since it acts as a cacheof derived storedprocedure arguments andcanbeinvokedpassingavariable lengthargument list to the 'execute'method.As always, take a look at both approaches anduse the approach that providesyouwiththemostbenefitforaparticularsituation.

Page 459: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.6.IntroductiontoAdoTemplateTheclassAdoTemplateisattheheartofSpring'sADO.NETsupport.ItisbasedonanInversionofControl(i.e.callback)designwiththecentralmethod'Execute'handing you aIDbCommand instance that has its Connectionand Transaction properties set based on the transaction context of the callingcode.Allresourcemanagementishandledbytheframework,youonlyneedtofocus on dealingwith theIDbCommand object. The other methods in thisclassbuilduponthiscentral 'Execute'methodtoprovideyouaquickmeans toexecutecommondataaccessscenarios.There are two implementations of AdoTemplate. The one that usesGenericsandisinthenamespaceSpring.Data.Genericandtheothernon-genericversion inSpring.Data. Ineithercaseyoucreatean instanceofanAdoTemplatebypassingitaIDbProviderinstanceasshownbelow

AdoTemplateadoTemplate=newAdoTemplate(dbProvider);

AdoTemplate is a thread-safe class and as such a single instance can beusedforalldataaccessoperationsinyouapplicationsDAOs.AdoTemplateimplements an IAdoOperations interface. Although theIAdoOperations interface ismore commonlyused for testing scenariosyoumayprefertocodeagainstitinsteadofthedirectclassinstance.If you are using the generic version ofAdoTemplate you can access the non-genericversionviathepropertyClassicAdoTemplate.ThefollowingtwosectionsshowbasicusageoftheAdoTemplate'Execute'APIfor.NET1.1and2.0.

20.6.1.ExecuteCallbackTheExecutemethodanditsassociatedcallbackfunction/intefaceisthebasicmethod uponwhich all the othermethods inAdoTemplate delegate theirwork.Ifyoucannotfindasuitable'one-liner'methodinAdoTemplate foryourpurposeyoucanalwaysfallbacktotheExecutemethodtoperformanydatabaseoperationwhilebenefitingfromADO.NETresourcemanagementandtransaction enlistment.This is commonly the casewhen you are using special

Page 460: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

providerspecificfeatures,suchasXMLorBLOBsupport.

20.6.2.ExecuteCallbackin.NET2.0In this example a simple query against the 'Northwind' database is done todeterminethenumberofcustomerswhohaveaparticularpostalcode.

publicintFindCountWithPostalCode(stringpostalCode)

{

returnadoTemplate.Execute<int>(delegate(DbCommandcommand)

{

command.CommandText=

"selectcount(*)fromCustomerswherePostalCode=@PostalCode"

DbParameterp=command.CreateParameter();

p.ParameterName="@PostalCode";

p.Value=postalCode;

command.Parameters.Add(p);

return(int)command.ExecuteScalar();

});

}

TheDbCommandthatispassedintotheanonymousdelegateisalreadyhasitConnectionproperty set to the correspondingvalueof thedbProvider instanceusedtocreatethetemplate.Furthermore,theTransactionpropertyoftheDbCommand is setbasedon the transactional calling context of the code asbased on the use of Spring's transaction management features. Also note thefeature of anonymous delegates to access the variable 'postalCode' which isdefined 'outside' the anonymous delegate implementation. The use ofanonymous delegates is a powerful approach since it allows you to writecompact data access code. If you find that your callback implementation isgettingverylong,itmayimprovecodeclaritytouseaninterfacebasedversionofthecallbackfunction,i.e.anICommandCallbackshownbelow.Asyoucansee,onlythemostrelevantportionsofthedataaccesstaskathandneed to be coded. (Note that in this simple example you would be better offusingAdoTemplate'sExecuteScalarmethoddirectly.Thismethodisdescribedin

Page 461: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

thefollowingsections).Asmentionedbefore,thetypicalusagescenariofortheExecute callback would involve downcasting the passed in DbCommandobjecttoaccessspecificproviderAPIfeatures.There isalsoan interfacebasedversionof theexecutemethod.Thesignaturesforthedelegateandinterfaceareshownbelow

publicdelegateTCommandDelegate<T>(DbCommandcommand);

publicinterfaceICommandCallback

{

TDoInCommand<T>(DbCommandcommand);

}

Whilethedelegateversionoffersthemostcompactsyntax,theinterfaceversionallows for reuse. The corresponding method signatures onSpring.Data.Generic.AdoTemplateareshownbelow

publicclassAdoTemplate:AdoAccessor,IAdoOperations

{

...

TExecute<T>(ICommandCallbackaction);

TExecute<T>(CommandDelegate<T>del);

...

}

Whileitiscommonfor.NET2.0ADO.NETproviderimplementationstoinheritfrom the base class System.Data.Common.DbCommand, that is not arequirement.Toaccommodatethefewthatdon't,whichasofthiswritingarethelatest Oracle (ODP) provider, Postgres, and DB2 for iSeries, two additionalexecutemethods are provided. The only difference is the use of callback anddelegate implementations that have IDbCommand and not DbCommand ascallback arguments. The following listing shows these methods onAdoTemplate.

publicclassAdoTemplate:AdoAccessor,IAdoOperations

Page 462: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

{

...

TExecute<T>(IDbCommandCallbackaction);

TExecute<T>(IDbCommandDelegate<T>del);

...

}

wherethesignaturesforthedelegateandinterfaceareshownbelow

publicdelegateTIDbCommandDelegate<T>(IDbCommandcommand);

publicinterfaceIDbCommandCallback<T>

{

TDoInCommand(IDbCommandcommand);

}

Internally theAdoTemplate implementation delegates to implementationsofIDbCommandCallbacksothatthe'lowestcommondenominator'APIisused tohavemaximumportability. Ifyouaccidentally callExecute<T>(ICommandCallback action)and the command does not inheritfrom DbCommand, anInvalidDataAccessApiUsageExceptionwillbethrown.Depending on how portable youwould like your code to be, you can chooseamong the two callback styles. The one based on DbCommand has theadvantage of access to the more user friendly DbParameter class ascomparedtoIDbParameterobtainedfromIDbCommand.

20.6.3.ExecuteCallbackin.NET1.1>AdoTemplatediffersfromits.NET2.0genericcounterpartinthatitexposestheinterfaceIDbCommand in its 'Execute' callback methods and delegate ascompared to the abstract base classDbProvider. Also, since anonymousdelegatesarenotavailablein.NET1.1,thetypicalusagepatternrequiresyouto

Page 463: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

create a explicitly delegate and/or class that implements theICommandCallback interface. Example code to query In .NET 1.1 the'Northwind'databaseisdonetodeterminethenumberofcustomerswhohaveaparticularpostalcodeisshownbelow.

publicvirtualintFindCountWithPostalCode(stringpostalCode)

{

return(int)AdoTemplate.Execute(newPostalCodeCommandCallback(postalCode));

}

andthecallbackimplementationis

privateclassPostalCodeCommandCallback:ICommandCallback

{

privatestringcmdText="selectcount(*)fromCustomerwherePostalCode=@PostalCode"

privatestringpostalCode;

publicPostalCodeCommandCallback(stringpostalCode)

{

this.postalCode=postalCode;

}

publicobjectDoInCommand(IDbCommandcommand)

{

command.CommandText=cmdText;

IDbDataParameterp=command.CreateParameter();

p.ParameterName="@PostalCode";

p.Value=postalCode;

command.Parameters.Add(p);

returncommand.ExecuteScalar();

}

}

Note that in this example, one could more easily use AdoTemplate'sExecuteScalarmethod.TheExecutemethodhasinterfaceanddelegateoverloads.Thesignaturesforthe

Page 464: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

delegateandinterfaceareshownbelow

publicdelegateobjectCommandDelegate(IDbCommandcommand);

publicinterfaceICommandCallback

{

objectDoInCommand(IDbCommandcommand);

}

The correspondingmethod signatures on Spring.Data.AdoTemplate are shownbelow

publicclassAdoTemplate:AdoAccessor,IAdoOperations

{

...

objectExecute(CommandDelegatedel);

objectExecute(ICommandCallbackaction);

...

}

Note that you have to cast to the appropriate object type returned from theexecutemethod.

20.6.4.QuickGuidetoAdoTemplateMethodsTherearemanymethodsinAdoTemplatesoitiseasytofeelabitoverwhelmedwhentakingalookattheSDKdocumentation.However,afterawhileyouwillhopefully find the class 'easy to navigate' with intellisense. Here is a quickcategorizationof themethodnamesand their associateddataaccessoperation.Each method is overloaded to handle common cases of passing in parametervalues.Thegeneric'catch-all'method

Execute - Allows you to perform any data access operation on astandardDbCommandobject.TheconnectionandtransactionpropertiesoftheDbCommandarealreadysetbasedonthetransactionalcallingcontext.

Page 465: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

There is also an overloaded method that operates on a standardIDbCommandobject.ThisisforthoseprovidersthatdonotinheritfromthebaseclassDbCommand.

ThefollowingmethodsmirrorthoseontheDbCommandobject.

ExecuteNonQuery - Executes the 'NonQuery' method on aDbCommand, applying provided parameters and returning the number ofrowsaffected.

ExecuteScalar - Executes the 'Scalar' method on a DbCommand,applying provided parameters, and returning the first column of the firstrowintheresultset.

Mappingresultsetstoobjects

QueryWithResultSetExtractor-Executeaquerymappingaresult set to an object with an implementation of theIResultSetExtractorinterface.

QueryWithResultSetExtractorDelegate - Same asQueryWithResultSetExtractor but using aResultSetExtractorDelegatetoperformresultsetmapping.

QueryWithRowCallback - Execute a query calling animplementationofIRowCallbackforeachrowintheresultset.

QueryWithRowCallbackDelegate - Same asQueryWithRowCallbackbut calling aRowCallbackDelegate foreachrow.

QueryWithRowMapper-ExecuteaquerymappingaresultsetonarowbyrowbasiswithanimplementationoftheIRowMapperinterface.

QueryWithRowMapperDelegate - Same asQueryWithRowMapper but using a RowMapperDelegate toperformresultsetrowtoobjectmapping.

Mappingresultsettoasingleobject

QueryForObject - Execute a query mapping the result set to anobjectusingaIRowMapper.Exceptionisthrownifthequerydoesnotreturnexactlyoneobject.

Page 466: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Query with a callback to create the DbCommand object. These are generallyused by the framework itself to support other functionality, such as in theSpring.Data.Objectsnamespace.

QueryWithCommandCreator-ExecuteaquerywithacallbacktoIDbCommandCreator to create a IDbCommand object and usingeither a IRowMapper or IResultSetExtractor to map the result set to anobject.Onevariationletsmultipleresultset'processors'bespecifiedtoactonmultipleresultsetsandreturnoutputparameters.

DataTableandDataSetoperations

DataTableCreate-CreateandFillDataTables

DataTableCreateWithParameters - Create and FillDataTablesusingaparametercollection.

DataTableFill-Fillapre-existingDataTable.

DataTableFillWithParameters - Fill a pre-existingDataTableusingparametercollection.

DataTableUpdate - Update the database using the providedDataTable,insert,update,deleteSQL.

DataTableUpdateWithCommandBuilder - Update thedatabaseusingtheprovidedDataTable,selectSQL,andparameters.

DataSetCreate-CreateandFillDataSets

DataSetCreateWithParameters-CreateandFillDataTablesusingaparametercollection.

DataSetFill-Fillapre-existingDataSet

DataSetFillWithParameters - Fill a pre-existing DataTableusingparametercollection.

DataSetUpdate - Update the database using the providedDataSet,insert,update,deleteSQL.

DataSetUpdateWithCommandBuilder-UpdatethedatabaseusingtheprovidedDataSet,selectSQL,andparameters..

Note

Page 467: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ThesemethodsarenotcurrentlyinthegenericversionofAdoTemplatebutaccessiblethroughthepropertyClassicAdoTemplate.

ParameterCreationutilitymethods

DeriveParameters - Derive the parameter collection for storedprocedures.

In turn eachmethod typically has four overloads, onewith noparametersandthree for providing parameters. Aside from the DataTable/DataSet operations,thethreeparameteroverloadsareoftheformshownbelow

MethodName(CommandType cmdType, string cmdText,CallbackInterfaceOrDelegate,parametersettingarguments)

TheCallbackInterfaceOrDelegateisoneofthethreetypeslistedpreviously.Theparameterssettingargumentsareoftheform

MethodName( ... string parameterName, Enum

dbType,intsize,objectparameterValue)

MethodName(...IDbParametersparameters)

MethodName( ... ICommandSetter

commandSetter)

Thefirstoverloadisaconveniencemethodwhenyouonlyhaveoneparametertoset.Thedatabaseenumerationisthebaseclass'Enum'allowingyoutopassinany of the provider specific enumerations as well as the common DbTypeenumeration.This is a tradeoff of type-safetywith provider portability. (Notegenericversioncouldbeimprovedtoprovidetypesafety...).The second overload contains a collection of parameters. The data type isSpring'sIDbParameterscollectionclassdiscussedinthefollowingsection.Thethirdoverloadisacallbackinterfaceallowingyoutosettheparameters(orotherproperties)oftheIDbCommandpassedtoyoubytheframeworkdirectly.Ifyouareusing.NET2.0thedelegateversionsofthemethodsareveryusefulsince very compact definitions of database operations can be created thatreferencevariableslocaltotheDAOmethod.Thisremovessomeofthetediumin passing parameters around with interface based versions of the callbackfunctionssincetheyneedtobepassedintotheconstructoroftheimplementingclass. The general guideline is to use the delegate when available for

Page 468: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

functionality that does not need to be shared across multiple DAO classes ormethodsanduseinterfacebasedversiontoreusetheimplementationinmultipleplaces. The .NET 2.0 versions make use of generics where appropriate andthereforeenhancetype-safety.

20.6.5.QuickGuidetoAdoTemplatePropertiesAdoTemplatehasthefollowingpropertiesthatyoucanconfigure

LazyInit - Indicates if the IAdoExceptionTranslatorshouldbecreatedonfirstencounterofanexceptionfromthedataprovideror when AdoTemplate is created. Default is true, i.e. to lazilyinstantiate.

ExceptionTranslator - Gets or sets the implementation ofIAdoExceptionTranslator to use. If no custom translator isprovided,adefaultErrorCodeExceptionTranslatorisused.

DbProvider-GetsorsetstheIDbProviderinstancetouse.

DataReaderWrapperType-GetsorsettheSystem.Typetousetocreate an instance of IDataReaderWrapper for the purpose ofproviding extended mapping functionality. Spring provides animplementation to use as the basis for a mapping strategy that will mapDBNull values to default values based on the standardIDataReader interface. See the section custom IDataReader

implementationsformoreinformation.

CommandTimeout - Gets or sets the command timeout forIDbCommands that this AdoTemplate executes. Default is 0,indicatingtousethedatabaseprovider'sdefault.

Page 469: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.7.TransactionManagementThe AdoTemplate is used in conjunction with an implementation of aIPlatformTransactionManager, which is Spring's portabletransaction management API. This section gives a brief overview of thetransactionmanagersyoucanusewithAdoTemplateandthedetailsofhowyoucanretrievetheconnection/transactionADO.NETobjectsthatarebound to thethreadwhenatransactionstarts.Pleaserefertothesectionkeyabstractions in thechapter on transactions for more comprehensive introduction to transactionmanagement.To use local transactions, those with only one transactional resource (i.e. thedatabase) you will typically useAdoPlatformTransactionManager.IfyouneedtomixHibernateand ADO.NET data access operations within the same local transaction youshould use HibernatePlatformTransaction manager which isdescribedmoreinthesectiononORMtransactionmanagement.While it ismostcommon touseSpring's transactionmanagement features to avoidthelowlevelmanagementofADO.NETconnectionandtransactionobjects,youcan retrieve the connection/transaction pair that was created at the start of atransaction and bound to the current thread. This may be useful for someintegrationwithotherdataaccessAPIs.ThecanbedoneusingtheutilityclassConnectionUtilsasshownbelow.

IDbProviderdbProvider=DbProviderFactory.GetDbProvider("System.Data.SqlClient"

ConnectionTxPairconnectionTxPairToUse=ConnectionUtils.GetConnectionTxPair(dbProvider);

IDbCommandcommand=DbProvider.CreateCommand();

command.Connection=connectionTxPairToUse.Connection;

command.Transaction=connectionTxPairToUse.Transaction;

Itispossibletoprovideawrapperaroundthestandard.NETproviderinterfacessuch that you can use the plain ADO.NET API in conjunction with Spring'stransactionmanagementfeatures.If you are usingServiceDomainPlatformTransactionManager or

Page 470: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TxScopePlatformTransactionManager then you can retrievethecurrentlyexecutingtransactionobjectviathestandard.NETAPIs.

Page 471: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.8.ExceptionTranslationAdoTemplate'smethods throwexceptionswithinaDataAccessObject (DAO)exceptionhierarchydescribedinChapter18,DAOsupport.Inaddition,thecommandtextanderrorcodeoftheexceptionareextractedandlogged.Thisleadstoeasierto write provider independent exception handling layer since the exceptionsthrown are not tied to a specific persistence technology. Additionally, forADO.NETcodetheerrormessagesloggedprovideinformationontheSQLanderrorcodetobetterhelpdiagnosetheissue.

Page 472: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.9.ParameterManagementAfairamountofthecodeinADO.NETapplicationsisrelatedtothecreationandpopulationofparameters.TheBCLparameter interfacesareveryminimalanddonothavemanyconveniencemethodsfoundinproviderimplementationssuchas SqlClient. Even still, with SqlClient, there is a fair amount of verbosity tocreating and populating a parameter collection. Spring provides two ways tomakethismundanetaskeasierandmoreportableacrossproviders.

20.9.1.IDbParametersBuilderInstead of creating a parameter on one line of code, then setting its type onanother and size on another, a builder and parameter interface,IDbParametersBuilder and IDbParameter respectfully, areprovidedso that this declarationprocess canbe condensed.The IDbParametersupport chaining calls to its methods, in effect a simple language-constraineddomainspecificlanguage,tobefancyaboutit.Hereisanexampleofitinuse.

IDbParametersBuilderbuilder=CreateDbParametersBuilder();

builder.Create().Name("Country").Type(DbType.String).Size(15).Value(country);

builder.Create().Name("City").Type(DbType.String).Size(15).Value(city);

//nowgettheIDbParameterscollectionforuseinpassingtoAdoTemplatemethods.

IDbParametersparameters=builder.GetParameters();

Pleasenote thatIDbParametersandIDbParameterarenotpartoftheBCL,butpartof theSpring.Data.Commonnamespace.TheIDbParameterscollectionisafrequentargumenttotheoverloadedmethodsofAdoTemplate.Theparameterprefix, i.e. '@' inSqlServer, isnot required tobeadded to theparameter name. TheDbProvider is aware of thismetadata andAdoTemplatewilladditautomaticallyifrequiredbeforeexecution.An additional feature of the IDbParametersBuilder is to create a SpringFactoryObjectthatcreatesIDbParametersforuseintheXMLconfigurationfileoftheIoCcontainer.ByleveragingSpring'sexpressionevaluationlanguage,theabove linesof codecanbe takenas text from theXMLconfiguration file and

Page 473: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

executed.Asaresultyoucanexternalizeyourparameterdefinitionsfromyourcode. In combination with abstract object definitions and importing ofconfiguration files your increase the chances of having one code base supportmultipledatabaseprovidersjustbyachangeinconfigurationfiles.

20.9.2.IDbParametersThis class is similar to the parameter collection class you find in providerspecific implementations of IDataParameterCollection. It contains a variety ofconveniencemethodstobuildupacollectionofparameters.Hereisanabbreviatedlistingofthecommonconveniencemethods.

intAdd(objectparameterValue)

voidAddRange(Arrayvalues)

IDbDataParameterAddWithValue(stringname,objectparameterValue)

IDbDataParameterAdd(stringname,EnumparameterType)

IDbDataParameterAddOut(stringname,EnumparameterType)

IDbDataParameterAddReturn(stringname,EnumparameterType)

voidDeriveParameters(stringstoredProcedureName)Hereasimpleusageexample

//insidemethodhashaslocalvariablecountryandcity...

IDbParametersparameters=CreateDbParameters();

parameters.AddWithValue("Country",country).DbType=DbType.String;

parameters.Add("City",DbType.String).Value=city;

//nowpassontoAdoTemplatemethods.

Theparameterprefix, i.e. '@' inSqlServer, isnot required tobeadded to theparameter name. TheDbProvider is aware of thismetadata andAdoTemplatewilladditautomaticallyifrequiredbeforeexecution.

Page 474: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.10.CustomIDataReaderimplementationsThepassedinimplementationofIDataReadercanbecustomized.Thisletsyou add a strategy for handling null values to the standard methods in theIDataReader interface or to provide sub-interface of IDataReader thatcontains extended functionality, for example support for default values. Incallbackcode,i.e.IRowMapperandassociateddelegate,youwoulddowncasttothesub-interfacetoperformprocessing.SpringprovidesaclasstomapDBNullvaluestodefaultvalues.Whenreadingfrom a IDataReader there is often the need tomapDBNull values to somedefaultvalues,i.e.nullorsayamagicnumbersuchas-1.Thisisusuallydonevia a ternary operator which decreases readability and also increases thelikelihood of mistakes. Spring provides an IDataReaderWrapperinterface(whichinherits fromthestandardIDataReader)so thatyoucanprovide your own implementation of a IDataReader thatwill performDBNullmapping for you in a consistent and non invasive manner to your result setreadingcode.Adefault implementation,NullMappingDataReader isprovided which you can subclass to customize or simply implement theIDataReaderWrapperinterfacedirectly.Thisinterfaceisshownbelow

publicinterfaceIDataReaderWrapper:IDataReader

{

IDataReaderWrappedReader

{

get;

set;

}

}

All of AdoTemplates callback interfaces/delegates that have anIDataReader as an argument are wrapped with aIDataReaderWrapperiftheAdoTemplatehasbeenconfiguredwithonevia its DataReaderWrapperType property. Your implementationshouldsupportazero-argconstructor.FrequentlyyouwilluseacommonmapperforDBNullacrossyourapplication

Page 475: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

soonlyoneinstanceofAdoTemplateandIDataReaderWrapperinrequired. If youneed to usemultiplenullmapping strategiesyouwill need tocreatemultipleinstancesofAdoTemplateandconfigurethemappropriatelyintheDAOobjects.

Page 476: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.11.BasicdataaccessoperationsThe'ExecuteNonQuery'and'ExecuteScalar'methodsofAdoTemplatehavethesamefunctionalityasthesamenamedmethodsontheDbCommandobject

20.11.1.ExecuteNonQueryExecuteNonQueryisusedtoperformcreate,update,anddeleteoperations.Ithasfouroverloadslistedbelowreflectingdifferentwaystosettheparameters.Anexampleofusingthismethodisshownbelow

publicvoidCreateCredit(floatcreditAmount)

{

AdoTemplate.ExecuteNonQuery(CommandType.Text,

String.Format("insertintoCredits(creditAmount)VALUES({0})"

creditAmount));

}

20.11.2.ExecuteScalarAnexampleofusingthismethodisshownbelow

intiCount=(int)adoTemplate.ExecuteScalar(CommandType.Text,

Page 477: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.12.QueriesandLightweightObjectMappingAcommonADO.NETdevelopmenttaskisreadinginaresultsetandconvertingit to a collection of domain objects. The family of QueryWith methods onAdoTemplatehelpinthistask.Theresponsibilityofperformingthemappingisgiven tooneof three callback interfaces/delegates thatyouare responsible fordeveloping.Thesecallbackinterfaces/delegatesare:

IResultSetExtractor / ResultSetExtractorDelegate - hands you aIDataReaderobjectforyoutoiterateoverandreturnaresultobject.

IRowCallback / RowCallbackDelegate - hands you a IDataReader toprocessthecurrentrow.Returnsvoidandassuchisusuallystatefulin thecaseofIRowCallbackimplementationsorusesavariabletocollectaresultthatisavailabletoananonymousdelegate.

IRowMapper/RowMapperDelegate-handsyouaIDataReadertoprocessthecurrentrowandreturnanobjectcorrespondingtothatrow.

There are generic versions of the IResultSetExtractor and IRowMapperinterfaces/delegates providing you with additional type-safety as compared totheobjectbasedmethodsignaturesusedinthe.NET1.1implementation.As usual with callback APIs in Spring.Data, your implementations of theseinterfaces/delegatesareonlyconcernedwiththecoretaskathand-mappingdata-whiletheframeworkhandlesiterationofreadersandresourcemanagement.Each 'QueryWith' method has 4 overloads to handle common ways to bindparameterstothecommandtext.Thefollowingsectionsdescribe inmoredetailhowtouseSpring's lightweightobjectmappingframework.

20.12.1.ResultSetExtractorThe ResultSetExtractor gives you control to iterate over the IDataReaderreturnedfromthequery.Youareresponsiblefor iteratingthroughall the resultsets and returning a corresponding result object. Implementations ofIResultSetExtractorare typicallystatelessand therefore reusableas longas theimplementationdoesn'taccessstateful resources.Theframeworkwillclose theIDataReaderforyou.TheinterfaceanddelegatesignatureforResutSetExtractorsisshownbelowfor

Page 478: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

thegenericversionintheSpring.Data.Genericnamespace

publicinterfaceIResultSetExtractor<T>

{

TExtractData(IDataReaderreader);

}

publicdelegateTResultSetExtractorDelegate<T>(IDataReaderreader);

Thedefinitionforthenon-genericversionisshownbelow

publicinterfaceIResultSetExtractor

{

objectExtractData(IDataReaderreader);

}

publicdelegateobjectResultSetExtractorDelegate(IDataReaderreader);

Here is an example taken from theSpring.DataQuickStart. It is amethod in aDAOclassthatinheritsfromAdoDaoSupport,whichhasaconveniencemethod'CreateDbParametersBuilder()'.

publicvirtualIList<string>GetCustomerNameByCountryAndCityWithParamsBuilder(

{

IDbParametersBuilderbuilder=CreateDbParametersBuilder();

builder.Create().Name("Country").Type(DbType.String).Size(15).Value(country);

builder.Create().Name("City").Type(DbType.String).Size(15).Value(city);

returnAdoTemplate.QueryWithResultSetExtractor(CommandType.Text,

customerByCountryAndCityCommandText,

new

builder.GetParameters());

}

TheimplementationoftheResultSetExtractorisshownbelow.

internalclassCustomerNameResultSetExtractor<T>:IResultSetExtractor<T>

{

publicTExtractData(IDataReaderreader)

Page 479: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

{

TcustomerList=newT();

while(reader.Read())

{

stringcontactName=reader.GetString(0);

customerList.Add(contactName);

}

returncustomerList;

}

}

Internally the implementation of the QueryWithRowCallback andQueryWithRowMapper methods are specializations of the generalResultSetExtractor. For example, the QueryWithRowMapper implementationiterates through the result set, calling the callbackmethod 'MapRow' for eachrowandcollectingtheresultsinanIList.Ifyouhaveaspecificcasethatisnotcovered by the QueryWithXXX methods you can subclass AdoTemplate andfollowthesameimplementationpatterntocreateanewQueryWithXXXmethodtosuityourneeds.

20.12.2.RowCallbackTheRowCallbackisusuallyastatefulobjectitselforpopulatesanotherstatefulobjectthatisaccessibletothecallingcode.HereisasampletakefromtheDataQuickStart

publicclassRowCallbackDao:AdoDaoSupport

{

privatestringcmdText="selectContactName,PostalCodefromCustomers"

publicvirtualIDictionary<string,IList<string>>GetPostalCodeCustomerMapping()

{

PostalCodeRowCallbackstatefullCallback=newPostalCodeRowCallback();

AdoTemplate.QueryWithRowCallback(CommandType.Text,cmdText,

statefullCallback);

//Dosomethingwithresultsinstatefulcallback...

returnstatefullCallback.PostalCodeMultimap;

}

}

Page 480: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The PostalCodeRowCallback builds up state which is then retrieved via thepropertyPostalCodeMultimap.TheCallbackimplementationisshownbelow

internalclassPostalCodeRowCallback:IRowCallback

{

privateIDictionary<string,IList<string>>postalCodeMultimap=

newDictionary<string,IList<string>>();

publicIDictionary<string,IList<string>>PostalCodeMultimap

{

get{returnpostalCodeMultimap;}

}

publicvoidProcessRow(IDataReaderreader)

{

stringcontactName=reader.GetString(0);

stringpostalCode=reader.GetString(1);

IList<string>contactNameList;

if(postalCodeMultimap.ContainsKey(postalCode))

{

contactNameList=postalCodeMultimap[postalCode];

}

else

{

postalCodeMultimap.Add(postalCode,contactNameList=

}

contactNameList.Add(contactName);

}

}

20.12.3.RowMapperTheRowMapperletsyoufocusonjustthelogictomaparowofyourresultsettoanobject.ThecreationofaIListtostoretheresultsanditeratingthroughtheIDataReaderishandledbytheframework.HereisasimpleexampletakenfromtheDataQuickStartapplication

publicclassRowMapperDao:AdoDaoSupport

{

privatestringcmdText="selectAddress,City,CompanyName,ContactName,"

"ContactTitle,Country,Fax,CustomerID,Phone,PostalCode,"

Page 481: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

"RegionfromCustomers";

publicvirtualIList<Customer>GetCustomers()

{

returnAdoTemplate.QueryWithRowMapper<Customer>(CommandType.Text,cmdText,

newCustomerRowMapper<Customer>());

}

}

wheretheimplementationoftheRowMapperis

publicclassCustomerRowMapper<T>:IRowMapper<T>whereT:Customer,

{

publicTMapRow(IDataReaderdataReader,introwNum)

{

Tcustomer=newT();

customer.Address=dataReader.GetString(0);

customer.City=dataReader.GetString(1);

customer.CompanyName=dataReader.GetString(2);

customer.ContactName=dataReader.GetString(3);

customer.ContactTitle=dataReader.GetString(4);

customer.Country=dataReader.GetString(5);

customer.Fax=dataReader.GetString(6);

customer.Id=dataReader.GetString(7);

customer.Phone=dataReader.GetString(8);

customer.PostalCode=dataReader.GetString(9);

customer.Region=dataReader.GetString(10);

returncustomer;

}

}

Youmayalsopassinadelegate,whichisparticularlyconvenientifthemappinglogicisshortandyouneedtoaccesslocalvariableswithinthemappinglogic.

publicvirtualIList<Customer>GetCustomersWithDelegate()

{

returnAdoTemplate.QueryWithRowMapperDelegate<Customer>(CommandType.Text,cmdText,

delegate(IDataReaderdataReader,int

{

Customercustomer=newCustomer();

Page 482: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

customer.Address=dataReader.GetString(0);

customer.City=dataReader.GetString(1);

customer.CompanyName=dataReader.GetString(2);

customer.ContactName=dataReader.GetString(3);

customer.ContactTitle=dataReader.GetString(4);

customer.Country=dataReader.GetString(5);

customer.Fax=dataReader.GetString(6);

customer.Id=dataReader.GetString(7);

customer.Phone=dataReader.GetString(8);

customer.PostalCode=dataReader.GetString(9);

customer.Region=dataReader.GetString(10);

returncustomer;

});

}

20.12.4.QueryforasingleobjectTheQueryForObjectmethod is usedwhenyou expect there to be exactly oneobject returned from the mapping, otherwise aSpring.Dao.IncorrectResultSizeDataAccessException will be thrown. Here issomesampleusagetakenfromtheDataQuickStart.

publicclassQueryForObjectDao:AdoDaoSupport

{

privatestringcmdText="selectAddress,City,CompanyName,ContactName,"

"ContactTitle,Country,Fax,CustomerID,Phone,PostalCode,"

"RegionfromCustomerswhereContactName=@ContactName"

publicCustomerGetCustomer(stringcontactName)

{

returnAdoTemplate.QueryForObject(CommandType.Text,cmdText,

newCustomerRowMapper<Customer>(),

"ContactName",DbType.String,30,contactName);

}

}

20.12.5.QueryusingaCommandCreatorThere is a family of overloaded methods that allows you to encapsulate andreuse a particular configuration of aIDbCommand object. These methods

Page 483: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

alsoallowforaccesstoreturnedoutparametersaswellasamethodthatallowsprocessingofmultipleresultsets.ThesemethodsareusedinternallytosupporttheclassesintheSpring.Data.ObjectsnamespaceandyoumayfindtheAPIusedinthatnamespacetobemoreconvenient.Thefamilyofmethodsislistedbelow.

object

QueryWithCommandCreator(IDbCommandCreator

cc,IResultSetExtractorrse)

void

QueryWithCommandCreator(IDbCommandCreator

cc,IRowCallbackrowCallback)

IList

QueryWithCommandCreator(IDbCommandCreator

cc,IRowMapperrowMapper)

Thereisalsothesamemethodswithanadditionalcollectingparametertoobtainanyoutputparameters.Theseare

object

QueryWithCommandCreator(IDbCommandCreator

cc, IResultSetExtractor rse, IDictionary

returnedParameters)

void

QueryWithCommandCreator(IDbCommandCreator

cc, IRowCallback rowCallback, IDictionary

returnedParameters)

IList

QueryWithCommandCreator(IDbCommandCreator

cc, IRowMapper rowMapper, IDictionary

returnedParameters)

TheIDbCommandCreatorcallbackinterfaceisshownbelow

publicinterfaceIDbCommandCreator

{

IDbCommandCreateDbCommand();

}

Page 484: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The created IDbCommand object is used when performing theQueryWithCommandCreatormethod.Toprocessmultipleresultsetsspecifyalistofnamedresultsetprocessors,( i.e.IResultSetExtractor, IRowCallback, or IRowMapper).Thismethodisshownbelow

IDictionary

QueryWithCommandCreator(IDbCommandCreator

cc,IListnamedResultSetProcessors)

The list must contain objects of the typeSpring.Data.Support.NamedResultSetProcessor. Thisis theclass responsible for associatinganamewith a result setprocessor.Theconstructorsarelistedbelow.

publicclassNamedResultSetProcessor{

publicNamedResultSetProcessor(stringname,IRowMapperrowMapper){...}

publicNamedResultSetProcessor(stringname,IRowCallbackrowcallback){...}

publicNamedResultSetProcessor(stringname,IResultSetExtractorresultSetExtractor){...}

...

}

TheresultsoftheRowMapperorResultSetExtractorareretrievedbynamefromthe dictionary that is returned. RowCallbacks, being stateless, only have theplaceholder text, "ResultSet returnedwasprocessedbyan IRowCallback"asavalueforthenameoftheRowCallbackusedasakey.OutputandInputOutputparameters can be retrieved by name. If this parameter name is null, then theindexoftheparameterprefixedwiththeletter'P'isakeyname,i.eP2,P3,etc.ThenamespaceSpring.Data.Objects.Genericcontainsgenericversionsof thesemethods.Thesearelistedbelow

T QueryWithCommandCreator<T>

(IDbCommandCreator cc,

Page 485: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

IResultSetExtractor<T>rse)

IList<T> QueryWithCommandCreator<T>

(IDbCommandCreator cc, IRowMapper<T>

rowMapper)

andoverloadsthathaveanadditionalcollectingparametertoobtainanyoutputparameters.

T QueryWithCommandCreator<T>

(IDbCommandCreator cc,

IResultSetExtractor<T> rse, IDictionary

returnedParameters)

IList<T> QueryWithCommandCreator<T>

(IDbCommandCreator cc, IRowMapper<T>

rowMapper,IDictionaryreturnedParameters)

Whenprocessingmultipleresultsetsyoucanspecifyuptotwotypesaferesultsetprocessors.

IDictionary QueryWithCommandCreator<T>

(IDbCommandCreator cc, IList

namedResultSetProcessors)

IDictionary QueryWithCommandCreator<T,U>

(IDbCommandCreator cc, IList

namedResultSetProcessors)

The list of result set processors contains either objects of the typeSpring.Data.Generic.NamedResultSetProcessor<T> orSpring.Data.NamedResultSetProcessor. The generic result set processors,NamedResultSetProcessor<T>,isusedtoprocessthefirstresultset in thecaseof using QueryWithCommandCreator<T> and to process the first and secondresult set in the case of using QueryWithCommandCreator<T,U>. AdditionalSpring.Data.NamedResultSetProcessors that are listed can be used to processadditional result sets. If you specify a RowCallback withNamedResultSetProcessor<T>, you still need to specify a type parameter (saystring)becausetheRowCallbackprocessordoesnotreturnanyobject.ItisuptosubclassesofRowCallbacktocollectstateduetoprocessingtheresultsetwhichislaterqueried.

Page 486: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.13.DataTableandDataSetAdoTemplate contains several 'families' ofmethods tohelp removeboilerplatecode and reduce common programming errors when using DataTables andDataSets. There aremanymethods inAdoTemplate so it is easy to feel a bitoverwhelmedwhen takinga lookat theSDKdocumentation.However,afterawhileyouwillhopefullyfindtheclass'easytonavigate'withintellisense.Hereisaquickcategorizationof themethodnamesand their associateddataaccessoperation. Eachmethod is overloaded to handle common cases of passing inparametervalues.The'catch-all'Executemethodsuponwhichotherfunctionalityisbuiltupuponareshownbelow.InSpring.Data.Core.AdoTemplate

object Execute(IDataAdapterCallback

dataAdapterCallback) - Execute ADO.NET operations on aIDbDataAdapterobjectusinganinterfacebasedcallback.

WhereIDataAdapterCallbackisdefinedas

publicinterfaceIDataAdapterCallback

{

objectDoInDataAdapter(IDbDataAdapterdataAdapter);

}

ThepassedinIDbDataAdapterwillhaveitsSelectCommandpropertycreatedandsetwithitsConnectionandTransactionvaluesbasedonthecallingtransactioncontext.Thereturnvalueistheresultofprocessingornull.There are type-safe versions of this method inSpring.Data.Generic.AdoTemplate

T Execute<T>(IDataAdapterCallback<T>

dataAdapterCallback) - Execute ADO.NET operations on aIDbDataAdapterobjectusinganinterfacebasedcallback.

T Execute<T>(DataAdapterDelegate<T> del) -Execute ADO.NET operations on a IDbDataAdapter object using andelegatebasedcallback.

Page 487: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

WhereIDataAdapterCallback<T>andDataAdapterDelegate<T>aredefinedas

publicinterfaceIDataAdapterCallback<T>

{

TDoInDataAdapter(IDbDataAdapterdataAdapter);

}

publicdelegateTDataAdapterDelegate<T>(IDbDataAdapterdataAdapter);

20.13.1.DataTablesDataTable operations are available on the classSpring.Data.Core.AdoTemplate. If you are using the genericversion, Spring.Data.Generic.AdoTemplate, you can accessthese methods through the property ClassicAdoTemplate, which returnsthenon-genericversionofAdoTemplate.DataTableoperationsavailablefallintothegeneralfamilyofmethodswith3-5overloadspermethod.

DataTableCreate-CreateandFillDataTables

DataTableCreateWithParameters - Create and FillDataTablesusingaparametercollection.

DataTableFill-Fillapre-existingDataTable.

DataTableFillWithParameters - Fill a pre-existingDataTableusingaparametercollection.

DataTableUpdate - Update the database using the providedDataTable,insert,update,deleteSQL.

DataTableUpdateWithCommandBuilder - Update thedatabaseusingtheprovidedDataTable,selectSQL,andparameters.

20.13.2.DataSetsDataSet operations are available on the classSpring.Data.Core.AdoTemplate. If you are using the genericversion, Spring.Data.Generic.AdoTemplate, you can accessthese methods through the property ClassicAdoTemplate, which returnsthenon-genericversionofAdoTemplate.DataSetoperationsavailable fall intothefollowingfamilyofmethodswith3-5overloadspermethod.

Page 488: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

DataSetCreate-CreateandFillDataSets

DataSetCreateWithParameters-CreateandFillDataTablesusingaparametercollection.

DataSetFill-Fillapre-existingDataSet

DataSetFillWithParameters - Fill a pre-existing DataTableusingparametercollection.

DataSetUpdate - Update the database using the providedDataSet,insert,update,deleteSQL.

DataSetUpdateWithCommandBuilder-UpdatethedatabaseusingtheprovidedDataSet,selectSQL,andparameters.

The following code snippets demonstrate the basic functionality of thesemethods using theNorthwind database. See theSDKdocumentation formoredetailsonotheroverloadedmethods.

publicclassDataSetDemo:AdoDaoSupport

{

privatestringselectAll=@"selectAddress,City,CompanyName,ContactName,"

"ContactTitle,Country,Fax,CustomerID,Phone,PostalCode,"

"RegionfromCustomers";

publicvoidDemoDataSetCreate()

{

DataSetcustomerDataSet=AdoTemplate.DataSetCreate(CommandType.Text,selectAll);

//customerDataSethasatablenamed'Table'with91rows

customerDataSet=AdoTemplate.DataSetCreate(CommandType.Text,selectAll,

//customerDataSethasatablenamed'Customers'with91rows

}

publicvoidDemoDataSetCreateWithParameters()

{

stringselectLike=@"selectAddress,City,CompanyName,ContactName,"

Page 489: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

"ContactTitle,Country,Fax,CustomerID,Phone,PostalCode,"

"RegionfromCustomerswhereContactNamelike@ContactName"

DbParametersdbParameters=CreateDbParameters();

dbParameters.Add("ContactName",DbType.String).Value="M%';

DataSetcustomerLikeMDataSet=AdoTemplate.DataSetCreateWithParams(CommandType.Text,selectLike,dbParameters);

//customerLikeMDataSethasatablenamed'Table'with12rows

}

publicvoidDemoDataSetFill()

{

DataSetdataSet=newDataSet();

dataSet.Locale=CultureInfo.InvariantCulture;

AdoTemplate.DataSetFill(dataSet,CommandType.Text,selectAll);

}

UpdatingaDataSetcanbedoneusingaCommandBuilder,automaticallycreatedfrom the specified select command and select parameters, or by explicitlyspecifying the insert, update, delete commands and parameters. Below is anexample,refertotheSDKdocumentationforadditionaloverloads

publicclassDataSetDemo:AdoDaoSupport

{

privatestringselectAll=@"selectAddress,City,CompanyName,ContactName,"

"ContactTitle,Country,Fax,CustomerID,Phone,PostalCode,"

"RegionfromCustomers";

publicvoidDemoDataSetUpdateWithCommandBuilder()

{

DataSetdataSet=newDataSet();

dataSet.Locale=CultureInfo.InvariantCulture;

AdoTemplate.DataSetFill(dataSet,CommandType.Text,selectAll,

AddAndEditRow(dataSet);.

AdoTemplate.DataSetUpdateWithCommandBuilder(dataSet,CommandType.Text,selectAll,

}

publicvoidDemoDataSetUpdateWithoutCommandBuilder()

{

DataSetdataSet=newDataSet();

Page 490: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

dataSet.Locale=CultureInfo.InvariantCulture;

AdoTemplate.DataSetFill(dataSet,CommandType.Text,selectAll,

AddAndEditRow(dataSet);.

stringinsertSql=@"INSERTCustomers(CustomerID,CompanyName)VALUES(@CustomerId,@CompanyName)"

IDbParametersinsertParams=CreateDbParameters();

insertParams.Add("CustomerId",DbType.String,0,"CustomerId"

insertParams.Add("CompanyName",DbType.String,0,"CompanyName"

stringupdateSql=@"updateCustomersSETPhone=@PhonewhereCustomerId=@CustomerId"

IDbParametersupdateParams=CreateDbParameters();

updateParams.Add("Phone",DbType.String,0,"Phone");//.Value="030-0074322";//simplechange,lastdigitchangedfrom1to2.

updateParams.Add("CustomerId",DbType.String,0,"CustomerId"

AdoTemplate.DataSetUpdate(dataSet,"Customers",

CommandType.Text,insertSql,insertParams,

CommandType.Text,updateSql,updateParams,

CommandType.Text,null

}

privatestaticvoidAddAndEditRow(DataSetdataSet)

{

DataRowdataRow=dataSet.Tables["Customers"].NewRow();

dataRow["CustomerId"]="NewID";

dataRow["CompanyName"]="NewCompanyName";

dataRow["ContactName"]="NewName";

dataRow["ContactTitle"]="NewContactTitle";

dataRow["Address"]="NewAddress";

dataRow["City"]="NewCity";

dataRow["Region"]="NR";

dataRow["PostalCode"]="NewCode";

dataRow["Country"]="NewCountry";

dataRow["Phone"]="NewPhone";

dataRow["Fax"]="NewFax";

dataSet.Tables["Customers"].Rows.Add(dataRow);

DataRowalfkiDataRow=dataSet.Tables["Customers"].Rows[0];

alfkiDataRow["Phone"]="030-0074322";//simplechange,lastdigitchangedfrom1to2.

}

}

Page 491: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

In the case of needing to set parameter SourceColumn or SourceVersionpropertiesitmaybemoreconvenienttouseIDbParameterBuilder.

Page 492: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.14. TableAdapters and participation in transactionalcontextTyped DataSets need to have commands in their internal DataAdapters andcommand collections explicitly set with a connection/transaction in order forthem to correctly participate with a surrounding transactional context. Thereason for this is by default the code generated is explicitly managing theconnections and transactions. This issue is very well described in the articleSystem.TransactionsandADO.NET2.0byADO.NETguruSahilMalik.Springoffersaconveniencemethod thatwilluse reflection to internally set the transactiononthetableadapter'sinternalcommandcollectiontotheambienttransaction.Thismethod on the classSpring.Data.Support.TypedDataSetUtils and is namedApplyConnectionAndTx.HereissampleusageofaDAOmethodthatusesaVS.NET2005generatedtypeddatasetforaPrintGroupMappingtable.

publicPrintGroupMappingDataSetFindAll()

{

PrintGroupMappingTableAdapteradapter=newPrintGroupMappingTableAdapter();

PrintGroupMappingDataSetprintGroupMappingDataSet=newPrintGroupMappingDataSet();

printGroupMappingDataSet=AdoTemplate.Execute(delegate(IDbCommandcommand)

{

TypedDataSetUtils.ApplyConnectionAndTx(adapter,command);

adapter.Fill(printGroupMappingDataSet.PrintGroupMapping);

returnprintGroupMappingDataSet;

})

asPrintGroupMappingDataSet;

returnprintGroupMappingDataSet;

}

This DAO method may be combined with other DAO operations inside atransactional context and they will all share the same connection/transactionobjects.TherearetwooverloadsofthemethodApplyConnectionAndTxwhichdifferin

Page 493: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

the second method argument, one takes an IDbCommand and the otherIDbProvider.Thesearelistedbelow

publicstaticvoidApplyConnectionAndTx(objecttypedDataSetAdapter,IDbCommandsourceCommand)

publicstaticvoidApplyConnectionAndTx(objecttypedDataSetAdapter,IDbProviderdbProvider)

The method that takes IDbCommand is a convenience if you will be usingAdoTemplatecallback'sas thepassed incommandobjectwill alreadyhave itsconnection and transaction properties set based on the current transactionalcontext.Themethod that takes an IDbProvider is convenient tousewhenyouhavedataaccesslogicthatisnotcontainedwithinasinglecallbackmethodbutisinsteadspeadamongmultipleclasses.Inthiscasepassingthetransactionallyaware IDbCommandobject canbe intrusiveon themethod signatures. Insteadyou can pass in an instance of IDbProvider that can be obtained via standarddependencyinjectiontechniquesorviaaservicelocatorstylelookup.

Page 494: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

20.15.DatabaseoperationsasObjectsThe Spring.Data.Objects and

Spring.Data.Objects.Genericnamespacescontainsclassesthatallowonetoaccessthedatabaseinamoreobject-orientedmanner.Bywayofanexample, one can execute queries and get the results back as a list containingbusinessobjectswiththerelationalcolumndatamappedtothepropertiesofthebusinessobject.Onecanalsoexecutestoredproceduresandrunupdate,deleteandinsertstatements.

Note

ThereisaviewbornefromexperienceacquiredinthefieldamongstsomeoftheSpringdevelopersthatthevariousRDBMSoperationclassesdescribedbelow(withtheexceptionoftheStoredProcedureclass)canoftenbereplacedwithstraightAdoTemplatecalls...oftenitissimplertouseandplaineasiertoreadaDAOmethodthatsimplycallsamethodonaAdoTemplatedirect(asopposedtoencapsulatingaqueryasafull-blownclass).Itmustbestressedhoweverthatthisisjustaview...ifyoufeelthatyouaregettingmeasurablevaluefromusingtheRDBMSoperationclasses,feelfreetocontinueusingtheseclasses.

20.15.1.AdoQueryAdoQuery is a reusable, threadsafe class that encapsulates an SQL query.SubclassesmustimplementtheNewRowMapper(..)methodtoprovideaIRowMapper instance that can create one object per row obtained fromiteratingovertheIDataReader that iscreatedduringtheexecutionof thequery. The AdoQuery class is rarely used directly since theMappingAdoQuery subclass provides a much more convenientimplementation for mapping rows to .NET classes. Another implementationsthat extendsAdoQuery isMappingadoQueryWithParameters(SeeSDKdocsfordetails).The AdoNonQuery class encapsulates an IDbCommand 'sExecuteNonQuery method functionality. Like the AdoQuery object, anAdoNonQuery object is reusable, and like allAdoOperationclasses,

Page 495: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

anAdoNonQuery can have parameters and is defined in SQL. This classprovidestwoexecutemethods

IDictionary ExecuteNonQuery(params object[]

inParameterValues)

IDictionary

ExecuteNonQueryByNamedParam(IDictionary

inParams)

This class is concrete. Although it can be subclassed (for example to add acustom update method) it can easily be parameterized by setting SQL anddeclaringparameters.An exampleof anAdoQuery subclass to encapsulate an insert statement for a'TestObject'(consistingonlynameandagecolumns)isshownbelow

publicclassCreateTestObjectNonQuery:AdoNonQuery

{

privatestaticstringsql="insertintoTestObjects(Age,Name)values(@Age,@Name)"

publicCreateTestObjectNonQuery(IDbProviderdbProvider):

{

DeclaredParameters.Add("Age",DbType.Int32);

DeclaredParameters.Add("Name",SqlDbType.NVarChar,16);

Compile();

}

publicvoidCreate(stringname,intage)

{

ExecuteNonQuery(name,age);

}

}

20.15.2.MappingAdoQueryMappingAdoQueryisareusablequeryinwhichconcretesubclassesmustimplement the abstract MapRow(..) method to convert each row of thesuppliedIDataReader into an object. Find below a brief example of acustom query that maps the data from a relation to an instance of the

Page 496: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Customerclass.

publicclassTestObjectQuery:MappingAdoQuery

{

privatestaticstringsql="selectTestObjectNo,Age,NamefromTestObjects"

publicTestObjectQuery(IDbProviderdbProvider)

:base(dbProvider,sql)

{

CommandType=CommandType.Text;

}

protectedoverrideobjectMapRow(IDataReaderreader,int

{

TestObjectto=newTestObject();

to.ObjectNumber=reader.GetInt32(0);

to.Age=reader.GetInt32(1);

to.Name=reader.GetString(2);

returnto;

}

}

20.15.3.AdoNonQueryThe AdoNonQuery class encapsulates an IDbCommand 'sExecuteNonQuery method functionality. Like the AdoQuery object, anAdoNonQuery object is reusable, and like allAdoOperationclasses,anAdoNonQuery can have parameters and is defined in SQL. This classprovidestwoexecutemethods

IDictionary ExecuteNonQuery(params object[]

inParameterValues)

IDictionary

ExecuteNonQueryByNamedParam(IDictionary

inParams)

This class is concrete. Although it can be subclassed (for example to add acustom update method) it can easily be parameterized by setting SQL anddeclaringparameters.

Page 497: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassCreateTestObjectNonQuery:AdoNonQuery

{

privatestaticstringsql="insertintoTestObjects(Age,Name)values(@Age,@Name)"

publicCreateTestObjectNonQuery(IDbProviderdbProvider):

{

DeclaredParameters.Add("Age",DbType.Int32);

DeclaredParameters.Add("Name",SqlDbType.NVarChar,16);

Compile();

}

publicvoidCreate(stringname,intage)

{

ExecuteNonQuery(name,age);

}

}

20.15.4.StoredProcedureTheStoredProcedureclassisdesignedtomakeitassimpleaspossibletocallastoredprocedure.Ittakesadvantageofmetadatapresentinthedatabasetolookupnamesofinandoutparameters..Thismeansthatyoudon'thavetoexplicitlydeclareparameters.Youcanofcoursestilldeclarethemifyouprefer.Therearetwoversionsof theStoredProcedureclass,one thatusesgenericsandone thatdoesn't.UsingtheStoredProcedureclassconsistsoftwosteps,firstdefiningthein/out parameter and any object mappers and second executing the storedprocedure.The non-generic version of StoredProcedure is in the namespaceSpring.Data.Objects. It contains the following methods to execute a storedprocedure

IDictionary ExecuteScalar(params object[]

inParameterValues)

IDictionary

ExecuteScalarByNamedParam(IDictionary

inParams)

IDictionary ExecuteNonQuery(params object[]

Page 498: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

inParameterValues)

IDictionary

ExecuteNonQueryByNamedParam(IDictionary

inParams)

IDictionary Query(params object[]

inParameterValues)

IDictionary QueryByNamedParam(IDictionary

inParams)

Each of these methods returns anIDictionary that contains the outputparameters and/or any results from Spring's object mapping framework. Theargumentstothesemethodscanbeavariablelengthargumentlist,inwhichcasethe order must match the parameter order of the stored procedure. If theargumentisanIDictionaryitcontainsparameterkey/valuepairs.Returnvaluesfromstoredproceduresarecontainedunderthekey"RETURN_VALUE".The standard in/out parameters for the stored procedure can be setprogrammaticallybyaddingtotheparametercollectionexposedbythepropertyDeclaredParameters. For each result sets that is returned by the storedprocedures you can registering either an IResultSetExtractor,IRowCallback,orIRowMapperbyname,whichisusedlatertoextractthemappedresultsfromthereturnedIDictionary.Letstakealookatanexample.ThefollowingstoredprocedureclasswillcalltheCustOrdersDetail stored procedure in the Northwind database, passing in theOrderID as a stored procedure argument and returning a collection ofOrderDetailsbusinessobjects.

publicclassCustOrdersDetailStoredProc:StoredProcedure

{

privatestaticstringprocedureName="CustOrdersDetail"

publicCustOrdersDetailStoredProc(IDbProviderdbProvider):

{

DeriveParameters();

AddRowMapper("orderDetailRowMapper",newOrderDetailRowMapper());

Compile();

}

Page 499: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicvirtualIListGetOrderDetails(intorderid)

{

IDictionaryoutParams=Query(orderid);

returnoutParams["orderDetailRowMapper"]asIList;

}

}

The 'DeriveParameters' method saves you the trouble of having todeclare eachparameter explicitly.WhenusingDeriveParameters is itoften common to use the Query method that takes a variable length list ofarguments. This assumes additional knowledge on the order of the storedprocedure arguments. If you do not want to follow this loose shorthandconvention, you can call the method QueryByNamesParametersinsteadpassinginaIDictionaryofparameterkey/valuepairs.

Note

Ifyouwouldliketohavethereturnvalueofthestoredprocedureincludedinthereturneddictionary,passintrueasamethodparametertoDeriveParameters().

TheStoredProcedureclass is threadsafeonce 'compiled',anactwhichisusuallydoneintheconstructor.Thissetsupthecacheofdatabaseparametersthat can be used on each call to Query or QueryByNamedParam. TheimplementationofIRowMapperthatisusedtoextractthebusinessobjectsis'registered'withtheclassandthenlaterretrievedbynameasafictionaloutputparameter. You may also register IRowCallback andIResultSetExtractor callback interfaces via theAddRowCallbackandAddResultSetExtractormethods.The generic version of StoredProcedure is in the namespaceSpring.Data.Objects.Generic. It allows you to define up to two generic typeparameters that will be used to process result sets returned from the storedprocedure.Anexampleisshownbelow

publicclassCustOrdersDetailStoredProc:StoredProcedure

{

Page 500: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

privatestaticstringprocedureName="CustOrdersDetail"

publicCustOrdersDetailStoredProc(IDbProviderdbProvider):

{

DeriveParameters();

AddRowMapper("orderDetailRowMapper",newOrderDetailRowMapper<OrderDetails>());

Compile();

}

publicvirtualList<OrderDetails>GetOrderDetails(int

{

IDictionaryoutParams=Query<OrderDetails>(orderid);

returnoutParams["orderDetailRowMapper"]asList<OrderDetails>;

}

}

YoucanfindreadytoruncodedemonstratingtheStoredProcedureclass in theexample'DataAccess'thatispartoftheSpring.NETdistribution.

Page 501: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter21.ObjectRelationalMapping(ORM)dataaccess

Page 502: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

21.1.IntroductionThe Spring Framework provides integration with NHibernate in terms ofresourcemanagement,DAOimplementationsupport,andtransactionstrategies.For example for NHibernate, there is first-class support with lots of IoCconvenience features, addressing many typical NHibernate integration issues.AllofthesesupportpackagesforO/R(ObjectRelational)mapperscomplywithSpring'sgeneric transactionandDAOexceptionhierarchies.There are usuallytwo integration styles: either using Spring'sDAO 'templates' or codingDAOsagainst the 'plain' NHibernate APIs. In both cases, DAOs can be configuredthrough Dependency Injection and participate in Spring's resource andtransactionmanagement.YoucanuseSpring'ssupportforNHibernatewithoutneedingtouseSpringIoCortransactionmanagementfunctionality.TheNHibernatesupportclassescanbeused in typical 3rd party library style. However, usage inside a Spring IoCcontainerdoesprovideadditionalbenefitsintermsofeaseofconfigurationanddeployment;assuch,mostexamplesinthissectionshowconfigurationinsideaSpringcontainer.SomeofthebenefitsofusingtheSpringFrameworktocreateyourORMDAOsinclude:

Ease of testing. Spring's IoC approach makes it easy to swap theimplementationsandconfiglocationsofHibernateSessionFactoryinstances,ADO.NETDbProviderinstances,transactionmanagers,andmapper object implementations (if needed).Thismakes itmuch easier toisolateandtesteachpieceofpersistence-relatedcodeinisolation.

Common data access exceptions. Spring can wrap exceptions from yourO/Rmapping toolofchoice,converting themfromproprietaryexceptionsto a common runtime DataAccessException hierarchy. You can still trapand handle exceptions anywhere you need to. Remember thatADO.NETexceptions(includingDBspecificdialects)arealsoconvertedtothesamehierarchy,meaningthatyoucanperformsomeoperationswithADO.NETwithinaconsistentprogrammingmodel.

Generalresourcemanagement.Springapplicationcontextscanhandle thelocation and configuration of Hibernate ISessionFactory

instances, ADO.NET DbProvider instances and other related

Page 503: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

resources. This makes these values easy to manage and change. Springoffers efficient, easy and safe handling of persistence resources. Forexample: related code usingNHibernate generally needs to use the sameNHibernate Session for efficiency and proper transaction handling.SpringmakesiteasytotransparentlycreateandbindaSession to thecurrent thread, either by using an explicit 'template' wrapper class at thecode level or by exposing a current Session through the HibernateSessionFactory (for DAOs based on plain Hibernate 1.2 API).Thus Spring solvesmany of the issues that repeatedly arise from typicalNHibernateusage,foranytransactionenvironment(localordistributed).

Integrated transactionmanagement. Spring allows you towrap yourO/Rmappingcodewitheitheradeclarative,AOPstylemethodinterceptor,oranexplicit'template'wrapperclassatthecodelevel.Ineithercase,transactionsemantics are handled for you, and proper transaction handling (rollback,etc)incaseofexceptionsistakencareof.Asdiscussedbelow,youalsogetthe benefit of being able to use and swap various transaction managers,without your Hibernate/ADO.NET related code being affected: forexample, between local transactions and distributed, with the same fullservices(suchasdeclarativetransactions)availableinbothscenarios.Asanadditional benefit, ADO.NET-related code can fully integratetransactionallywiththecodeyouusetodoO/Rmapping.Thisisusefulfordataaccess that'snot suitable forO/Rmappingwhich stillneeds to sharecommontransactionswithORMoperations.

The NHibernate Northwind example in the Spring distribution shows aNHibernate implementation of a persistence-technology agnostic DAOinterfaces. (In the upcoming RC1 release the SpringAir example willdemonstrateanADO.NETandNHibernatebasedimplementationoftechnologyagnostic DAO interfaces.) The NHibernate Northwind example serves as aworking sample application that illustrates the use of NHibernate in a Springweb application. It also leverages declarative transaction demarcation withdifferenttransactionstrategies.BothNHibernate1.0andNHibernate1.2aresupported.Differencesrelatetotheuseofgenericsandnewfeaturessuchascontextualsessions.Forinformationonthelatter,refertothesectionImplementingDAOsbasedontheplainNHibernateAPI.TheNHibernate1.0support is in theassemblySpring.Data.NHibernateand the1.2supportisintheassemblySpring.Data.NHibernate12

Page 504: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

At the moment the only ORM supported in NHibernate, but others can beintegrated with Spring (in as much as makes sense) to offer the same valueproposition.

Page 505: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

21.2.NHibernateWewillstartwithacoverageofNHibernate inaSpringenvironment,using it todemonstrate the approach that Spring takes towards integrating O/Rmappers.This sectionwill covermany issues in detail and show different variations ofDAOimplementationsandtransactiondemarcations.MostofthesepatternscanbedirectlytranslatedtoallothersupportedO/Rmappingtools.ThefollowingdiscussionfocusesonHibernate1.0.4,themajordifferenceswithNHibernate 1.2 being the ability to participate in Spring transaction/sessionmanagementviathenormalNHibernateAPIinsteadofthe'template'approach.SpringsupportsbothNHibernate1.0andNHibernate1.2viaseparate.dllswiththesameinternalnamespace.

21.2.1.ResourcemanagementTypical business applications are often cluttered with repetitive resourcemanagementcode.Manyprojectstrytoinventtheirownsolutionsforthisissue,sometimessacrificingproperhandlingoffailuresforprogrammingconvenience.Spring advocates strikingly simple solutions for proper resource handling,namely IoC via templating; for example infrastructure classes with callbackinterfaces, or applying AOP interceptors. The infrastructure cares for properresourcehandling,andforappropriateconversionofspecificAPIexceptionstoacommoninfrastructureexceptionhierarchy.SpringintroducesaDAOexceptionhierarchy, applicable to any data access strategy. For direct ADO.NET, theAdoTemplate classmentioned in a previous section cares for connectionhandling, and for proper conversion ofADO.NETdata access exceptions (noteven singly rooted in .NET 1.1) to Spring's DataAccessExceptionhierarchy, including translation of database-specific SQL error codes tomeaningfulexceptionclasses.Itsupportsbothdistributedandlocaltransactions,viarespectiveSpringtransactionmanagers.Spring also offers Hibernate support, consisting of aHibernateTemplate analogous to AdoTemplate, aHibernateInterceptor, and a Hibernate transaction manager. Themajorgoal is to allow for clear application layering,with anydata access andtransaction technology,and for loosecouplingofapplicationobjects.Nomorebusinessservicedependenciesonthedataaccessortransactionstrategy,nomorehard-coded resource lookups, no more hard-to-replace singletons, no more

Page 506: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

custom service registries. One simple and consistent approach to wiring upapplicationobjects,keepingthemasreusableaspossible.Alltheindividualdataaccess features are usable on their own but integrate nicely with Spring'sapplication context concept, providing XML-based configuration and cross-referencing of plain object instances that don't need to be Spring-aware. In atypicalSpringapplication,manyimportantobjectsareplain.NETobjects:dataaccess templates, data access objects (that use the templates), transactionmanagers, business services (that use the data access objects and transactionmanagers),ASP.NETwebpages(thatusethebusinessservices),andsoon.

21.2.2.TransactionManagementWhile NHibernate offers an API for transaction management you will quitelikely find the benefits of using Spring's generic transaction managementfeatures to be more compelling to use, typically for use of a declarativeprogrammingmodel for transaction demarcation and easilymixingADO.NETand NHibernate operations within a single transaction. See the chapter ontransaction management for more information on Spring's transactionmanagement features. There are two choices for transaction managementstrategies, one based on the NHibernate API and the other the .NET 2.0TransactionScopeAPI.The first strategy is encapsulated in the classSpring.Data.NHibernate.HibernateTransactionManager

in both theSpring.Data.NHibernatenamespace. This strategy ispreferredwhenyouareusingasingledatabase.ADO.NEToperationscanalsoparticipateinthesametransaction,eitherbyusingAdoTemplateorbyretrievingtheADO.NETconnection/transactionobjectpair stored in thread local storagewhenthetransactionbegins.RefertothedocumentationofSpring'sADO.NETframework for more information on retrieving and using theconnection/transaction pair without using AdoTemplate. You can use theHibernateTransactionManager and associated classes such as SessionFactory,HibernateTemplatedirectlyasyouwouldanythirdpartyAPI,howevertheyaremost commonly used through Spring's XML configuration file to gain thebenefits of easy configuration for a particular runtime environment and as thebasisfortheconfigurationofadataaccesslayeralsoconfiguredusingXML.AnXML fragment showing the declaration ofHibernateTransactionManagerisshownbelow.

Page 507: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="HibernateTransactionManager"

type="Spring.Data.NHibernate.HibernateTransactionManager,Spring.Data.NHibernate"

<propertyname="DbProvider"ref="DbProvider"/>

<propertyname="SessionFactory"ref="MySessionFactory"/>

</object>

TheimportantpropertyofHibernateTransactionManagerarethereferences to the DbProvider and the Hibernate ISessionFactory. For moreinformationontheDbProvider,refertothechapterDbProviderandthefollowingsectiononSessionFactorysetup.The second strategy is to use the classSping.Data.TxScopeTransactionManagerthatuses.NET2.0System.Transaction namespace and its corresponding TransactionScope API.This is preferredwhenyou are usingmultiple transactional resources, such asmultipledatabases.BothstrategiesassociateoneHibernateSessionforthescopeofthetransaction(scopeinthegeneraldemarcationsense,notSystem.Transactionsense).Ifthereis no transaction then a new Session will be opened for each operation. Theexceptionto thisrule iswhenusing theOpenSessionInViewModulein a web application in single session mode (see Section 21.2.10, “Web SessionManagement”). In this case the session will be created on the start of the webrequestandclosedontheendoftherequest.Notethatthesession'sflushmodewill be set toFlushMode.NEVER at the start of the request. If a non-readonly transaction is performed, then during the scope of that transactionprocessing the flush mode will be changed to AUTO, and then set back toNEVER at the end of the transaction scope so that any changes to objectsassociatedwith the session during renderingwill not be persisted back to thedatabasewhenthesessionisclosedattheendofthewebrequest.

21.2.3.SessionFactorysetupinaSpringcontainerToavoidtyingapplicationobjectstohard-codedresourcelookups,Springallowsyou to define resources like a DbProvider or a HibernateSessionFactoryasobjectsinanapplicationcontext.Applicationobjectsthat need to access resources just receive references to such pre-defined

Page 508: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

instancesviaobjectreferences(theDAOdefinitioninthenextsectionillustratesthis).ThefollowingexcerptfromanXMLapplicationcontextdefinitionshowshow to set up Spring's ADO.NET DbProvider and a HibernateSessionFactoryontopofit:

<objectsxmlns="http://www.springframework.net"

xmlns:db="http://www.springframework.net/database">

<!--Propertyplaceholderconfigurerfordatabasesettings-->

<objecttype="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer,Spring.Core"

<propertyname="ConfigSections"value="databaseSettings"

</object>

<!--DatabaseandNHibernateConfiguration-->

<db:providerid="DbProvider"

provider="SqlServer-1.1"

connectionString="IntegratedSecurity=false;DataSource=(local);IntegratedSecurity=true;Database=Northwin;UserID=springqa;Password=springqa;"

<objectid="MySessionFactory"type="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate"

<propertyname="DbProvider"ref="DbProvider"/>

<propertyname="MappingAssemblies">

<list>

<value>Spring.Northwind.Dao.NHibernate</value>

</list>

</property>

<propertyname="HibernateProperties">

<dictionary>

<entrykey="hibernate.connection.provider"

value="NHibernate.Connection.DriverConnectionProvider"

<entrykey="hibernate.dialect"

value="NHibernate.Dialect.MsSql2000Dialect"/>

<entrykey="hibernate.connection.driver_class"

value="NHibernate.Driver.SqlClientDriver"/>

Page 509: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</dictionary>

</property>

</object>

</objects>

Manyof thepropertiesonLocalSessionFactoryObjectare thoseyou will commonly configure, for example the propertyMappingAssembliesspecifiesalistofassembliestoseachforhibernatemapping files. The property HibernateProperies are the familiarNHibernatepropertiesusedtosettypicaloptionssuchasdialectanddriverclass.The location of NHibernate mapping information can also be specified usingSpring's IResource abstraction via the property MappingResources. TheIResource abstraction supports opening an input stream from assemblies, filesystem,andhttp(s)basedonaUrisyntax.Youcanalsoleveragetheextensibilityof IResource and thereby allow NHibernate to obtain its configurationinformationfromlocationssuchasadatabaseorLDAP.Forotherpropertiesyoucan configure them as you normal using the filehibernate.cfg.xmland refer to it via the propertyConfigFileNames. This property is astringarraysomultipleconfigurationfilesaresupported.There are other properties in LocalSessionFactoryObject thatrelate to the integration of Spring with NHibernate. The propertyExposeTransactionAwareSessionFactory is discussedbelow and allows you to use Spring's declarative transaction demarcationfunctionality with the standard NHibernate API (as compared to usingHibernateTemplate).ThepropertyDbProvider is used to infer twoNHibernate configurationsoptions.

Infer the connection string, typically done via the hibernate property"hibernate.connection.connection_string".

Delegate to the DbProvider itself as the NHibernate connectionproviderinsteadoflistingitviapropertyhibernate.connection.providerviaHibernateProperties.

If you specifyboth thepropertyhibernate.connection.provider andDbProvider

Page 510: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

(as shown above) the configuration of the propertyhibernate.connection.providerisusedandawarninglevelmessageislogged. IfyouuseSpring'sDbProvider as theNHibernate connectionprovider thenyoucantakeadvantageofIDbProvider implementationsthatwillletyouchange the connection string at runtime such as UserCredentialsDbProvider andMultiDelegatingDbProvider.

Note

UserCredentialsDbProviderandMultiDelegatingDbProvideronlychangetheconnectionstringatruntimebasedonvaluesinthreadlocalstorageanddonotclearouttheHibernatecachethatisuniquetoeachISessionFactoryinstance.Assuch,theyareonlyusefulforselectingatruntimeasingledatabaseinstance.Cleaningupanexistingsessionfactorywhenswitchingtoanewdatabaseislefttousercode.Creatinganewsessionfactoryperconnectionstring(assumingthesamemappingfilescanbeusedacrossalldatabasesconnections)isnotcurrentlysupported.Tosupportthisfunctionality,youcansubclassLocalSessionFactoryObjectandoverridethemethodISessionFactoryNewSessionFactory(Configurationconfig)sothatitreturnsanimplementationofISessionFactorythatselectsamongmultipleinstancesbasedonvaluesinthreadlocalstorage,muchliketheimplementationofMultiDelegatingDbProvider.

21.2.4.TheHibernateTemplateThebasicprogrammingmodelfortemplatinglooksasfollowsformethods thatcanbepartofanycustomdataaccessobjectorbusinessservice.Therearenorestrictionsontheimplementationofthesurroundingobjectatall, it justneedsto provide a Hibernate SessionFactory. It can get the latter fromanywhere,butpreferably as anobject reference fromaSpring IoCcontainer -via a simple SessionFactory property setter. The following snippetsshow a DAO definition in a Spring container, referencing the above definedSessionFactory,andanexampleforaDAOmethodimplementation.

<objects>

Page 511: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="CustomerDao"type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao,Spring.Northwind.Dao.NHibernate"

<propertyname="SessionFactory"ref="MySessionFactory"/>

</object>

</objects>

publicclassHibernateCustomerDao:ICustomerDao{

privateHibernateTemplatehibernateTemplate;

publicISessionFactorySessionFactory

{

set{hibernateTemplate=newHibernateTemplate(value);}

}

publicCustomerSaveOrUpdate(Customercustomer)

{

hibernateTemplate.SaveOrUpdate(customer);

returncustomer;

}

}

TheHibernateTemplate classprovidesmanymethods thatmirror themethodsexposedontheHibernateSessioninterface,inadditiontoanumberofconveniencemethodssuchastheoneshownabove.IfyouneedaccesstotheSession to invoke methods that are not exposed on theHibernateTemplate, you can always drop down to a callback-basedapproachlikeso.

publicclassHibernateCustomerDao:ICustomerDao{

privateHibernateTemplatehibernateTemplate;

publicISessionFactorySessionFactory

{

set{hibernateTemplate=newHibernateTemplate(value);}

}

publicCustomerSaveOrUpdate(Customercustomer)

{

Page 512: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

returnHibernateTemplate.Execute(

delegate(ISessionsession)

{

//dowhateveryouwantwiththesession....

session.SaveOrUpdate(customer);

returncustomer;

})asCustomer;

}

}

Using the anonymous delegate is particularly convenient when you wouldotherwise be passing various method parameter calls to the interface basedversionof this callback.Furthermore,whenusing generics, you can avoid thetypecastandwritecodelikethefollowing

IList<Supplier>suppliers=HibernateTemplate.ExecuteFind<Supplier>(

delegate(ISessionsession)

{

returnsession.CreateQuery("fromSuppliersweres.Code=?"

.SetParameter(0,code)

.List<Supplier>();

});

where code is a variable in the surrounding block, accessible inside theanonymousdelegateimplementation.AcallbackimplementationeffectivelycanbeusedforanyHibernatedataaccess.HibernateTemplatewillensurethatSessioninstancesareproperlyopened and closed, and automatically participate in transactions. The templateinstances are thread-safe and reusable, they can thus be kept as instancevariables of the surrounding class. For simple single step actions like a singleFind, Load, SaveOrUpdate, orDelete call,HibernateTemplate offersalternative convenience methods that can replace such one line callbackimplementations. Furthermore, Spring provides a convenientHibernateDaoSupport base class that provides aSessionFactorypropertyforreceivingaSessionFactoryandforuse by subclasses. In combination, this allows for very simple DAOimplementationsfortypicalrequirements:

Page 513: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassHibernateCustomerDao:HibernateDaoSupport,ICustomerDao

{

publicCustomerSaveOrUpdate(Customercustomer)

{

HibernateTemplate.SaveOrUpdate(customer);

returncustomer;

}

}

21.2.5.ImplementingSpring-basedDAOswithoutcallbacksAs an alternative to using Spring'sHibernateTemplate to implementDAOs, data access code can also be written in a more traditional fashion,withoutwrappingtheHibernateaccesscodeinacallback,whilestillrespectingandparticipatinginSpring'sgenericDataAccessExceptionhierarchy.TheHibernateDaoSupport base class offers methods to access thecurrent transactionalSessionand toconvertexceptions insucha scenario;similar methods are also available as static helpers on theSessionFactoryUtils 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 (whichavoidstheneedtoclosethereturnedSession,asitslifecycleismanagedbythetransaction).Askingforthe

publicclassHibernateProductDao:HibernateDaoSupport,IProductDao{

publicCustomerSaveOrUpdate(Customercustomer)

{

ISessionsession=DoGetSession(false);

session.SaveOrUpdate(customer);

returncustomer;

}

}

}

This code will not translate the Hibernate exception to a genericDataAccessException.

Page 514: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

21.2.6. Implementing DAOs based on plain Hibernate1.2/2.0APIHibernate1.2introducedafeaturecalled"contextualSessions",whereHibernateitself manages one current ISession per transaction. This is roughlyequivalent to Spring's synchronization of one Hibernate Session pertransaction.AcorrespondingDAOimplementationlookslikeasfollows,basedontheplainHibernateAPI:

publicclassProductDaoImplimplementsIProductDao{

privateSessionFactorysessionFactory;

publicISessionFactorySessionFactory

{

get{returnsessionFactory;}

set{sessionFactory=value;}

}

publicIList<Product>LoadProductsByCategory(Stringcategory){

returnSessionFactory.GetCurrentSession()

.CreateQuery("fromtest.Productproductwhereproduct.category=?"

.SetParameter(0,category)

.List<Product>();

}

}

publicclassHibernateCustomerDao:ICustomerDao{

privateISessionFactorysessionFactory;

publicISessionFactorySessionFactory

{

set{sessionFactory=value;}

}

publicCustomerSaveOrUpdate(Customercustomer)

{

sessionFactory.GetCurrentSession().SaveOrUpdate(customer);

returncustomer;

Page 515: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

}

TheaboveDAOfollows theDependencyInjectionpattern: it fitsnicely into aSpring IoC container, just like it would if coded against Spring'sHibernateTemplate.Ofcourse,suchaDAOcanalsobesetupinplainC# (for example, in unit tests): simply instantiate it and callSessionFactorypropertywiththedesiredfactoryreference.AsaSpringobjectdefinition,itwouldlookasfollows:

<objects>

<objectid="CustomerDao"type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao,Spring.Northwind.Dao.NHibernate"

<propertyname="sessionFactory"ref="MySessionFactory"/>

</object>

</objects>

The SessionFactory configuration to support this programming model can bedone twoways, bothvia configurationofSpring'sLocalSessionFactoryObject.YoucanenabletheuseofSpring'simplementationoftheNHibernateextensioninterface, ICurrentSessionContext, by setting the property'ExposeTransactionAwareSessionFactory'totrueonLocalSessionFactoryObject.This is just a short-cut for setting the NHibernate propertycurrent_session_context_classwiththenameoftheimplementationclasstouse.Thefirstwayisshownbelow

<objectid="sessionFactory"type="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate12"

<propertyname="ExposeTransactionAwareSessionFactory"value

<!--otherconfigurationsettingsomitted-->

</object>

Whichissimplyashortcutforthefollowingconfiguration

<objectid="sessionFactory"type="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate12"

Page 516: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--otherconfigurationsettingsomitted-->

<propertyname="HibernateProperties">

<dictionary>

<!--otherdictionaryentriesomitted-->

<entrykey="hibernate.current_session_context_class"

value="Spring.Data.NHibernate.SpringSessionContext,Spring.Data.NHibernate12"

</dictionary>

</property>

</object>

Themainadvantageof thisDAOstyle is that itdependsontheHibernateAPIonly;noimportofanySpringclassisrequired.Thisisofcourseappealingfromanon-invasivenessperspective,andwillnodoubtfeelmorenaturaltoHibernatedevelopers.

21.2.6.1.ExceptionTranslationHowever, the DAO implemenation as shown throws plainHibernateException which means that callers can only treatexceptions as generally fatal - unless theywant to dependonHibernate's ownexception hierarchy. Catching specific causes such as an optimistic lockingfailure is not possible without tying the caller to the implementation strategy.This trade offmight be acceptable to applications that are stronglyHibernate-basedand/ordonotneedanyspecialexceptiontreatment.Asanalternativeyoucan use Spring's exception translation advice to convert the NHibernateexceptiontoSpring'sDataAccessExceptionhierarchy.Spring offers a solution allowing exception translation to be appliedtransparentlythroughthe[Repository]attribute:

[Repository]

publicclassHibernateCustomerDao:ICustomerDao{

//classbodyhere

}

Page 517: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

andregisteranexceptiontranslationpostprocessor.

<objects>

<!--configuresessionfactory(omittiedforbrevity)-->

<!--Exceptiontranslationobjectpostprocessor-->

<objecttype="Spring.Dao.Attributes.PersistenceExceptionTranslationPostProcessor,Spring.Data"/>

<!--SameDAOconfigurationasbefore-->

<objectid="CustomerDao"type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao,Spring.Northwind.Dao.NHibernate">

<propertyname="sessionFactory"ref="MySessionFactory"/>

</object>

</objects>

The postprocessor will automatically look for all exception translators(implementations of the IPersistenceExceptionTranslatorinterface)andadviseallobjectmarkedwiththe[Repository]attributesothatthediscoveredtranslatorscaninterceptandapplytheappropriatetranslationon the thrown exceptions. Spring's LocalSessionFactory objectimplements the IPersistenceExceptionTranslator interfaceand performs the same exception translation as was done when usingHibernateTemplate.

The [Repository] attribute is definedin the Spring.Data assembly,howeveritisusedasa'marker'attribute,andyoucanprovideyourownifyouwould like to avoid coupling yourDAO implementation to a Spring attribute.This is done by settingPersistenceExceptionTranslationPostProcessor's

propertyRepositoryAttributeTypetoyourownattributetype.

Note

Insummary:DAOscanbeimplementedbasedontheplainHibernate1.2/2.0API,whilestillbeingabletoparticipateinSpring-managedtransactionsandexceptiontranslation.

21.2.7.Programmatictransactiondemarcation

Page 518: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Transactions canbedemarcated in a higher level of the application, on top ofsuchlower-leveldataaccessservicesspanninganynumberofoperations.Thereare no restrictions on the implementation of the surrounding business servicehereaswell,itjustneedsaSpringPlatformTransactionManager.Again,thelattercancomefromanywhere,butpreferablyasanobjectreferencevia aTransactionManager property - just like theproductDAOshouldbesetviaasetProductDao(..)method.Thefollowingsnippetsshow a transaction manager and a business service definition in a Springapplicationcontext,andanexampleforabusinessmethodimplementation.

<objects>

<objectid="HibernateTransactionManager"

type="Spring.Data.NHibernate.HibernateTransactionManager,Spring.Data.NHibernate"

<propertyname="DbProvider"ref="DbProvider"/>

<propertyname="SessionFactory"ref="MySessionFactory"/>

</object>

<!--DAOdefinitionnotlisted,seeaboveforanexample.-->

<objectid="FulfillmentService"type="Spring.Northwind.Service.FulfillmentService,Spring.Northwind.Service"

<propertyname="CustomerDao"ref="CustomerDao"/>

<propertyname="OrderDao"ref="OrderDao"/>

<propertyname="ShippingService"ref="ShippingService"/>

<propertyname="TransactionManager"ref="HibernateTransactionManager"

</object>

</objects>

publicclassFulfillmentService:IFulfillmentService

privateTransactionTemplatetransactionTemplate;

privateIProductDaoproductDao;

privateICustomerDaocustomerDao;

Page 519: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

privateIOrderDaoorderDao;

privateIShippingServiceshippingService;

publicTransactionManagerTransactionManager

{

set{transactionTemplate=newTransactionTemplate(value

}

publicvoidProcessCustomer(stringcustomerId)

{

tt.Execute(delegate(ITransactionStatusstatus)

{

//Findallordersforcustomer

Customercustomer=CustomerDao.FindById(customerId);

foreach(Orderorderincustomer.Orders)

{

//ValidateOrder

Validate(order);

//Shipwithexternalshippingservice

ShippingService.ShipOrder(order);

//Updateshippingdate

order.ShippedDate=DateTime.Now;

//Updateshipmentdate

OrderDao.SaveOrUpdate(order);

//Otheroperations...Decreaseproductquantity...etc

}

returnnull;

});

}

}

21.2.8.DeclarativetransactiondemarcationAlternatively, one can use Spring's declarative transaction support, whichessentiallyenablesyou to replaceexplicit transactiondemarcationAPIcalls inyour C# code with an AOP transaction interceptor configured in a Spring

Page 520: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

container.Youcaneitherexternalizethetransactionsemantics(likepropagationbehavior and isolation level ) in a configuration file or use the Transactionattributeontheservicemethodtosetthetransactionsemantics.Anexampleshowingattributedriventransactionisshownbelow

<objects>

<objectid="HibernateTransactionManager"

type="Spring.Data.NHibernate.HibernateTransactionManager,Spring.Data.NHibernate"

<propertyname="DbProvider"ref="DbProvider"/>

<propertyname="SessionFactory"ref="MySessionFactory"/>

</object>

<!--DAOdefinitionnotlisted,seeaboveforanexample.-->

<objectid="FulfillmentService"type="Spring.Northwind.Service.FulfillmentService,Spring.Northwind.Service"

<propertyname="CustomerDao"ref="CustomerDao"/>

<propertyname="OrderDao"ref="OrderDao"/>

<propertyname="ShippingService"ref="ShippingService"/>

</object>

<!--Import'standardxml'configurationforattributedrivendeclarativetxmanagement-->

<importresource="DeclarativeServicesAttributeDriven.xml"/>

</objects>

Notethatwiththenewtransactionnamespace,youcanreplacetheimportingofDeclarativeServicesAttributeDriven.xml with the following single line,<tx:attribute-driven/> that more clearly expresses the intent ascomparedtothecontentsofDeclarativeServicesAttributeDriven.xml.

<objectsxmlns="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.nethttp://www.springframework.net/schema/objects/spring-objects.xsd

http://www.springframework.net/schema/txhttp://www.springframework.net/schema/tx/spring-tx-1.1.xsd"

Page 521: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="HibernateTransactionManager"

type="Spring.Data.NHibernate.HibernateTransactionManager,Spring.Data.NHibernate"

<propertyname="DbProvider"ref="DbProvider"/>

<propertyname="SessionFactory"ref="MySessionFactory"/>

</object>

<!--DAOdefinitionnotlisted,seeaboveforanexample.-->

<objectid="FulfillmentService"type="Spring.Northwind.Service.FulfillmentService,Spring.Northwind.Service"

<propertyname="CustomerDao"ref="CustomerDao"/>

<propertyname="OrderDao"ref="OrderDao"/>

<propertyname="ShippingService"ref="ShippingService"/>

</object>

<tx:attribute-driven/>

</objects>

Theplacementofthetransactionattributeintheservicelayermethodisshownbelow.

publicclassFulfillmentService:IFulfillmentService

{

//fieldsandpropertiesfordaoobjectomitted,seeabove

[Transaction(ReadOnly=false)]

publicvoidProcessCustomer(stringcustomerId)

{

//Findallordersforcustomer

Customercustomer=CustomerDao.FindById(customerId);

foreach(Orderorderincustomer.Orders)

{

//ValidateOrder

Validate(order);

Page 522: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

//Shipwithexternalshippingservice

ShippingService.ShipOrder(order);

//Updateshippingdate

order.ShippedDate=DateTime.Now;

//Updateshipmentdate

OrderDao.SaveOrUpdate(order);

//Otheroperations...Decreaseproductquantity...etc

}

}

}

Ifyouprefertonotuseattributetodemarcateyourtransactionboundaries,youcan import a configuration file with the following XML instead of using<tx:attribute-driven/>

<objectid="TxProxyConfigurationTemplate"abstract="true"

type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject,Spring.Data"

<propertyname="PlatformTransactionManager"ref="HibernateTransactionManager"

<propertyname="TransactionAttributes">

<name-values>

<!--Addcommonmethodsacrossyourserviceshere-->

<addkey="Process*"value="PROPAGATION_REQUIRED"/>

</name-values>

</property>

</object>

RefertothedocumentationonSpringTransactionmanagementforconfigurationofotherfeatures,suchasrollbackrules.

21.2.9.TransactionmanagementstrategiesBothTransactionTemplateandTransactionInterceptor(notyet seenexplicitly inaboveconfiguration,TransactionProxyFactoryObjectusesaTransactionInterceptor,youwouldhavetospecifyitexplicitlyifyouwereusinganordinaryProxyFactoryObject.)delegatetheactualtransactionhandling

Page 523: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

to a PlatformTransactionManager instance, which can be aHibernateTransactionManager (for a single HibernateSessionFactory, using a ThreadLocal Session under thehood) or aTxScopeTransactionManager (delegating to MS-DTCfor distributed transaction) for Hibernate applications. You could even use acustom PlatformTransactionManager implementation. Soswitching from native Hibernate transaction management toTxScopeTransactionManager, such as when facing distributed transactionrequirements for certain deployments of your application, is just a matter ofconfiguration. Simply replace theHibernate transactionmanagerwithSpring'sTxScopeTransactionManagerimplementation.Bothtransactiondemarcationanddata access code will work without changes, as they just use the generictransactionmanagementAPIs.Fordistributed transactions acrossmultipleHibernate session factories,simplycombine TxScopeTransactionManager as a transaction strategywith multiple LocalSessionFactoryObject definitions. Each ofyourDAOsthengetsonespecificSessionFactoryreferencepassedintoit'srespectiveobjectproperty.

TOBEDONE

HibernateTransactionManager can export the ADO.NETTransaction used by Hibernate to plain ADO.NET access code, for aspecificDbProvider. (matching connection string). This allows for high-leveltransactiondemarcationwithmixedHibernate/ADO.NETdataaccess!

21.2.10.WebSessionManagementTheopensessioninviewpatternkeepsthehibernatesessionopenduringpagerenderingsolazilyloadedhibernateobjectscanbedisplayed.YouconfigureitsusebyaddinganadditionalcustomHTTPmoduledeclarationasshownbelow

<system.web>

<httpModules>

<addname="OpenSessionInView"type="Spring.Data.NHibernate.Support.OpenSessionInViewModule,Spring.Data.NHibernate"

</httpModules>

Page 524: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

...

</system.web>

You can configure which SessionFactory the OpenSessionInViewModule willuse by setting 'global' application key-value pairs as shown below. (this willchangeinfuturereleases)

<appSettings>

<addkey="Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName"

</appSettings>

Thedefaultbehaviorofthemoduleisthatasinglesessioniscurrentlyusedforthelifeoftherequest.RefertotheearliersectiononTransactionManagementinthis chapter for more information on how sessions are managed in theOpenSessionInViewModule. You can also configure in the application settingthe EntityInterceptorObjectName using the keySpring.Data.NHibernate.Support.OpenSessionInViewModule.EntityInterceptorObjectName

and if SingleSession mode is used via the keySpring.Data.NHibernate.Support.OpenSessionInViewModule.SingleSession

If SingleSession is set to false, referred to as 'deferred closemode', theneachtransactionscopewilluseanewSessionandkeptopenuntiltheendofthewebrequest. This has the drawback that the first level cache is not reused acrosstransactions and that objects are required to be unique across all sessions.Problemscanariseifthesameobjectisassociatedwithmorethanonehibernatesession.

ImportantBydefault,OSIVappliesFlushMode.NEVERoneverysessionitcreates.ThisisbecauseifOSIVflushedpendingchangesduring"EndRequest"andanerroroccurs,allresponsehasalreadybeensenttotheclient.Therewouldbenowayoftellingtheclientabouttheerror.

BydefaultthismeansyouMUSTexplicitlydemarcatetransactionboundariesaroundnon-readonlystatementswhenusingOSIV.ForconfiguringtransactionsseeSection21.2.8,“Declarativetransactiondemarcation”ortheSpring.Data.NHibernate.Northwindexampleapplication.

21.2.11.SessionScope

Page 525: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheclassSpring.Data.NHibernate.Support.SessionScopeallowsforyoutouseasingle NHibernate session across multiple transactions. The usage is shownbelow

using(newSessionScope())

{

...domultipleoperationswithasinglesession,possibly

}

Attheendoftheusingblockthesessionisautomaticallyclosed.Alltransactionswithin the scope use the same session, if you are using Spring'sHibernateTemplate or using Spring's implementation of NHibernate 1.2'sICurrentSessionContext interface.Seeother sections in this chapter for furtherinformationonthoseusagescenarios.

Page 526: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PartIII.TheWebThispartofthereferencedocumentationcoverstheSpringFramework'ssupportforthepresentationtier,specificallyweb-basedpresentationtiers.

Chapter22,Spring.NETWebFramework

Chapter23,ASP.NETAJAX

Page 527: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter22.Spring.NETWebFramework

Page 528: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.1.IntroductionSpring.NET's web application framework aims to increase your productivitywritingASP.NETWebFormsapplications.ItoffersauniquevaluepropositiontocreatingASP.NETapplicationsnotfoundinother.NETwebframeworks.The goal of the framework is to make it easy to write 'thin and clean' webapplications.Bythin,whatismeantisthattheWebForm'sresponsibilityistoactasadapterbetweentheHTMLbasedworldofthewebandtheooworldofyourapplication.Theapplication layeryourweb formcommunicateswith iswherethebusinesslogicresides,notinthewebtier.By'clean'whatismeantthatthewebframeworkshouldhaveagoodseparationofconcerns,leadingideallytoanevent-handlerthatdoesnotcontainanyreferencetoUIelements.Thismakesitpossible to test your event handler code in integration style tests.Last but notleast, Spring's web framework reduces the incidental complexity of commontasks in the web tier, for example the conversion of HTML control data toobjects and then vice-versa after the request has been processed by theapplicationlayer.HighlightsofSpring'sWebframeworkare

Dependency Injection forallASP.NETartifacts.This includespagesandusercontrols but also modules, providers and HTTP handlers. Your pages,controls, etc., do not have any Spring dependencies in order to beconfiguredviadependencyinjection.

Bi-directionaldatabinding.Thisallowsyoutodeclarativelydefinethedatathatwillbemarshaledoutofyourhtml/usercontrolsandintoadatamodelthatinturnisgenerallysubmittedtotheapplicationlayer.Afterthedatamodelisupdatedintheapplicationlayer,thosechangesareautomaticallyreflectedin the html/user controls on post back. This removes large amounts oftedious,errorproneboilerplatecode.

Web object scopes. Object definitions can be defined at the application,sessionorrequestscope.Thismakesiteasytoinject,sayasessionscopedshopping cart, into your page without having to do any lower levelprogramming.

Data Model Management. While ASP.NET managed the view state of yourform,itdoesnotofferfacilitiestomanagethedatamodelthatyoubuilduptosubmittotheapplicationlayer.Springprovidesamechanismsimilarto

Page 529: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

viewstatetohelpmanageyourdatamodel.

UIagnosticvalidationframework.Declarativelydefinecomplexvalidationrules,for example that take into account complex relationships in your datamodel.Errorcontrolsareprovidedtoeasilyrendervalidationfailure.Thisallowsyoutocentralizeyourvalidationlogicandalsoreuseitontheserverside,forexampleusingparametervalidationadvicedescribedintheaspectlibrarychapter

Externalized page navigation through 'result mapping'. Instead of hard coding urlsand data to direct where a page should go next, result mappings areexternallydefinedandconfigured thatassociate logicalnamesandaURL(+ data). This also allows for the encryption of values that are sent viaResponse.Redirect.

Improved localization and master page support - Advanced localizationfeatures(includingimagelocalization)aswellasdeclarativeconfigurationofwhatmaterpagetoapplytodifferentpartsofyourwebapplicationareeasytoperform.

AllyouknowaboutASP.NETdevelopmentstillapplies,Spring'sapproachisto'embraceandextend'thebasicASP.NETprogrammingmodelsoyoucanbeasproductiveaspossible.

Note

SupportforASP.NETMVCisplannedforSpring.NET2.0andpreviewsofourintegrationwiththeMVCframeworkwillbemodeavailablewhenthefinalMVCframeworkships.

Whatfollowsisamoredetailedbackgroundandmotivationoffeaturesandmostimportantly the detailed reference manual for using Spring's web framework.Oneof thegreat things about the framework is that it is not an all or nothingsolution.Ifyouchoosetouseonlydependencyinjectionandbi-directionaldatabinding, that is just fine. You can incrementally adopt the web framework,addressing problems areas in your current web application with a specificfeature.Thereisnoneedtogo'wholehog'intousingallpartsoftheframeworkeverywhereinyourapplication.The Spring.NET distribution ships with a number of Web QuickStarts and acompletereferenceapplication,SpringAir.WebQuickStartsarethebestwaytolearneachSpring.Webfeaturebyfollowingsimpleexamples,andtheSpringAir

Page 530: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

referenceapplicationhasaSpring.Web-enabledfrontendwhichusesmanybestpractices for Spring.NETweb applications, so please do refer to it as you arereadingthis(reference)material(seeChapter37,SpringAir-ReferenceApplication).

Page 531: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.2.BackgroundOne of the objections many developers have to the ASP.NET programmingmodel is that it isnota"trueMVC"(Model-View-Controller) implementation,becausecontroller-typelogicwithinthepageistootightlycoupledtotheview.Agoodexampleofthisareeventhandlerswithinthepageclass,whichtypicallyhave references to view elements, such as input controls, all over the place.Withoutgettingintoacademicdiscussionofwhat"trueMVC"is,andwhetheritis even appropriate to try to fit form-based technology such asASP.NET intotraditionallyrequest-basedMVCpatternwhenMVP(Model-View-Presenter)orPresentationModelmightbemoreappropriate,we'dliketoagreewiththecriticsonthemost importantpoint theyaremaking:controller-type logic,suchas thecodewithin page event handlers inASP.NET, should not depend on the viewelements.Havingsaidthat, therearegood thingsaboutASP.NET.Server-sideformsandcontrols make developers significantly more productive and allow us tosignificantlysimplifypagemarkup.Theyalsomakecross-browserissueseasiertodealwith,aseachcontrolcanmakesurethatitrenderscorrectmarkupbasedontheuser'sbrowser.Theabilitytohookcustomlogicintothelifecycleofthepage,aswellastocustomizeHTTPprocessingpipelinearealsoverypowerfulfeatures. Finally, being able to interact with the strongly typed server-sidecontrolsinsteadofmanipulatingstring-basedHTTPrequestcollections,suchasForm and QueryString, is a much needed layer of abstraction in webdevelopment.For thesereasons,wedecidedthat insteadofdevelopinganew,"pureand trueMVC"webframeworkaspartofSpring.NET,weshouldtakeamorepragmaticapproach and extend ASP.NET in such a way that most, if not all of itsshortcomingsareeliminated. It shouldbenoted thatwith the introductionofa'true MVC framework' being added to .NET, with extension points for IoCcontainers such as Spring, Springwill continue to play a role within aMVCbased model once that functionality is available from Microsoft. It is worthnoting thatSpringJavahasaverypopularMVCframeworkandmuchof thatexperience and added value can be transliterated to help developers be moreproductivewhenusingtheupcomingASP.NETMVCsupport.Spring.Webalsoaddssupportforapplyingthedependencyinjectionprincipletoone'sASP.NETPagesandControlsaswellashttpmodulesandcustom

Page 532: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

provider modules. This means that application developers can easily injectservice dependencies into web controllers by leveraging the power of theSpring.NET IoC container. See Dependency Injection for ASP.NET Pages for moreinformation.Aswesaidearlier,eventhandlersincode-behindclassesreallyshouldnothaveto dealwithASP.NETUI controls directly. Such event handlers should ratherworkwiththepresentationmodelofthepage,representedeitherasahierarchyof domain objects or anADO.NETDataSet. It is for that reason that theSpring.NETteamimplementedbidirectionaldatabinding framework tohandlethemappingofvaluestoandfromthecontrolsonapagetotheunderlyingdatamodel.The data binding framework also transparently takes care of data typeconversion and formatting, enabling application developers toworkwith fullytyped data (domain) objects in the event handlers of code-behind files. SeeBidirectionalDataBindingandModelManagementformoreinformation.The flow of control through an application is another area of concern that isaddressedbySpring.NETWebFramework.TypicalASP.NETapplicationswilluse Response.Redirect or Server.Transfer calls withinPagelogictonavigatetoanappropriatepageafteranactionisexecuted.Thistypicallyleadstohard-codedtargetURLsinthePage,whichisneveragoodthing.ResultmappingsolvesthisproblembyallowingapplicationdeveloperstospecifyaliasesforactionresultsthatmaptotargetURLsbasedoninformationinanexternalconfigurationfilethatcaneasilybeedited.UnderconsiderationforfuturereleasesofSpring.NETisaprocessmanagementframework,whichwilltakethisapproachtoanotherlevel,allowingyoutocontrolcomplexpageflowsinaverysimpleway.SeeResultMappingformoreinformation.Standard localization support is also limited in versions of ASP.NET prior toASP.NET2.0.EventhoughVisualStudio2003generatesalocalresourcefileforeachASP.NETPage andusercontrol, those resources are never usedby theASP.NET infrastructure. This means that application developers have to dealdirectly with resource managers whenever they need access to localizedresources,whichintheopinionoftheSpring.NETteamshouldnotbethecase.Spring.NET's Web Framework (hereafter referred to as Spring.Web) addscomprehensivesupportforlocalizationusingbothlocalresourcefilesandglobalresources that are configured within and for a Spring.NET container. SeeLocalizationandMessageSourcesformoreinformation.

Page 533: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Inadditiontotheaforementionedfeaturesthatcanbeconsideredtobethe'core'featuresoftheSpring.Webframework,Spring.Webalsoshipswithanumberofother lesser features that might be useful to a large number of applicationdevelopers. Some of these additional features include back-ports of ASP.NET2.0features thatcanbeusedwithASP.NET1.1, suchasMasterPagesupport.SeeMasterPagesinASP.NET1.1formoreinformation.In order to implement some of the abovementioned features the Spring.NETteam had to extend (as in the object-oriented sense) the standard ASP.NETPage and UserControl classes. This means that in order to takeadvantage of the full feature stack of Spring.Web (most notably bidirectionaldata binding, localization and result mapping), your code-behind classes willhave to extend Spring.Web specific base classes such asSpring.Web.UI.Page; however, some very powerful features such asdependency injection for ASP.NET Pages, Controls, and providers can beleveragedwithouthavingtoextendSpring.Web-specificbaseclasses.ItisworthstatingthatbytakingadvantageofsomeofthemoreusefulfeaturesofferedbySpring.Webyouwillbecoupling thepresentation tierofyourapplication(s) toSpring.Web.Thechoiceofwhetherornotthisisappropriateis,ofcourse,lefttoyou.

Page 534: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.3.Automaticcontextloadingandhierarchicalcontexts

22.3.1.ConfigurationUnsurprisingly,Spring.WebbuildsontopoftheSpring.NETIoCcontainer,andmakes heavy use (internally) of the easy pluggability and standardizedconfiguration afforded by the IoC container. This also means that all of thecontrollers (ASP.NET Pages) that make up a typical Spring.Web enabledapplication will be configured using the same standard Spring.NET XMLconfigurationsyntax.Spring.WebusesacustomPageHandlerFactoryimplementation to loadandconfigureaSpring.NETIoCcontainer,which is inturn used to locate an appropriate Page to handle a HTTP request. TheWebSupportModule configures miscellaneous Spring infrastructureclassesforuseinawebenvironment,forexamplesettingthestoragestrategyofLogicalThreadContexttobeHybridContextStorage.The instantiation and configuration of the Spring.NET IoC container by theSpring.Web infrastructure iswholly transparent to applicationdevelopers,whowilltypicallyneverhavetoexplicitlyinstantiateandconfigureanIoCcontainermanually(byforexampleusingthenewoperatorinC#).Inordertoeffectthetransparent bootstrapping of the IoC container, the Spring.Web infrastructurerequirestheinsertionofthefollowingconfigurationsnippetintoeachandeverySpring.Web-enabledwebapplication'srootWeb.configfile(theverbandpath properties can of course be changed from the values that are shownbelow):

<system.web>

<httpHandlers>

<addverb="*"path="*.aspx"type="Spring.Web.Support.PageHandlerFactory,Spring.Web"

</httpHandlers>

<httpModules>

<addname="Spring"type="Spring.Context.Support.WebSupportModule,Spring.Web"

</httpModules>

...

</system.web>

PleasenotethatthissnippetofstandardASP.NETconfigurationisonlyrequired

Page 535: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

tobepresentintherootdirectoryofeachSpring.Webwebapplication(i.e.intheweb.config file present in the top level virtual directory of anASP.NETwebapplication).TheaboveXMLconfigurationsnippetwilldirecttheASP.NETinfrastructuretouse Spring.NET's page factory, which will in turn create instances of theappropriate.aspxPage,(possibly)injectdependenciesintosaidPage(asrequired),andthenforwardthehandlingoftherequesttosaidPage.AftertheSpring.Webpagefactoryisconfigured,youwillalsoneedtodefinearoot application context by adding a Spring.NET configuration section to thatsameweb.configfile.Thefinalconfigurationfileshouldlookalittlelikethis(yourexactconfigurationwillnodoubtvaryinparticulars)...

<?xmlversion="1.0"encoding="utf-8"?>

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.WebContextHandler,Spring.Web"

</sectionGroup>

</configSections>

<spring>

<context>

<resourceuri="~/Config/CommonObjects.xml"/>

<resourceuri="~/Config/CommonPages.xml"/>

<!--TESTCONFIGURATION-->

<!--

<resourceuri="~/Config/Test/Services.xml"/>

<resourceuri="~/Config/Test/Dao.xml"/>

-->

<!--PRODUCTIONCONFIGURATION-->

<resourceuri="~/Config/Production/Services.xml"

<resourceuri="~/Config/Production/Dao.xml"/>

</context>

</spring>

Page 536: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<system.web>

<httpHandlers>

<addverb="*"path="*.aspx"type="Spring.Web.Support.PageHandlerFactory,Spring.Web"

</httpHandlers>

<httpModules>

<addname="Spring"type="Spring.Context.Support.WebSupportModule,Spring.Web"

</httpModules>

</system.web>

</configuration>

Thereareafewimportantpointsthatneedtobenotedwithregardtotheaboveconfiguration:

1. You must define a custom configuration section handler for thespring/context element. If you use Spring.NET for manyapplicationsonthesamewebserver,itmightbeeasiertomovethewholedefinitionoftheSpring.NETsectiongrouptoyourmachine.configfile.

2. The custom configuration section handler is of the typeSpring.Context.Support.WebContextHandler whichwill in turn instantiate an IoC container of the typeSpring.Context.Support.WebApplicationContext.ThiswillensurethatallofthefeaturesprovidedbySpring.Webarehandledproperly(suchasrequestandsession-scopedobjectdefinitions).

3. Withinthe<spring>elementyouneedtodefinearootcontext,andresourcelocationsthatcontaintheobjectdefinitionsthatwillbeusedwithinthewebapplication (such as service or business tier objects) then need to bespecifiedaschildelementswithinthe<context>element.Objectdefinitionresourcescanbefully-qualifiedpathsorURLs,ornon-qualified,as intheexample above. Non-qualified resources will be loaded using the defaultresource type for the context, which for theWebApplicationContextistheWebResourcetype.

4. Please note that the object definition resources do not all have to be thesame resource type (e.g. all file://, all http://, allassembly://, etc). This means that you can load some objectdefinitionsfromresourcesembeddeddirectlywithinapplicationassemblies

Page 537: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

(assembly://),whilecontinuingtoloadotherobjectdefinitionsfromwebresourcesthatcanbemoreeasilyedited.

22.3.1.1.ConfigurationforIIS7TheconfigurationforIIS7isshownbelow

<system.webServer>

<validationvalidateIntegratedModeConfiguration="false"/>

<modules>

<addname="Spring"type="Spring.Context.Support.WebSupportModule,Spring.Web"

</modules>

<handlers>

<addname="SpringPageHandler"verb="*"path="*.aspx"type

<addname="SpringContextMonitor"verb="*"path="ContextMonitor.ashx"

</handlers>

</system.webServer>

22.3.2.ContextHierarchyASP.NET provides a hierarchical configuration mechanism by allowingapplication developers to override configuration settings specified at a higherlevel in the web application directory hierarchy with configuration settingsspecifiedatthelowerlevel.For example, a web application's rootWeb.config file overrides settingsfromthe(lowerlevel)machine.configfile.Inthesamefashion,settingsspecified within the web.config file within a subdirectory of a webapplication will override settings from the root Web.config and so on.LowerlevelWeb.configfilescanalsoaddsettingsoftheirownthatwerenotpreviouslydefinedanywhere.Spring.Web leverages this ASP.NET feature to provide support for a contexthierarchy.YourlowerlevelWeb.configfilescanbeusedtoaddnewobjectdefinitionsortooverrideexistingonespervirtualdirectory.What thismeans toapplicationdevelopers is thatonecaneasilycomponentizean application by creating a virtual directory per component and creating acustom context for each component that contains the necessary configurationinfo for thatparticularcontext.Theconfiguration fora lower levelcomponent

Page 538: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

will generally contain only those definitions for the pages that the componentconsists of and (possibly) overrides for some of the definitions from the rootcontext(forexample,menus).Becauseeachsuchlowerlevelcomponentwillusuallycontainonlyafewobjectdefinitions, application developers are encouraged to embed those objectdefinitionsdirectlyintotheWeb.configforthelowerlevelcontextinsteadof relying on an external resource containing object definitions. This is easilyaccomplishedbycreatingacomponentWeb.configsimilartothefollowingone:

<?xmlversion="1.0"encoding="utf-8"?>

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<contexttype="Spring.Context.Support.WebApplicationContext,Spring.Web"

<resourceuri="config://spring/objects"/>

</context>

<objectsxmlns="http://www.springframework.net">

<objecttype="MyPage.aspx"parent="basePage">

<propertyname="MyRootService"ref="myServiceDefinedInRootContext"

<propertyname="MyLocalService"ref="myServiceDefinedLocally"

<propertyname="Results">

<!--...-->

</property>

</object>

<objectid="myServiceDefinedLocally"type="MyCompany.MyProject.Services.MyServiceImpl,MyAssembly"

</objects>

</spring>

</configuration>

The<context/>elementseenabove(containedwithinthe<spring/>element) simply tells the Spring.NET infrastructure code to load (its) objectdefinitionsfromthespring/objectssectionoftheconfigurationfile.

Page 539: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

You can (and should) avoid the need to specify<configSections/>elementbymoving theconfigurationhandlerdefinitionfor the<objects>elementtoahigherlevel(root)Web.configfile,oreventothelevelofthemachine.configfileifSpring.NETistobeusedformultipleapplicationsonthesameserver.Avery importantpoint tobeawareof is that thiscomponent-levelcontextcanreferencedefinitionsfromitsparentcontext(s).Basically,ifareferencedobjectdefinition is not found in the current context, Spring.NET will search all theancestorcontextsinthecontexthierarchyuntilitfindssaidobjectdefinition(orultimatelyfailsandthrowsanexception).

Page 540: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.4.DependencyInjectionforASP.NETPagesSpring.Web builds on top of the feature set and capabilities ofASP.NET; oneexampleofthiscanbeseenthewaythatSpring.Webhasusedthecode-behindclass of thePage mechanism to satisfy theController portion of theMVC architectural pattern. In MVC-based (web) applications, theControlleristypicallyathinwrapperaroundoneormoreserviceobjects.In the specific case of Spring.Web, the Spring.NET team realized that it wasvery important that service object dependencies be easily injected intoPageControllers. Accordingly, Spring.Web provides first class support fordependency injection inASP.NETPages.This allows applicationdevelopersto inject any required service object dependencies (and indeed any otherdependencies) into their Pages using standard Spring.NET configurationinsteadofhavingtorelyoncustomservicelocatorsormanualobjectlookupsinaSpring.NETapplicationcontext.Once an application developer has configured the Spring.NET web applicationcontext, said developer can easily create object definitions for the pages thatcomposethatwebapplication:

<objectsxmlns="http://www.springframework.net">

<objectname="basePage"abstract="true">

<propertyname="MasterPageFile"value="~/Web/StandardTemplate.master"

</object>

<objecttype="Login.aspx">

<propertyname="Authenticator"ref="authenticationService"

</object>

<objecttype="Default.aspx"parent="basePage"/>

</objects>

Thisexamplecontainsthreedefinitions:

1. The first definition is an abstract definition for the base page thatmanyotherpagesintheapplicationwill inheritfrom.Inthiscase,thedefinitionsimplyspecifieswhichpage is tobe referencedas themasterpage,but it

Page 541: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

will typically also configure localization-related dependencies and rootfoldersforimages,scriptsandCSSstylesheets.

2. The second definition defines a login page that neither inherits from thebase page nor references the master page.What it does show is how toinject a service object dependency into a page instance (theauthenticationServiceisdefinedelsewhere).

3. Thefinaldefinitiondefinesadefaultapplicationpage.Inthiscaseitsimplyinheritsfromthebasepageinordertoinheritthemasterpagedependency,but apart from that it doesn't need any additional dependency injectionconfiguration.

Onethingthatslightlydifferentiates theconfigurationofASP.NETpagesfromthe configuration of other .NET classes is in the value passed to thetypeattribute.Ascanbeseenintheaboveconfigurationsnippetthetypenameisactually the path to the.aspx file for thePage, relative to the directorycontextitisdefinedin.Inthecaseoftheaboveexample,thosedefinitionsareinthe root context soLogin.aspx andDefault.aspx alsomust be inthe root of theweb application's virtual directory. Themaster page is definedusing an absolute path because it could conceivably be referenced from childcontextsthataredefinedwithinsubdirectoriesofthewebapplication.The astute reader may have noticed that the definitions for theLogin andDefaultpagesdon'tspecifyeitheroftheidandnameattributes.Thisisinmarked contrast to typical object definitions in Spring.NET,where theid ornameattributesaretypicallymandatory(althoughnotalways,asinthecaseofinner object definitions). This is actually intentional, because in the case ofSpring.WebPageController instances one typically wants to use thenameof the.aspx filenameas the identifier. If anid isnot specified, theSpring.Web infrastructurewill simplyuse thenameof the.aspx file as theobject identifier (minus any leading path information, and minus the fileextensiontoo).Nothing prevents an application developer from specifying anid ornamevalueexplicitly;oneusecasewhentheexplicitnamingmightbeusefuliswhenone wants to expose the same page multiple times using a slightly differentconfiguration(Add/Editpagesforexample).Ifyouwouldliketouseabstractobjectdefinitions and have your page inherit from them, the use of the name

Page 542: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

attribute should be used instead of the id attribute on the abstract objectdefinition.

22.4.1.InjectingDependenciesintoControlsSpring.Web also allows application developers to inject dependencies intocontrols (both user controls and standard controls) that are containedwithin apage.Thiscanbeaccomplishedglobally forallcontrolsofaparticularTypebyusingthelocationofthe.ascxastheobjecttypeidentifier.Thisissimilartoinjectinginto.aspxpagesshownabove.

<objecttype="~/controls/MyControl.ascx"abstract="true">

<!--injectdependencieshere...-->

</object>

Ineithercase,besuretomarktheobjectdefinitionasabstract(byaddingabstract="true"totheattributelistofthe<object/>element).

22.4.2.InjectingdependenciesintocustomHTTPmodulesYou can perform dependency injection on customHTTPmodules through theuse of the classSpring.Context.Support.HttpApplicationConfigurer

YouregisteryourcustomHTTPmoduleasyouwouldnormally,forexampleamodule of the typeHtmlCommentAppenderModule, taken from theWeb Quickstart, appends additional comments into the http response. It isregisteredasshownbelow

<httpModules>

<addname="HtmlCommentAppender"type="HtmlCommentAppenderModule"

</httpModules>

Toconfigure thismodule,namingconventionsareused to identify themodulename with configuration instructions in the Spring configuration file. TheModuleTemplates property of HttpApplicationConfigurer is a dictionary thattakesasakeythenameoftheHTTPmodule,HtmlCommentAppender,andasavaluetheconfiguration instructionsasyouwouldnormallyuseforconfiguringanobjectwithSpring.Anexampleisshownbelow.HttpApplicationConfigurer'

Page 543: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ModuleTemplatesproperty.

<objectname="HttpApplicationConfigurer"type="Spring.Context.Support.HttpApplicationConfigurer,Spring.Web"

<propertyname="ModuleTemplates">

<dictionary>

<entrykey="HtmlCommentAppender"><!--thisnamemustmatchthemodulename-->

<object>

<!--select"viewsource"inyourbrowseronanypagetoseetheappendedhtmlcomment-->

<propertyname="AppendText"value="Myconfiguredcomment!"

</object>

</entry>

</dictionary>

</property>

</object>

YoucanseethisexampleinactionintheWebQuickstart.

22.4.3. Injecting dependencies into HTTP handlers andhandlerfactoriesYou can perform dependency injection on IHttpHandlers andIHttpHandlerFactory. This effectively allows for a fully Spring-managed <httpHandlers> configuration section. To configure anIHttpHandler or IHttpHandlerFactory you should registerSpring'sMappingHandlerFactory with a specific path or wildcardstring(i.e.*.aspx)usingthestandardconfigurationofan<httpHandler>inweb.config.Thisisshownbelow

<system.web>

<httpHandlers>

<!--

thelinesbelowmap*any*requestendingwith*.ashxor*.whatever

totheglobal(!)MappingHandlerFactory.Further"specialication"

ofwhichhandlertomaptoisdonewithinMappingHandlerFactory'sconfiguration-

useMappingHandlerFactoryConfigurerforthis(seebelow)

-->

<addverb="*"path="*.ashx"type="Spring.Web.Support.MappingHandlerFactory,Spring.Web"validate="true"/>

<addverb="*"path="*.whatever"type="Spring.Web.Support.MappingHandlerFactory,Spring.Web"validate="false"/>

</httpHandlers>

</system.web>

Page 544: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The specializationofwhich specific handler ismapped to the path is donebyconfiguration of Spring's

MappingHandlerFactoryConfigurer class. TheMappingHandlerFactoryConfigurer is configured by specifying a dictionary ofkeyvalueparis,thekeyvalueisaregularexpressionthatwillmatchtherequestURL and the value is an instance of an IHttpHandler or IHttpHandlerFactoryconfiguredviadependencyinjection.theconfigurationofMappingHandlerFactoryConfigurerisshownbelow

<objectsxmlns="http://www.springframework.net">

<!--configurestheglobalGenericHandlerFactoryinstance-->

<objectname="mappingHandlerFactoryConfigurer"type="Spring.Web.Support.MappingHandlerFactoryConfigurer,Spring.Web"

<propertyname="HandlerMap">

<dictionary>

<!--mapanyrequestendingwith*.whatevertoNoOpHandler-->

<entrykey="\.whatever$"value="myCustomHandler"

<entrykey="\.ashx$"value="standardHandlerFactory"

</dictionary>

</property>

</object>

<objectname="standardHandlerFactory"type="Spring.Web.Support.DefaultHandlerFactory,Spring.Web"

<!--definesastandardsingletonthatwillhandle*.whateverrequests-->

<objectname="myCustomHandler"type="MyCustomHttpHandler,App_Code"

<propertyname="MessageText"value="ThistextisinjectedviaSpring"

</object>

<!--

usedforconfiguring~/DemoHandler.ashxcustomhandler

note,thatthisisanabstractdefinitionbecause'type'isnotspecified

-->

<objectname="DemoHandler.ashx">

<propertyname="OutputText">

<value>ThistextisinjectedviaSpring</value>

</property>

</object>

</objects>

Page 545: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Spring's DefaultHandlerFactory will use the .NET classSystem.Web.UI.SimpleHandlerFactory to create handler instaces and willconfigure each instances used an object definition whose name matches therequest url's filename. The abstract object definition ofDemoHandler.ashx is an example of this approach. You may alsoconfigure standard classes that implment the IHttpHandler interface asdemonstrated in the example above for the classMyCustomHttpHandler.PleaserefertotheWebQuickstartapplicationtooseethisinaction.

22.4.4.InjectingdependenciesintocustomprovidersCustomproviderscanbeconfiguredwithSpring.Theapproachtoconfigurationis a family of adapters that correspond 1-to-1 with the standard ASP.NETproviders that are registered using the standard ASP.NET mechanism. TheadaptersinheritfromtheircorrespondinglynamedproviderclassintheBCL.

MembershipProviderAdapter

ProfileProviderAdapter

RoleProviderAdapter

SiteMapProviderAdapterHereisanexampleofhowtoregistertheadapterformembershipproviders.

<membershipdefaultProvider="mySqlMembershipProvider"

<providers>

<clear/>

<addconnectionStringName=""name="mySqlMembershipProvider"

</providers>

</membership>

The name of the provider must match the name of the object in the springconfiguration that will serve as the actual provider implementation. ForconveniencethereareconfigurableversionsoftheprovidersfoundinASP.NETso thatyoucanuse the full functionalityof spring toconfigure these standardproviderimplementations,forexampleusingpropertyplaceholders,etc.Theseare

ConfigurableActiveDirectoryMembershipProvider

Page 546: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ConfigurableSqlMembershipProvider

ConfigurableSqlProfileProvider

ConfigurableSqlRoleProvider

ConfigurableXmlSiteMapProviderHereisanexampleconfigurationtakenfromtheWebQuickstartthatsimplysetsthedescriptionpropertyandconnectionstring.

<objectid="mySqlMembershipProvider"type="Spring.Web.Providers.ConfigurableSqlMembershipProvider"

<propertyname="connectionStringName"value="MyLocalSQLServer"

<propertyname="parameters">

<name-values>

<addkey="description"value="membershipproviderdescription"

</name-values>

</property>

</object>

Your own custom providers of course will contain additional configurationspecifictoyourimplementation.

22.4.5.CustomizingcontroldependencyinjectionThere might be situations where it is necessary to customize Spring.Web'sdependency injection processing. In particular when using GridViews, whichcreate a large number of child controls, dependency injection can slow downyour page. To overcome this problem, you may tell Spring to handle thedependency injection process yourself by implementing the interfaceISupportsWebDependencyInjectionasshownbelow:

[C#]

classMyControl:Control,ISupportsWebDependencyInjection

{

privateIApplicationContext_defaultApplicationContext;

publicIApplicationContextDefaultApplicationContext

{

get{return_defaultApplicationContext;}

set{_defaultApplicationContext=value;}

}

Page 547: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

overrideprotectedAddedControl(Controlcontrol,intindex)

{

//handleDIforchildrenourselves-

//defaultstoacalltoInjectDependenciesRecursive

WebUtils.InjectDependenciesRecursive(_defaultApplicationContext,control);

base.AddedControl(control,index);

}

}

There is aSpring server control, Panel, that provides an easierway to turnofdependencyinjectionforpartsofyourpage.Exampleuseisshownbelow

<spring:Panelrunat="server"

suppressDependencyInjection="true"

renderContainerTag="false">

..putyourheavycontrolshere-theywon'tbetouchedbyDI

</spring:Panel>

Bywrappingtheperformancesensitivepartsofyourpagewithinthispanel,youcan easily turn off DI using the attribute suppressDependencyInjection. Bydefault<spring:Panel/>won'trenderacontainertag(<div>,<span>,etc.).Youcan modify this behavior by setting the attribute "renderContainerTag"accordingly.

Page 548: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.5.WebobjectscopesSpring.NET web applications support an additional attribute within objectdefinitionelementsthatallowsyoutocontrolthescopeofanobject:

<objectid="myObject"type="MyType,MyAssembly"scope="application|session|request"

As you can see, there are three possible values for the scope attribute --application,sessionorrequest.Applicationscopeisthedefault,andwillbeusedforallobjects thatdon'thavescopeattributedefined.As itsnamesays, itwillresult in a single instance of an object being created for the duration of theapplication, so itworks exactly like the standard singleton objects in non-webapplications.Sessionscopeallowsyou todefineobjects in suchaway that aninstanceiscreatedforeachHttpSession.Thisistheidealscopeforobjectsthatyouwantboundtoasingleusersuchasuserprofile,shoppingcart,etc.RequestscopewillresultinacreationofaninstanceperHTTPrequest.Unlike with prototype objects, calls toIApplicationContext.GetObject will return the same instanceoftherequest-scopedobjectduringasingleHTTPrequest.Thisallowsyou,forexample, to inject thesamerequest-scopedobject intomultiplepagesand thenuseserver-sidetransfertomovefromonepagetoanother.Asallthepagesareexecutedwithin thesingleHTTPrequest in thiscase, theywillshare thesameinstanceoftheinjectedobject.Onethingtokeepinmindisthatobjectscanonlyreferenceotherobjectsthatarein the same or broader scope. Thismeans that application-scoped objects canonly reference other application-scoped, session-scoped objects can referencebothsessionandapplication-scopedobjects,andfinally,request-scopedobjectscan reference other request, session or application-scoped objects. Also,prototype objects (and that includes all ASP.NET web pages defined withinSpring.NETcontext)canreferencesingletonobjectsfromanyscope,aswellasotherprototypeobjects.

Page 549: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.6.MasterPagesinASP.NET1.1Support for ASP.NET 1.1 master pages in Spring.Web is very similar to thesupportformasterpagesinASP.NET2.0.The idea is thatawebdevelopercandefinea layout template for thesiteasamaster page and specify content place holders that other pages can thenreference and populate. A sample master page (MasterLayout.ascx)couldlooklikethis:

<%@Controllanguage="c#"Codebehind="MasterLayout.ascx.cs"

<%@RegisterTagPrefix="spring"Namespace="Spring.Web.UI.Controls"

<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.0Transitional//EN"

<html>

<head>

<title>MasterPage</title>

<linkrel="stylesheet"type="text/css"href="<%=Context.Request.ApplicationPath%>/css/styles.css"

<spring:ContentPlaceHolderid="head"runat="server"/>

</head>

<body>

<formrunat="server">

<tablecellPadding="3"width="100%"border="1">

<tr>

<tdcolspan="2">

<spring:ContentPlaceHolderid="title"

<!--defaulttitlecontent-->

</spring:ContentPlaceHolder>

</td>

</tr>

<tr>

<td>

<spring:ContentPlaceHolderid="leftSidebar"

<!--defaultleftsidecontent-->

</spring:ContentPlaceHolder>

</td>

<td>

<spring:ContentPlaceHolderid="main"

<!--defaultmainareacontent-->

</spring:ContentPlaceHolder>

</td>

</tr>

</table>

Page 550: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</form>

</body>

</html>

Asyoucanseefromtheabovecode,themasterpagedefinestheoveralllayoutfor the page, in addition to four content placeholders that other pages canoverride. The master page can also include default content within theplaceholder that will be displayed if a derived page does not override theplaceholder.Apage(Child.aspx)thatusesthismasterpagemightlooklikethis:

<%@RegisterTagPrefix="spring"Namespace="Spring.Web.UI.Controls"

<%@Pagelanguage="c#"Codebehind="Child.aspx.cs"AutoEventWireup

<html>

<body>

<spring:Contentid="leftSidebarContent"contentPlaceholderId

<!--leftsidebarcontent-->

</spring:Content>

<spring:Contentid="mainContent"contentPlaceholderId

<!--mainareacontent-->

</spring:Content>

</body>

</html>

The <spring:Content/> control in the above example uses thecontentPlaceholderId attribute (property) to specify exactlywhichplaceholder from themaster page is to be overridden. Because this particularpagedoesnotdefinecontentelementsfortheheadandtitleplaceholders,theywillbedisplayedusingthedefaultcontentsuppliedinthemasterpage.Both theContentPlaceHolder andContent controls can containanyvalidASP.NETmarkup:HTML,standardASP.NETcontrols,usercontrols,etc.

VS.NET2003issue

Technically,the<html>and<body>tagsfromthepreviousexamplearenotstrictlynecessarybecausetheyarealreadydefinedin

Page 551: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

themasterpage.However,ifthesetagsareomitted,thenVisualStudio2003willcomplainaboutaschemaandintellisensewon'twork,soit'smucheasiertoworkintheHTMLviewifthosetagsareincluded.Theywillbeignoredwhenthepageisrendered.

22.6.1.LinkingchildpagestotheirmasterThe Spring.Web.UI.Page class exposes a property calledMasterPageFile,whichcanbeusedtospecifythemasterpage.TherecommendedwaytodothisisbyleveragingtheSpring.NETIoCcontainerandcreatingdefinitionssimilartothefollowing:

<?xmlversion="1.0"encoding="utf-8"?>

<objectsxmlns="http://www.springframework.net">

<objectname="basePage"abstract="true">

<propertyname="MasterPageFile"value="~/MasterLayout.ascx"

</object>

<objecttype="Child.aspx"parent="basePage">

<!--injectotherobjectsthatpageneeds-->

</object>

</objects>

This approach allows application developers to change themaster page beingusedforanumberofpageswithinawebapplication.Ofcourse,themasterpagecan still be overridden on a per context or per page basis by creating a newabstract page definition within a child context, or by specifying theMasterPageFilepropertydirectly.

Page 552: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.7.BidirectionalDataBindingandModelManagementAproblemwiththeexistingdatabindingsupport inASP.NETis that itisone-way only. It allows application developers to bind page controls to the datamodelanddisplayinformationfromsaiddatamodel,butitdoesn'tallowfortheextractionofvaluesfromthecontrolswhentheformissubmitted.Spring.Webadds such bidirectional data binding to ASP.NET by allowing developers tospecify data binding rules for their page, and by automatically evaluatingconfigureddatabindingrulesattheappropriatetimeinthepage'slifecycle.ASP.NET also doesn't provide any support for model management within thepostbacks. Sure, it has a ViewState management, but that takes care of thecontrol state only andnot of the state of anypresentationmodel objects thesecontrols might be bound to. In order to manage model within ASP.NET,developerswill typicallyuseHTTPSessionobject to store themodel betweenthepostbacks.Thisresults inadecentamountofboilerplatecode thatcanandshould be eliminated, which is exactly what Spring.Web does by providing asimplesetofmodelmanagementmethods.Pleasenotethatinordertotakeadvantageofthebidirectionaldatabindingandmodelmanagement support provided by Spring.Web, youwill have to coupleyourpresentation layer toSpring.Web; this isbecause featuresrequires you toextend a Spring.Web.UI.Page instead of the usualSystem.Web.UI.Pageclass.Spring.Webdatabindingisveryeasytouse.Applicationdeveloperssimplyneedto override the protected InitializeDataBindings method andconfiguredatabindingrulesforthepage.Theyalsoneedtooverridethreemodelmanagement methods: InitializeModel, LoadModel andSaveModel. This is perhaps best illustrated by an example from theSpringAirreferenceapplication.First,let'stakealookatthepagemarkup:

<%@PageLanguage="c#"Inherits="TripForm"CodeFile="TripForm.aspx.cs"

<asp:ContentID="body"ContentPlaceHolderID="body"runat="server"

<divstyle="text-align:center">

<h4><asp:LabelID="caption"runat="server"></asp:Label>

<table>

<trclass="formLabel">

<td>&nbsp;</td>

Page 553: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<tdcolspan="3">

<spring:RadioButtonGroupID="tripMode"runat

<asp:RadioButtonID="OneWay"runat="server"

<asp:RadioButtonID="RoundTrip"runat

</spring:RadioButtonGroup>

</td>

</tr>

<tr>

<tdclass="formLabel"align="right">

<asp:LabelID="leavingFrom"runat="server"

<tdnowrap="nowrap">

<asp:DropDownListID="leavingFromAirportCode"

</td>

<tdclass="formLabel"align="right">

<asp:LabelID="goingTo"runat="server"/>

<tdnowrap="nowrap">

<asp:DropDownListID="goingToAirportCode"

</td>

</tr>

<tr>

<tdclass="formLabel"align="right">

<asp:LabelID="leavingOn"runat="server"

<tdnowrap="nowrap">

<spring:CalendarID="departureDate"runat

</td>

<tdclass="formLabel"align="right">

<asp:LabelID="returningOn"runat="server"

<tdnowrap="nowrap">

<divid="returningOnCalendar">

<spring:CalendarID="returnDate"runat

</div>

</td>

</tr>

<tr>

<tdclass="buttonBar"colspan="4">

<br/>

<asp:ButtonID="findFlights"runat="server"

</tr>

</table>

</div>

</asp:Content>

Page 554: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Ignoreforthemomentthefactthatnoneofthelabelcontrolshavetextdefined,whichwillbedescribedlaterwhenwediscusslocalizationinSpring.NET.Whatisimportantforthepurposesofourcurrentdiscussion,isthatwehaveanumberof input controls defined: tripMode radio group,leavingFromAirportCode and goingToAirportCode

dropdowns,aswellastwoSpring.NETCalendarcontrols,departureDateandreturnDate.Next,let'stakealookatthemodelwewillbebindingthisformto:

namespaceSpringAir.Domain

{

[Serializable]

publicclassTrip

{

//fields

privateTripModemode;

privateTripPointstartingFrom;

privateTripPointreturningFrom;

//constructors

publicTrip()

{

this.mode=TripMode.RoundTrip;

this.startingFrom=newTripPoint();

this.returningFrom=newTripPoint();

}

publicTrip(TripModemode,TripPointstartingFrom,TripPointreturningFrom)

{

this.mode=mode;

this.startingFrom=startingFrom;

this.returningFrom=returningFrom;

}

//properties

publicTripModeMode

{

get{returnthis.mode;}

Page 555: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

set{this.mode=value;}

}

publicTripPointStartingFrom

{

get{returnthis.startingFrom;}

set{this.startingFrom=value;}

}

publicTripPointReturningFrom

{

get{returnthis.returningFrom;}

set{this.returningFrom=value;}

}

}

[Serializable]

publicclassTripPoint

{

//fields

privatestringairportCode;

privateDateTimedate;

//constructors

publicTripPoint()

{}

publicTripPoint(stringairportCode,DateTimedate)

{

this.airportCode=airportCode;

this.date=date;

}

//properties

publicstringAirportCode

{

get{returnthis.airportCode;}

set{this.airportCode=value;}

}

publicDateTimeDate

{

Page 556: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

get{returnthis.date;}

set{this.date=value;}

}

}

[Serializable]

publicenumTripMode

{

OneWay,

RoundTrip

}

}

As you can see, Trip class uses the TripPoint class to representdeparture and return, which are exposed as StartingFrom andReturningFrom properties. It also uses TripMode enumeration tospecifywhether the trip isonewayor return trip,which is exposedasModeproperty.Finally,let'sseethecode-behindclassthattieseverythingtogether:

publicclassTripForm:Spring.Web.UI.Page

{

//model

privateTriptrip;

publicTripTrip

{

get{returntrip;}

set{trip=value;}

}

//servicedependency,injectedbySpringIoCcontainer

privateIBookingAgentbookingAgent;

publicIBookingAgentBookingAgent

{

set{bookingAgent=value;}

}

//modelmanagementmethods

protectedoverridevoidInitializeModel()

{

Page 557: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

trip=newTrip();

trip.Mode=TripMode.RoundTrip;

trip.StartingFrom.Date=DateTime.Today;

trip.ReturningFrom.Date=DateTime.Today.AddDays(1);

}

protectedoverridevoidLoadModel(objectsavedModel)

{

trip=(Trip)savedModel;

}

protectedoverrideobjectSaveModel()

{

returntrip;

}

//databindingrules

protectedoverridevoidInitializeDataBindings()

{

BindingManager.AddBinding("tripMode.Value","Trip.Mode"

BindingManager.AddBinding("leavingFromAirportCode.SelectedValue"

BindingManager.AddBinding("goingToAirportCode.SelectedValue"

BindingManager.AddBinding("departureDate.SelectedDate"

BindingManager.AddBinding("returnDate.SelectedDate",

}

//eventhandlerforfindFlightsbutton,usesinjected'bookingAgent'

//serviceandmodel'trip'objecttofindflights

privatevoidSearchForFlights(objectsender,EventArgse)

{

FlightSuggestionssuggestions=bookingAgent.SuggestFlights(trip);

if(suggestions.HasOutboundFlights)

{

//redirecttoSuggestedFlightspage

}

}

}

Therearequiteafewthingsthatarehappeninginthisrelativelysimplepieceofcode,soit'sworththatwespendsometimeoneachone:

1. When the page is initially loaded (IsPostback==false), the

Page 558: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

InitializeModel()methodiscalledwhichinitializesthetripobjectbycreatinganewinstanceandsettingitspropertiestodesiredvalues.Rightbefore the page is rendered, the SaveModel() method will beinvokedandwhatever thevalue it returnswillbestoredwithin theHTTPSession.Finally,oneachpostback,theLoadModel()methodwillbecalledandthevaluereturnedbythepreviouscalltoSaveModelwillbepassedtoitasanargument.Inthisparticularcasetheimplementationisverysimplebecauseourwholemodel is just thetripobject.As such,SaveModel() simply returnsthe trip object and LoadModel() casts the savedModel()argumenttoTripandassignsittothetripfieldwithinthepage.Inthemore complex scenarios, youwill typically return adictionary containingyourmodelobjectsfromtheSaveModel()method,andreadthevaluesfromthatdictionarywithintheLoadModel().

2. InitializeDataBindingsmethoddefinesthebindingrules forallfiveinputcontrolsonourform.ItdoessobyinvokingAddBindingmethod on the BindingManager exposed by the page.AddBindingmethodisheavilyoverloadedanditallowsyoutospecifya binding direction and a formatter to use in addition to the source andtargetbindingexpressionsthatareusedabove.We'lldiscusstheseoptionalparameters shortly, but for now let's focus on the source and targetexpressions.The Data Binding framework uses Spring.NET Expression Language todefinebindingexpressions.Inmostcases,likeintheexampleabove,bothsourceandtargetexpressionwillevaluatetoapropertyorafieldwithinoneofthecontrolsoradatamodel.Thisisalwaysthecasewhenyouaresettingabi-directionalbinding,asbothbindingexpressionsneedtobe"settable".WhatisimportanttorememberaboutInitializeDataBindingsmethodisthat it isexecutedonlyonceperpagetype.Basically,allof thebindingexpressionsareparsedthefirsttimethepageisinstantiated,andarethecachedandusedbyallinstancesofthatsamepagetypethatarecreatedat a later time. This is done for performance reasons, as data bindingexpression parsing on every postback is unnecessary and would add asignificantoverheadtotheoverallpageprocessingtime.

Page 559: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

3. IfyoulookattheSearchForFlightseventhandler,youwillnoticethatithasno dependencies on the view elements. It simply uses the injectedbookingAgent service and a trip object that in order to obtain a list ofsuggested flights. Furthermore, if youmake anymodifications to the tripobject within your event handler, bound controls will be updatedaccordinglyjustbeforethepageisrendered.Thisaccomplishesoneof themajorgoalswesetout toachieve,allowingdeveloperstoremoveviewelementreferencesfromthepageeventhandlersanddecouplecontroller-typemethodsfromtheview.

Now thatyouhavea solidhigh-levelpictureofhowSpring.NETdatabindingandmodelmanagementaretypicallyusedinwebapplications,let'stakealookatthedetailsandseehowdatabindingisactuallyimplementedunderthehood,whattheextensionpointsare,andwhataresomeadditionalfeaturesthatmakedatabindingframeworkusableinreal-worldapplications.

22.7.1.DataBindingUndertheHoodSpring.NET Data Binding framework revolves around two main interfaces:IBinding andIBindingContainer.TheIBinding interface isdefinitelythemoreimportantoneofthetwo,asithastobeimplementedbyallbindingtypes.Thisinterfacedefinesseveralmethods,withsomeofthembeingoverloadedforconvenience:

publicinterfaceIBinding

{

voidBindSourceToTarget(objectsource,objecttarget,ValidationErrorsvalidationErrors);

voidBindSourceToTarget(objectsource,objecttarget,ValidationErrorsvalidationErrors,

IDictionaryvariables);

voidBindTargetToSource(objectsource,objecttarget,ValidationErrorsvalidationErrors);

voidBindTargetToSource(objectsource,objecttarget,ValidationErrorsvalidationErrors,

IDictionaryvariables);

voidSetErrorMessage(stringmessageId,paramsstring[]errorProviders);

}

Astheirnamesimply,BindSourceToTargetmethod isused toextract

Page 560: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

and copy bound values from the source object to the target object, whileBindTargetToSource does the opposite. Both method names andparameter typesareverygeneric for a good reason -- data binding frameworkcanindeedbeusedtobindanytwoobjects.Usingittobindwebformstomodelobjectsisjustoneofitspossibleuses,althoughaverycommononeandtightlyintegratedintotheSpring.NETWebFramework.ThevalidationErrors parameter requires further explanation. Whilethe data binding framework is not in any way coupled to the data validationframework, they are in some ways related. For example, while the datavalidationframeworkisbestsuitedtovalidatethepopulatedmodelaccordingtothebusinessrules,thedatabindingframeworkisinabetterpositiontovalidatedata types during the binding process. However, regardless of where specificvalidationisperformed,allerrormessagesshouldbepresentedtotheuserinaconsistent manner. In order to accomplish this, Spring.NETWeb Frameworkpasses the same ValidationErrors instance to binding methods and to anyvalidators thatmightbeexecutedwithinyoureventhandlers.Thisensures thatallerrormessagesarestoredtogetherandaredisplayedconsistently to theenduser,usingSpring.NETvalidationerrorcontrols.The last method in the IBinding interface, SetErrorMessage,enablesthisbyallowingyoutospecifytheresourceidoftheerrormessagetobedisplayedinthecaseofbindingerror,aswellasthelistoferrorprovidersthatmessages should be displayed in. We will see an example of theSetErrorMessageusageshortly.

TheIBindingContainer interface extends theIBinding interfaceandaddsthefollowingmembers:

publicinterfaceIBindingContainer:IBinding

{

boolHasBindings{get;}

IBindingAddBinding(IBindingbinding);

IBindingAddBinding(stringsourceExpression,stringtargetExpression);

IBindingAddBinding(stringsourceExpression,stringtargetExpression,BindingDirectiondirection);

IBindingAddBinding(stringsourceExpression,stringtargetExpression,IFormatterformatter);

IBindingAddBinding(stringsourceExpression,stringtargetExpression,BindingDirectiondirection,

IFormatterformatter);

}

Page 561: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

As you can see, this interface has a number of overloadedAddBindingmethods. The first one,AddBinding(IBindingbinding) is themostgenericone,asitcanbeusedtoaddanybindingtypetothecontainer.Theotherfourareconveniencemethods thatprovideasimplewaytoadd themostcommonly used binding type, SimpleExpressionBinding. TheSimpleExpressionBinding is what we used in the example at thebeginning of this section to bind our web form to aTrip instance. It usesSpring.NETExpressionLanguagetoextractandtosetvalueswithinsourceandtarget objects. We discussed sourceExpression andtargetExpression arguments earlier, so let's focus on the remainingones.

22.7.1.1.BindingDirectionThe direction argument determines whether the binding is bidirectional orunidirectional.Bydefault,alldatabindingsarebidirectionalunlessthedirectionargumentissettoeitherBindingDirection.SourceToTargetorBindingDirection.TargetToSource.Ifoneofthesetwovaluesis specified, binding will be evaluated only when the appropriateBindDirectionmethodisinvoked,andwillbecompletelyignoredintheotherdirection.Thisisveryusefulwhenyouwanttobindsomeinformationfromthemodelintonon-inputcontrols,suchaslabels.However, unidirectional data bindings are also usefulwhen your form doesn'thaveasimpleone-to-onemappingtopresentationmodel.Inourearliertripformexample,thepresentationmodelwasintentionallydesignedtoallowforsimpleone-to-onemappings.Forthesakeofdiscussion,let'saddtheAirportclassandmodifyourTripPointclasslikethis:

namespaceSpringAir.Domain

{

[Serializable]

publicclassTripPoint

{

//fields

privateAirportairport;

privateDateTimedate;

Page 562: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

//constructors

publicTripPoint()

{}

publicTripPoint(Airportairport,DateTimedate)

{

this.airport=airport;

this.date=date;

}

//properties

publicAirportAirport

{

get{returnthis.airport;}

set{this.airport=value;}

}

publicDateTimeDate

{

get{returnthis.date;}

set{this.date=value;}

}

}

[Serializable]

publicclassAirport

{

//fields

privatestringcode;

privatestringname;

//properties

publicstringCode

{

get{returnthis.code;}

set{this.code=value;}

}

publicstringName

{

get{returnthis.name;}

set{this.name=value;}

Page 563: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

}

}

InsteadofthestringpropertyAirportCode,ourTripPointclassnowexposes anAirport propertyof typeAirport,which is defined above.Nowwehaveaproblem:whatusedtobeasimplestringtostringbinding,withthe airport code selected in a dropdown being copied directly into theTripPoint.AirportCode property and vice versa, now becomes a not so simplestring to Airport binding, so let's see how we can solve this mismatchproblem.Firstofall,bindingfromthemodeltothecontrolisstillverystraightforward.Wejustneedtosetupone-waybindingsfromthemodeltocontrols:

protectedoverridevoidInitializeDataBindings()

{

BindingManager.AddBinding("leavingFromAirportCode.SelectedValue"

BindingManager.AddBinding("goingToAirportCode.SelectedValue"

...

}

All we need to do is extract airport code value from theTrip.StartingFrom.Airport.Code instead ofTrip.StartingFrom.AirportCode. Unfortunately, binding fromthe control to the model the same way won't work: we might be able to setCode property of the Airport object, but that will likely make theAirport.Namepropertyinvalid.Whatwereallywantdoisfindaninstanceof the Airport class based on the airport code and set theTripPoint.Airportpropertytoit.Fortunately,thisisverysimpletodowith Spring.NET data binding, especially because we already haveairportDao object defined in the Spring context, which hasGetAirport(stringairportCode) findermethod.Allweneedtodo is set updata bindings from source to target thatwill invoke this findermethodwhenevaluatingthesourceexpression.Ourcompletesetofbindingsforthesetwodropdownlistswillthenlooklikethis:

protectedoverridevoidInitializeDataBindings()

Page 564: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

{

BindingManager.AddBinding("@(airportDao).GetAirport(leavingFromAirportCode.SelectedValue)"

BindingManager.AddBinding("leavingFromAirportCode.SelectedValue"

BindingManager.AddBinding("@(airportDao).GetAirport(goingToAirportCode.SelectedValue)"

BindingManager.AddBinding("goingToAirportCode.SelectedValue"

...

}

That's it --byusing twounidirectionalbindingswithdifferentexpressionsandby leveraging the fact that expressions can reference objects defined in theSpringcontext,wewereabletosolvethisnon-trivialdatabindingproblem.

22.7.1.2.FormattersThe last argument to AddBinding method that we need to discuss is aformatterargument.Thisargumentallowsyoutospecifyaformatterthatshouldbeused toparse stringvalue from the typical input controlbefore it isboundtothemodel,andtoformatstronglytypedmodelvaluebeforeitisboundtothecontrol.You will typically use one of the formatters provided in theSpring.Globalization.Formatters namespace, but if you have requirements thatcannotbesatisfiedbyoneofthestandardformatters it iseasyenoughtowriteyourown--allyouneedtodoisimplementaverysimpleIFormatterinterface:

publicinterfaceIFormatter

{

stringFormat(objectvalue);

objectParse(stringvalue);

}

Standard formatters provided with Spring.NET are:CurrencyFormatter, DateTimeFormatter,FloatFormatter,IntegerFormatter, NumberFormatterand PercentFormatter, which should be sufficient for most usagescenarios.

22.7.1.3.TypeConversion

Page 565: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Becausethedatabindingframeworkusesthesameexpressionevaluationengineas the Spring.NET IoC container, itwill use any registered type converters toperformdatabinding.ManytypeconvertersareincludedwithSpring.NET(takea look at the classes in Spring.Objects.TypeConverters namespace) andautomatically registered for you, but you can implement your own customconverters and register them using standard Spring.NET type converterregistrationmechanisms.

22.7.1.4.DataBindingEventsSpring.Web's base Page class adds two events to the standard .NET pagelifecycle-DataBoundandDataUnbound.

TheDataUnbound event is fired after the data model has been updatedusingvaluesfromthecontrols.ItisfiredrightaftertheLoadeventandonlyonpostbacks, because it doesn't make sense to update the data model using thecontrols'initialvalues.TheDataBoundisfiredaftercontrolshavebeenupdatedusingvaluesfromthedatamodel.ThishappensrightbeforethePreRenderevent.

ThefactthatdatamodelisupdatedimmediatelyaftertheLoadeventandthatcontrolsareupdatedrightbeforethePreRendereventmeansthatyoureventhandlers will be able to work with a correctly updated data model, as theyexecuteaftertheLoadevent,andthatanychangesyoumaketothedatamodelwithineventhandlerswillbereflectedinthecontrolsimmediatelyafterwards,asthey(thecontrols)areupdatedpriortotheactualrendering.

22.7.1.5.RenderingBindingErrorsIfthereareerrorsinthedatabinding,forexample,tryingtobindastring'hello'to an integer property on themodel, you can specify how those fundamentalbindingerrorsshouldberendered.AnexampleofthisshownbelowtakenfromtheWebQuickStart'RobustEmployeeInfo'example.

[Default.aspx.cs]

protectedoverridevoidInitializeDataBindings()

{

//collecttxtId.Textbindingerrorsin"id.errors"collection

Page 566: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

BindingManager.AddBinding("txtId.Text","Employee.Id").SetErrorMessage(

...

[Default.aspx]

...

<asp:TextBoxID="txtId"runat="server"/>

<!--outputvalidationerrorsfrom"id.errors"collection-->

<spring:ValidationErrorProvider="id.errors"runat="server"/>

...

The SetErrorMessage specifies the message text or resource id of the errormessagetobedisplayedfollowedbyavariablelengthlistofstringsthatspecifythe collection of error providers message where the message should bedisplayed. In the above case the error provider will be rendered in Spring'sValidationErrorUserControl.See

22.7.1.6.HttpRequestListBindingContainerHttpRequestListBindingContainer extracts posted raw values from the requestand populates the specified IList by creating objects of the type specified andpopulatingeachoftheseobjectsaccordingtotherequestBindingscollection.Please checkout the WebQuickStart sample's demo ofHttpRequestListBindingContainer.Below

protectedoverridevoidInitializeDataBindings()

{

//HttpRequestListBindingContainerunbindsspecifiedvaluesfromRequest->Productlist

HttpRequestListBindingContainerrequestBindings=

newHttpRequestListBindingContainer("sku,name,quantity,price"

requestBindings.AddBinding("sku","Sku");

requestBindings.AddBinding("name","Name");

requestBindings.AddBinding("quantity","Quantity",quantityFormatter);

requestBindings.AddBinding("price","Price",priceFormatter);

BindingManager.AddBinding(requestBindings);

}

NoteDuetothefact,thatbrowsersdon'tsendthevaluesofuncheckedcheckboxes,youcan'tuse

Page 567: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

HttpRequestListBindingContainerwith<inputtype="checkbox">htmlcontrols.

22.7.2.UsingDataBindingPanelTo simplify use of Spring's Data Binding feature on web pages and controls,Spring.Web provides a special DataBindingPanel container control. ADataBindingPaneldoesnotrenderanyhtmlcodeitself,butallowsforspecifyingadditional,databindingrelatedattributestoitschildcontrols:

<%@PageLanguage="C#"CodeFile="Default.aspx.cs"Inherits="DataBinding_EasyEmployeeInfo_Default"

<%@RegisterTagPrefix="spring"Namespace="Spring.Web.UI.Controls"

<html>

<body>

<spring:DataBindingPanelID="ctlDataBindingPanel"runat="server"

<tablecellpadding="3"cellspacing="3"border="0">

<tr>

<td>EmployeeID:</td>

<td>

<asp:TextBoxID="txtId"runat="server"BindingTarget

</td>

</tr>

<tr>

<td>FirstName:</td>

<td><asp:TextBoxID="txtFirstName"runat="server"

</tr>

</table>

</spring.DataBindingPanel>

</body>

</html>

UsingDataBindingPanelthebindinginformationcanbespecifieddirectlyonthecontrol declaration. The following attributes are recognized by aDataBindingPanel:

BindingTargetcorresponds to the target expression used inIBindingContainer.AddBinding()

BindingSourcecorresponds to the source expression used in

Page 568: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

IBindingContainer.AddBinding(). For standard controls you don't need tospecifythesourceexpression.Ifyouarebindingtosomecustomcontrol,ofcourseyoumustspecificthisattribute.

BindingDirectiononeofthevaluesoftheBindingDirectionenumeration

BindingFormatterif you need a custom formatter, you can specific the object name of aformatter here. The formatter instance will be obtained by a call toIApplicationContext.GetObject()eachtimeitisneeded.

BindingTypeIn case you need a completely customized binding, specify its typehere.Notethatacustombindingtypemustimplementthefollowingconstructorsignature:ctor(string source,string target,

BindingDirection,IFormatter)

NoteTheVisualStudioWebFormEditorwillofcoursecomplainaboutbindingattributesbecauseitdoesn'tknowthem.Youcansafelyignorethosewarnings.

22.7.3.CustomizingModelPersistenceAswasalreadymentionedintheintroductiontothischapter,modelmanagementneeds an application developer to override InitializeModel(),SaveModel() and LoadModel() for storing model informationbetween requests in the user's session. On web farms this of course storinginformation in a user's session is not a good strategy. Thus it is possible tochoose another persistence strategy by setting a Spring.Web.UI.Page's resp.Spring.Web.UI.UserControl'sModelPersistenceMediumproperty:

<objectid="modelPersister"type="Sample.DatabaseModelPersistenceMedium,MyCode"

<objecttype="UserRegistration.aspx">

<propertyname="ModelPersistenceMedium"ref="modelPersister"

</object>

Page 569: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Toimplementanyarbitrarypersistencestrategy,onesimplyneedstoimplementtheIModelPersistenceMediuminterface:

publicinterfaceIModelPersistenceMedium

{

//Loadthemodelforthespecifiedcontrolcontext.

objectLoadFromMedium(Controlcontext);

//Savethespecifiedmodelobject.

voidSaveToMedium(Controlcontext,objectmodelToSave);

}

Page 570: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.8.LocalizationandMessageSourcesWhile recognizing that the .NET framework has excellent support forlocalization,thesupportwithinASP.NET1.xissomewhatincomplete.Every.aspxpageinanASP.NETprojecthasaresourcefileassociatedwithit,but those resourcesareneverused (by thecurrentASP.NET infrastructure).ASP.NET 2.0 will change that and allow application developers to use localresources for pages. In the meantime, the Spring.NET team built support forusing local pages resources into Spring.Web thus allowing applicationdeveloperstostartusingASP.NET2.0-likepageresourcesimmediately.Spring.Web supports several different approaches to localizationwithin awebapplication,whichcanbemixedandmatchedasappropriate.Bothpushandpullmechanismsaresupported,aswellasthefallbacktogloballydefinedresourceswhen a local resource cannot be found. Spring.Web also provides support foruserculturemanagementandimagelocalization,whicharedescribedinthelatersections.

Tip

IntroductorymaterialcoveringASP.NETGlobalizationandLocalizationcanbefoundatthefollowingURLs;GlobalizationArchitectureforASP.NETandLocalizationPracticesforASP.NET2.0byMicheleLerouxBustamante.

22.8.1. Automatic Localization Using Localizers ("Push"Localization)Thecentralideabehind'push'localizationisthatanapplicationdevelopershouldbe able to specify localization resources in the resource file for the page andhave those resourcesautomaticallyapplied to theusercontrolson thepagebytheframework.Forexample,anapplicationdevelopercoulddefineapagesuchasUserRegistration.aspx...

<%@RegisterTagPrefix="spring"Namespace="Spring.Web.UI.Controls"

<%@Pagelanguage="c#"Codebehind="UserRegistration.aspx.cs"

AutoEventWireup="false"Inherits="ArtFair.Web.UI.Forms.UserRegistration"

<html>

<body>

<spring:Contentid="mainContent"contentPlaceholderId

Page 571: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<divalign="right">

<asp:LinkButtonID="english"Runat="server"

<asp:LinkButtonID="serbian"Runat="server"

</div>

<table>

<tr>

<td><asp:Labelid="emailLabel"Runat="server"

<td><asp:TextBoxid="email"Runat="server"

</tr>

<tr>

<td><asp:Labelid="passwordLabel"Runat=

<td><asp:TextBoxid="password"Runat="server"

</tr>

<tr>

<td><asp:Labelid="passwordConfirmationLabel"

<td><asp:TextBoxid="passwordConfirmation"

</tr>

<tr>

<td><asp:Labelid="nameLabel"Runat="server"

<td><asp:TextBoxid="name"Runat="server"

</tr>

...

<tr>

<tdcolspan="2">

<asp:Buttonid="saveButton"Runat="server"

<asp:Buttonid="cancelButton"Runat=

</td>

</tr>

</table>

</spring:Content>

</body>

</html>

Acloseinspectionoftheabove.aspxcoderevealsthatnoneoftheLabelorButton controls have had a value assigned to theText property. ThevaluesoftheTextpropertyforthesecontrolsarestoredinthelocal resourcefile(ofthepage)usingthefollowingconventiontoidentifytheresource(string).

$this.controlId.propertyName

Page 572: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The corresponding local resource file,UserRegistration.aspx.resx,isshownbelow.

<root>

<dataname="$this.emailLabel.Text">

<value>Email:</value>

</data>

<dataname="$this.passwordLabel.Text">

<value>Password:</value>

</data>

<dataname="$this.passwordConfirmationLabel.Text">

<value>Confirmpassword:</value>

</data>

<dataname="$this.nameLabel.Text">

<value>Fullname:</value>

</data>

...

<dataname="$this.countryLabel.Text">

<value>Country:</value>

</data>

<dataname="$this.saveButton.Text">

<value>$messageSource.save</value>

</data>

<dataname="$this.cancelButton.Text">

<value>$messageSource.cancel</value>

</data>

</root>

VS2003

Toviewthe.resxfileforapage,youmayneedtoenable"Project/ShowAllFiles"inVisualStudio.When"ShowAllFiles"isenabled,the.resxfileappearslikea"child"ofthecode-behindpage.WhenVisualStudiocreatesthe.resxfile,itwillincludeaxds:schemaelementandseveralresheadelements.Yourdataelementswillfollowtheresheadelements.Whenworkingwiththe.resxfiles,youmaywanttochoose"OpenWith"fromthecontextmenuandselectthe"SourceCode"texteditor.

Page 573: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

VS2005

TocreatearesourcefileinVS2005,openyourcontrolorpageindesignmodeandselect"Tools/Generatelocalresource"fromthemenu

Finally a localizer must be configured for the page to enable automaticlocalization:

<objectid="localizer"type="Spring.Globalization.Localizers.ResourceSetLocalizer,Spring.Core"

<objecttype="UserRegistration.aspx">

<propertyname="Localizer"ref="localizer"/>

</object>

For more information on configuring localizers see Section 22.8.3, “Working withLocalizers”

22.8.2.GlobalMessageSourcesThe last two resource definitions from the previous section require someadditionalexplanation:

<dataname="$this.saveButton.Text">

<value>$messageSource.save</value>

</data>

<dataname="$this.cancelButton.Text">

<value>$messageSource.cancel</value>

</data>

In some cases it makes sense to apply a resource that is defined globally asopposedtolocally.Inthisexample,itmakesbettersensetodefinevaluesfortheSaveandCancelbuttonsgloballyastheywillprobablybeusedthroughouttheapplication.The above example demonstrates how one can achieve that by defining aresourceredirection expression as thevalue of a local resource by prefixing aglobalresourcenamewiththefollowingstring.

$messageSource.

Page 574: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Taking the case of the above example, this will tell the localizer to use thesaveandcancelportionsoftheresourcekeyaslookupkeystoretrievetheactualvaluesfromaglobalmessagesource.Theimportantthingtorememberisthat one need only define a resource redirect once, typically in the invariantresource file – any lookup for a resource redirectwill simply fall back to theinvariantculture,andresultinaglobalmessagesourcelookupusingthecorrectculture.Global resources are (on a per-context basis) defined as a plain vanilla objectdefinitionusingthereservednameof'messageSource',whichonecanaddtoone'sSpring.NETconfigurationfileasshownbelow.

<objectid="messageSource"type="Spring.Context.Support.ResourceSetMessageSource,Spring.Core"

<propertyname="ResourceManagers">

<list>

<value>MyApp.Web.Resources.Strings,MyApp.Web</value>

</list>

</property>

</object>

NET2.0TouseresourcesfromyourApp_GlobalResourcesfolder,specifyApp_GlobalResourcesasassemblyname(seetheSpringAirexampleapplicationformore):

<value>Resources.Strings,

App_GlobalResources</value>

The global resources are cached within the Spring.NETIApplicationContext and are accessible through the Spring.NETIMessageSourceinterface.

TheSpring.WebPageandUserControlclasseshaveareferencetotheirowning IApplicationContext and it's associatedIMessageSource. As such, they will automatically redirect resourcelookupstoaglobalmessagesourceifalocalresourcecannotbefound.Currently, the ResourceSetMessageSource is the only messagesourceimplementationthatshipswithSpring.NET.

Page 575: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.8.3.WorkingwithLocalizersInordertoapplyresourcesautomatically,alocalizerneedstobeinjectedintoallpagesrequiringthisfeature(typicallyaccomplishedusingabasepagedefinitionthat other pages will inherit from). The injected localizer will inspect theresourcefilewhenthepageisfirstrequested,cachetheresourcesthatstartwiththe'$this'marker string value, and apply the values to the controls thatpopulatethepagepriortothepagebeingrendered.A localizer is simply an object that implements theSpring.Globalization.ILocalizer interface.Spring.Globalization.AbstractLocalizer is provided asa convenient base class for localization: this class has one abstract method,LoadResources. This method must load and return a list of all theresourcesthatmustbeautomaticallyappliedfromtheresourcestore.Spring.NET ships with one concrete implementation of a localizer,Spring.Globalization.Localizers.ResourceSetLocalizer

that retrieves a list of resources to apply from the local resource file. FuturereleasesofSpring.NETmayprovideotherlocalizersthatreadresourcesfromanXMLfileorevenaflat textfilethatcontainsresourcename-valuepairswhichwill allow application developers to store resources within the files in a webapplication insteadof as embedded resources in an assembly.Of course, if anapplicationdeveloperwouldratherstoresuchresourcesinadatabase,heorshecan write their ownILocalizer implementation that will load a list ofresourcestoapplyfromadatabase.Asmentionedpreviously,onewouldtypicallyconfigurethelocalizertobeusedwithin an abstract base definition for those pages that require localization asshownbelow.

<objectid="localizer"type="Spring.Globalization.Localizers.ResourceSetLocalizer,Spring.Core"

<objectname="basePage"abstract="true">

<description>

Pagesthatreferencethisdefinitionastheirparent

(seeexamplesbelow)willautomaticallyinheritfollowingproperties.

</description>

<propertyname="Localizer"ref="localizer"/>

</object>

Page 576: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Ofcourse,nothingprevents anapplicationdeveloper fromdefiningadifferentlocalizerforeachpageintheapplication;inanycase,onecanalwaysoverridethelocalizerdefinedinabase(page)definition.Alternatively,ifonedoeswantanyresourcestobeappliedautomaticallyonecancompletelyomitthelocalizerdefinition.Onelast thingtonoteis thatSpring.NETUserControl instanceswill(bydefault) inherit the localizer and other localization settings from the page thattheyarecontainedwithin,butonecansimilarlyalsooverridethatbehaviorusingexplicitdependencyinjection.

22.8.4.ApplyingResourcesManually("Pull"Localization)Whileautomaticlocalizationasdescribedaboveworksgreatformanyform-likepages,itdoesn'tworknearlyaswellforthecontrolsdefinedwithinanyiterativecontrolsbecausetheIDsforsuchiterativecontrolsarenotfixed.Italsodoesn'tworkwellinthosecaseswhereoneneedstodisplaythesameresourcemultipletimes within the same page. For example, think of the header columns foroutgoing and return flights tables within the SpringAir application (seeChapter37,SpringAir-ReferenceApplication).Inthesesituations,oneshoulduseapull-stylemechanismforlocalization,whichboilsdowntoasimpleGetMessagecallasshownbelow.

<asp:Repeaterid="outboundFlightList"Runat="server">

<HeaderTemplate>

<tableborder="0"width="90%"cellpadding="0"cellspacing

<thead>

<trclass="suggestedTableCaption">

<thcolspan="6">

<%=GetMessage("outboundFlights")%>

</th>

</tr>

<trclass="suggestedTableColnames">

<th><%=GetMessage("flightNumber")%></th>

<th><%=GetMessage("departureDate")%></th>

<th><%=GetMessage("departureAirport")%></th>

<th><%=GetMessage("destinationAirport")%></th>

<th><%=GetMessage("aircraft")%></th>

<th><%=GetMessage("seatPlan")%></th>

Page 577: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</tr>

</thead>

<tbody>

</HeaderTemplate>

The GetMessage method is available within both theSpring.Web.UI.Page and Spring.Web.UI.UserControlclasses,anditwillautomaticallyfallbacktoaglobalmessagesourcelookupifalocalresourceisnotfound.

22.8.5.LocalizingImageswithinaWebApplicationSpring.Webprovides an easy (and consistent)way to localize imageswithin aweb application.Unlike text resources,which can be storedwithin embeddedresourcefiles,XMLfiles,orevenadatabase,imagesinatypicalwebapplicationareusuallystoredasfilesonthefilesystem.Usingacombinationofdirectorynaming conventions and a custom ASP.NET control, Spring.Web allowsapplication developers to localize images within the page as easily as textresources.TheSpring.WebPage class exposes theImagesRoot property,which isused todefine therootdirectorywhere imagesarestored.Thedefaultvalue is'Images', whichmeans that the localizer expects to find an 'Images' directorywithintheapplicationroot,butonecansetittoanyvalueinthedefinitionofthepage.In order to localize images, one needs to create a directory for each localizedcultureundertheImagesRootdirectoryasshownbelow.

/MyApp

/Images

/en

/en-US

/fr

/fr-CA

/sr-SP-Cyrl

/sr-SP-Latn

...

Once an appropriate folder hierarchy is in place all one need do is put the

Page 578: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

localized images in the appropriate directories and make sure that differenttranslationsofthesameimagearenamedthesame.Inordertoplacealocalizedimageonapage,oneneedstousethe<spring:LocalizedImage>asshownbelow.

<%@Pagelanguage="c#"Codebehind="StandardTemplate.aspx.cs"

AutoEventWireup="false"Inherits="SpringAir.Web.StandardTemplate"

<%@RegisterTagPrefix="spring"Namespace="Spring.Web.UI.Controls"

<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.0Transitional//EN"

<html>

<body>

<spring:LocalizedImageid="logoImage"imageName="spring-air-logo.jpg"

</body>

</html>

Thiscontrolwillfindthemostspecificdirectorythatcontainsanimagewiththespecifiednameusingstandardlocalizationfallbackrulesandtheuser'sculture.Forexample, if theuser'sculture is'en-US', the localizerwill lookfor thespring-air-logo.jpg file in Images/en-US, then inImages/enandfinally,iftheimagefilehasstillnotbeenfound,intherootImages directory (which for all practical purposes serves as an invariantculturefolder).

22.8.6.UserCultureManagementIn addition to global and local resource management, Spring.Web also addssupportforuserculturemanagementbyexposingthecurrentCultureInfothrough theUserCulture property on thePage andUserControlclasses.TheUserCulture property will simply delegate culture resolution to animplementation ofSpring.Globalization.ICultureResolver interface. Onecan specify exactly which culture resolver to use by configuring theCultureResolver property of the Page class in the relevant objectdefinitionasshownbelow.

<objectname="BasePage"abstract="true">

<propertyname="CultureResolver">

Page 579: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objecttype="Spring.Globalization.Resolvers.CookieCultureResolver,Spring.Web"

</property>

</object>

Several useful implementations ofICultureResolver ship as part ofSpring.Web,soitisunlikelythatapplicationdeveloperswillhavetoimplementtheir ownculture resolver.However, if onedoeshave such a requirement, theresultingimplementationshouldbefairlystraightforwardas thereareonly twomethodsthatoneneedimplement.ThefollowingsectionsdiscusseachavailableimplementationoftheICultureResolverinterface.

22.8.6.1.DefaultWebCultureResolverThis isdefaultculture resolver implementation. Itwillbeused ifonedoesnotspecify a culture resolver for a page, or if one explicitly injects aDefaultWebCultureResolverintoapagedefinitionexplicitly.Thelatter case (explicit injection) is sometimes useful because it allows one tospecify a culture that should always be used by providing a value to theDefaultCulturepropertyontheresolver.

The DefaultWebCultureResolver will first look at theDefaultCulturepropertyandreturnitsvalueifsaidpropertyvalueisnotnull.Ifitisnull,theDefaultWebCultureResolverwillfallbacktorequest header inspection, and finally, if no 'Accept-Lang' requestheadersarepresentitwillreturntheUIcultureofthecurrentlyexecutingthread.

22.8.6.2.RequestCultureResolverThis resolver works in a similar way to theDefaultWebCultureResolver with the exception that it alwayschecks request headers first, and only then falls back to the value of theDefaultCulturepropertyortheculturecodeofthecurrentthread.

22.8.6.3.SessionCultureResolverThisresolverwilllookforcultureinformationintheuser'ssessionandreturnitif it finds one. If not, it will fall back to the behavior of theDefaultWebCultureResolver.

Page 580: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.8.6.4.CookieCultureResolverThisresolverwilllookforcultureinformationinacookie,andreturnitifitfindsone. If not, it will fall back to the behavior of theDefaultWebCultureResolver.

Warning

CookieCultureResolverwillnotworkifyourapplicationuseslocalhostastheserverURL,whichisatypicalsettinginadevelopmentenvironment.InordertoworkaroundthislimitationyoushoulduseSessionCultureResolverduringdevelopmentandswitchtoCookieCultureResolverbeforeyoudeploytheapplicationinaproduction.ThisiseasilyaccomplishedinSpring.Web(simplychangetheconfigfile)butissomethingthatyoushouldbeawareof.

22.8.7.ChangingCulturesInordertobeabletochangethecultureapplicationdeveloperswillneedtouseone of the culture resolvers that support culture changes, such asSessionCultureResolver or CookieCultureResolver.One could also write a custom ICultureResolver that will persistcultureinformationinadatabase,aspartofauser'sprofile.Once that requirement is satisfied, all that one need do is to set theUserCulturepropertytoanewCultureInfoobjectbeforethepageis rendered. In thefollowing.aspx example, there are two linkbuttons thatcanbeusedtochangetheuser'sculture.Inthecode-behind,thisisalloneneeddo to set the new culture. A code snippet for the code-behind file(UserRegistration.aspx.cs)isshownbelow.

protectedoverridevoidOnInit(EventArgse)

{

InitializeComponent();

this.english.Command+=newCommandEventHandler(this.SetLanguage);

this.serbian.Command+=newCommandEventHandler(this.SetLanguage);

Page 581: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

base.OnInit(e);

}

privatevoidSetLanguage(objectsender,CommandEventArgse)

{

this.UserCulture=newCultureInfo((string)e.CommandArgument);

}

Page 582: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.9.ResultMappingOneof theproblemsevident inmanyASP.NETapplications is that there isnobuilt-inwaytoexternalizetheflowofanapplication.Themostcommonwayofdefining application flow is by hardcoding calls to theResponse.Redirect and Server.Transfer methods withineventhandlers.Thisapproachisproblematicbecauseanychangestotheflowofanapplicationnecessitates code changes (with the attendant recompilation, testing,redeployment, etc).Amuchbetterway, andone thathasbeenproven toworksuccessfullyinmanyMVC(Model-View-Controller)webframeworksis toprovidethemeanstoexternalizethemappingofactionresultstotargetpages.Spring.WebaddsthisfunctionalitytoASP.NETbyallowingonetodefineresultmappingswithin thedefinitionofapage,and to thensimplyuse logical resultnameswithineventhandlerstocontrolapplicationflow.In Spring.Web, a logical result is encapsulated and defined by theResultclass;becauseofthisonecanconfigureresultsjustlikeanyotherobject:

<objectsxmlns="http://www.springframework.net">

<objectid="homePageResult"type="Spring.Web.Support.Result,Spring.Web"

<propertyname="TargetPage"value="~/Default.aspx"/>

<propertyname="Mode"value="Transfer"/>

<propertyname="Parameters">

<dictionary>

<entrykey="literal"value="MyText"/>

<entrykey="name"value="%{UserInfo.FullName}"

<entrykey="host"value="%{Request.UserHostName}"

</dictionary>

</property>

</object>

<objectid="loginPageResult"type="Spring.Web.Support.Result,Spring.Web"

<propertyname="TargetPage"value="Login.aspx"/>

<propertyname="Mode"value="Redirect"/>

</object>

<objecttype="UserRegistration.aspx"parent="basePage">

<propertyname="UserManager"ref="userManager"/>

Page 583: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<propertyname="Results">

<dictionary>

<entrykey="userSaved"value-ref="homePageResult"

<entrykey="cancel"value-ref="loginPageResult"

</dictionary>

</property>

</object>

</objects>

TheonlypropertythatyoumustsupplyavalueforeachandeveryresultistheTargetPage property. The value of the Mode property can be eitherTransfer, TransferNoPreserve, Redirect, and defaults toTransfer if none is specified. TransferNoPreserve issues a server-sidetransferwith 'preserveForm=false', so thatQueryString and Form data are notpreserved.If one's target page requires parameters, one can define them using theParametersdictionaryproperty.Onesimplyspecifies either literalvaluesor object navigation expressions for such parameter values; if one specifies anexpression,thisexpressionwillbeevaluatedinthecontextofthepageinwhichthe result is being referenced... in the specific caseof the above example, thismeans that any page that uses thehomePageResult needs to expose aUserInfopropertyonthepageclassitself.

Note

InSpring1.1.0andbeforetheprefixusedtoindicateanobjectnavigationexpressionintheParametersdictionarypropertywasthedollarsign,i.e.${UserInfo.FullName}.Thisconflictedwiththeprefixusedtoperformpropertyreplacement,thedollarsign,asdescribedinthesectionPropertyPlaceholderConfigurer.AsaworkaroundyoucanchangetheprefixandsuffixusedinPropertyPlaceholderConfigurertobedifferent,forexampleprefix=$${andsuffix=}.InSpring1.1.1anewprefixcharacter,thepercentsign(i.e.%{UserInfo.FullName}.)canbeusedintheParametersdictionarytoavoidthisconflictsoyoucankeepthefamiliarNAntstylePropertyPlaceholderConfigurerdefaults.

Parameters will be handled differently depending on the result mode. For

Page 584: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

redirect results, every parameter will be converted to a string, then URLencoded, and finally appended to a redirect query string. On the other hand,parametersfortransferresultswillbeaddedtotheHttpContext.Itemscollection before the request is transferred to the target page.Thismeans thattransfers are more flexible because any object can be passed as a parameterbetweenpages.Theyarealsomoreefficientbecausetheydon'trequirearound-triptotheclientandbacktotheserver,sotransfermodeisrecommendedasthepreferredresultmode(itisalsothecurrentdefault).

Tip

Ifyoushouldneedtocustomizehowtoaredirectrequestisgenerate,forexampletoencrypttherequestparameters,subclasstheRequestobjectandoverrideoneormoreprotectedmethods,forexamplestringBuildUrl(stringresolvedPath,

IDictionaryresolvedParameters).SeetheAPIdocumentationforadditionalinformation.

The above example shows independent result object definitions, which areusefulforglobalresultssuchasahome-andlogin-page.Resultdefinitionsthatareonlygoingtobeusedbyonepageshouldbesimplyembeddedwithinthe definition of a page, either as inner object definitions or using a specialshortcutnotationfordefiningaresultdefinition:

<objecttype="~/UI/Forms/UserRegistration.aspx"parent="basePage"

<propertyname="UserManager">

<refobject="userManager"/>

</property>

<propertyname="Results">

<dictionary>

<entrykey="userSaved"value="redirect:UserRegistered.aspx?status=RegistrationSuccessful,user=${UserInfo}"

<entrykey="cancel"value-ref="homePageResult"/>

</dictionary>

</property>

</object>

Theshortnotationfortheresultmustadheretothefollowingformat...

[<mode>:]<targetPage>[?param1,param2,...,paramN]

Page 585: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

There are three possible values for themode value referred to in the abovenotationsnippet;theyare:

redirect

transfer

TransferNoPreserveThey correspond to the values of the ResultMode enumeration. One thing tonoticeisthatacommaisusedinsteadofanampersandtoseparateparameters;thisisdonesoastoavoidtheneedforlaboriousampersandescapingwithinanXMLobjectdefinition.Theuseoftheampersandcharacter isstillsupportedifrequired, but one will then have to specify it using the well known& entityreference.Onceonehasdefinedone'sresults,itisverysimpletousethemwithintheeventhandlersofone'spages(UserRegistration.apsx.cs)...

privatevoidSaveUser(objectsender,EventArgse)

{

UserManager.SaveUser(UserInfo);

SetResult("userSaved");

}

publicvoidCancel(objectsender,EventArgse)

{

SetResult("cancel");

}

protectedoverridevoidOnInit(EventArgse)

{

InitializeComponent();

this.saveButton.Click+=newEventHandler(this.SaveUser);

this.cancelButton.Click+=newEventHandler(this.Cancel);

base.OnInit(e);

}

One could of course further refactor the above example and use definedconstants.Thiswouldbeagoodthingtodointhecaseofalogicalresultnamesuchas"home"thatislikelytobereferencedbymanypages.

Page 586: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.9.1.RegisteringuserdefinedtransfermodesYoumayalso registeracustominterpreter thatcanparse theshort-handstringrepresentation that creates a Result object.. The string representation can bebrokendownintotwopartsshownbelow

<resultmode>:<textualresultrepresentation>

The interface IResultFactory is responsible for creating an IResultobjectfromthesetwopieces,asshownbelow

publicinterfaceIResultFactory

{

IResultCreateResult(stringresultMode,stringresultText);

}

AResultFactoryRegistry is used to associate a given resultmodestringwithanIResultFactoryimplementation.Hereisanexample

classMySpecialResultLogic:IResult

{

...

}

classMySpecialResultLogicFactory:IResultFactory

{

IResultCreate(stringmode,stringexpression){

/*...convert'expression'intoMySpecialResultLogic*/

}

}

//registerwithglobalfactory

ResultFactoryRegistry.RegisterResultFactory("mySpecialMode",newMySpecialResultLogicFactory);

Youwouldthenusethecustom'continue'modeinyourpageasshownbelow

//configureyourResults

<objecttype="mypage.aspx">

<propertyname="Results">

<dictionary>

Page 587: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<entrykey="continue"value="mySpecialMode:<someMySpecialResultLogicstringrepresentation>"/>

</dictionary>

</property>

</object>

The result redirection is done as before, by callingmyPage.SetResult("continue");

Page 588: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.10.Client-SideScriptingASP.NET has decent support for client-side scripting through the use of thePage.RegisterClientScriptBlock andPage.RegisterStartupScriptmethods.However,neitherofthesetwomethodsallowsyoutooutputaregisteredscriptmarkupwithina<head>sectionofapage,whichis(inmanycases)exactlywhatyouwouldliketodo.

22.10.1.RegisteringScriptswithintheheadHTMLsectionSpring.Web adds several methods to enhance client-side scripting to the baseSpring.Web.UI.Page class: RegisterHeadScriptBlockandRegisterHeadScriptFile, eachwith a few overrides.You cancall these methods from your custom pages and controls in order to registerscriptblocksandscript files thatmustbe included in the<head> sectionofthefinalHTMLpage.Theonlyadditionalthingthatisrequiredtomakethisworkisthatyouusethe<spring:Head> server-side control to define your <head> sectioninsteadofusingthestandardHTML<head>element.Thisisshownbelow.

<%@Pagelanguage="c#"Codebehind="StandardTemplate.aspx.cs"

AutoEventWireup="false"Inherits="SpringAir.Web.StandardTemplate"

<%@RegisterTagPrefix="spring"Namespace="Spring.Web.UI.Controls"

<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.0Transitional//EN"

<html>

<spring:Headrunat="server"id="Head1">

<title>

<spring:ContentPlaceHolderid="title"runat="server">

<%=GetMessage("default.title")%>

</spring:ContentPlaceHolder>

</title>

<LINKhref="<%=CssRoot%>/default.css"type="text/css"

<spring:ContentPlaceHolderid="head"runat="server"></spring:ContentPlaceHolder>

</spring:Head>

<body>

...

</body>

</html>

Page 589: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The example above shows you how you would typically set-up a<head>sectionwithinamasterpagetemplateinordertobeabletochangethetitlevalueand to add additional elements to the<head> section from the child pagesusing<spring:ContentPlaceholder>controls.However,onlythe<spring:Head> declaration is required in order for Spring.NETRegister*scriptstoworkproperly.

22.10.2.AddingCSSDefinitionstotheheadSectionInasimilarfashion,youcanaddreferencestoCSSfiles,orevenspecificstyles,directly to the<head> HTML section usingPage.RegisterStyleandPage.RegisterStyleFilemethods.ThelatteronesimplyallowsyoutoincludeareferencetoanexternalCSSfile,whiletheformeroneallowsyou to define embedded style definitions by specifying the style name anddefinitionastheparameters.ThefinallistofstyledefinitionsregisteredthiswaywillberenderedwithinthesingleembeddedstylesectionofthefinalHTMLdocument.

22.10.3.Well-KnownDirectoriesIn order to make the manual inclusion of client-side scripts, CSS files andimageseasier,theSpring.WebPageclassexposesseveralpropertiesthathelpyou referencesuchartifactsusingabsolutepaths.This affordswebapplicationdevelopers a great deal of convenience functionality straight out of the box ifthey stick to common conventions such as a web application (directory)structure..These properties are ScriptsRoot, CssRoot and ImagesRoot.TheyhavedefaultvaluesofScripts,CSSandImages,whichwillworkjust fine if you create and use these directories in your web application root.However,ifyouprefertoplacethemsomewhereelse,youcanalwaysoverridedefault values by injecting new values into your page definitions (you willtypically inject these values only in the base page definition, as they arenormally shared by all the pages in the application). An example of suchconfigurationisshownbelow:

<objectname="basePage"abstract="true">

Page 590: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<description>

Conveniencebasepagedefinitionforallthepages.

Pagesthatreferencethisdefinitionastheirparent(seetheexamplesbelow)

willautomaticallyinheritthefollowingproperties....

</description>

<propertyname="CssRoot"value="Web/CSS"/>

<propertyname="ImagesRoot"value="Web/Images"/>

</object>

Page 591: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

22.11.SpringUserControlsSpring provides several custom user controls that are located in theSpring.Web.UI.Controlsnamespace.Thissectionprimarilyliststhecontrols and points to other documentation to provide additional information.Thereareafewothercontrolsnotdocumentedhere,pleasechecktheSDKdocsfortheirdescriptions.

22.11.1.ValidationControlsThelocationinthewebpagewherevalidationerrorsaretoberenderedcanbespecifies by using the ValidationSummary andValidationError controls. There are two controls since they havedifferent defaults for how errors are rendered.ValidationSummary isused to display potentially multiple errors identified by the validationframework.ValidationError is used to display field-level validationerrors.PleaserefertothesectionASP.NETusagetipsinthechapterontheValidationFrameworkmoreinformation.

22.11.2.DatabindingControlsSome standard controls are not easy to usewith Spring's databinding support.Examplesarecheckboxesandratiobuttongroups.InthiscaseyoushouldusetheCheckBoxList andRadioButtonGroup controls. Databindingitself can be done using the DataBindingPanel instead of the using theBindingManagerAPIwithinthecodebehindpage.

22.11.3.CalendarControlApop-upDHTMLcalendarcontrolisprovided.ItisaslightlymodifiedversionoftheDynarch.comDHTMLCalendarcontrolwrittenbyMihaiBazon.

22.11.4.PanelControlYou can suppress dependency injection for controls inside your ASP.NET byusing thePanel control.See the sectionCustomizing control dependency injection formoreinformation.

Page 592: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter23.ASP.NETAJAX

Page 593: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

23.1.IntroductionSpring'sASP.NETAJAX integration allows for a plain .NET object (PONO),thatisonethatdoesn'thaveanyattributesorspecialbaseclasses,tobeexportedasaweb service, configuredviadependency injection, 'decorated'byapplyingAOP,andthenexposedtoclientsideJavaScript.

Page 594: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

23.2.WebServicesSpring.NET, and particularly Spring.Web, improved support for web services in.NET with theWebServiceExporter. Exporting of an ordinary plain.NETobjectasawebserviceisachievedbyregisteringacustomimplementationof theWebServiceHandlerFactory class as the HTTP handler for*.asmxrequests.Microsoft ASP.NET AJAX introduced a new HTTP handlerSystem.Web.Script.Services.ScriptHandlerFactory

toallowaWebServicetobeinvokedfromthebrowserbyusingJavaScript.Spring's integration allows for both Spring.Web and ASP.NET AJAXfunctionalitytobeusedtogetherbycreatinganewHTTPhandler.

23.2.1.ExposingWebServicesThe WebServiceExporter combined with the new HTTP handlerexposesPONOsasWebServicesinyourASP.NETAJAXapplication.In order for a Web service to be accessed from script, theWebServiceExporter should decorate theWebService classwith theScriptServiceAttribute.Thecodebelowistakenfromthesampleapplication Spring.Web.Extensions.Sample, aka the 'AJAX' shortcut in theinstallation.:

<objectid="ContactWebService"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

<propertyname="TargetName"value="ContactService"/>

<propertyname="Namespace"value="http://Spring.Examples.Atlas/ContactService"

<propertyname="Description"value="ContactWebServices"/>

<propertyname="TypeAttributes">

<list>

<objecttype="System.Web.Script.Services.ScriptServiceAttribute,System.Web.Extensions"

</list>

</property>

</object>

AllthatoneneedstodoinordertousetheWebServiceExporteris:

Page 595: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

1. Configure the Web.config file of your ASP.NET AJAX application as aSpring.Webapplication.

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.WebContextHandler,Spring.Web"

</sectionGroup>

<spring>

<context>

<resourceuri="~/Spring.config"/>

</context>

</spring>

2. Register the HTTP handler and the Spring HttpModule under thesystem.websection.

<httpHandlers>

<removeverb="*"path="*.asmx"/>

<addverb="*"path="*.asmx"validate="false"type="Spring.Web.Script.Services.ScriptHandlerFactory,Spring.Web.Extensions"

<addverb="*"path="*_AppService.axd"validate="false"type

<addverb="GET,HEAD"path="ScriptResource.axd"type="System.Web.Handlers.ScriptResourceHandler,System.Web.Extensions,Version=1.0.61025.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35"

</httpHandlers>

<httpModules>

<addname="ScriptModule"type="System.Web.Handlers.ScriptModule,System.Web.Extensions,Version=1.0.61025.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35"

<addname="SpringModule"type="Spring.Context.Support.WebSupportModule,Spring.Web"

</httpModules>

3. Register the HTTP handler and the Spring HttpModule undersystem.webServersection.

<modules>

<addname="ScriptModule"preCondition="integratedMode"type

<addname="SpringModule"type="Spring.Context.Support.WebSupportModule,Spring.Web"

Page 596: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</modules>

<handlers>

<removename="WebServiceHandlerFactory-Integrated"/>

<addname="ScriptHandlerFactory"verb="*"path="*.asmx"preCondition

type="Spring.Web.Script.Services.ScriptHandlerFactory,Spring.Web.Extensions"

<addname="ScriptHandlerFactoryAppServices"verb="*"path=

type="System.Web.Script.Services.ScriptHandlerFactory,System.Web.Extensions,Version=1.0.61025.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35"

<addname="ScriptResource"preCondition="integratedMode"verb

</handlers>

You can find a full Web.config file in the example that comes with thisintegration.

23.2.2.CallingWebServicesbyusingJavaScriptAproxyclassisgeneratedforeachWebService.CallstoWebServicesmethodsare made by using this proxy class. When using theWebServiceExporter, the name of the proxy class is equal to theWebServiceExporter'sid.

//ThisfunctioncallstheContactWebservicemethod

//passingsimpletypeparametersandthecallbackfunction

functionGetEmails(prefix,count)

{

ContactWebService.GetEmails(prefix,count,GetEmailsOnSucceeded);

}

Page 597: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PartIV.ServicesThis part of the reference documentation covers the Spring Framework'sintegration with .NET distributed technologies such as .NET Remoting,Enterprise Services, Web Services. Integration with WCF Services isforthcoming.Pleaserefertotheintroductionchapterformoredetails.

Chapter24,IntroductiontoSpringServices

Chapter25,.NETRemoting

Chapter26,.NETEnterpriseServices

Chapter27,WebServices

Chapter28,WindowsCommunicationFoundation(WCF)

Page 598: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter24.IntroductiontoSpringServices

Page 599: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

24.1.IntroductionThegoalofSpring's integrationwithdistributed technologies is to adapt plain.NET objects so they can be usedwith a specific distributed technology. Thisintegrationisdesignedtobeasnon-intrusiveaspossible.Ifyouneedtoexposean object to a remote process then you can define an exporter for that object.Similarly,ontheclientsideyoudefineancorrespondingendpointaccessor.Ofcourse, the object's methods still need to be suitable for remoting, i.e. coarsegrained,toavoidmakingunnecessaryandexpensiveremotecalls.SincetheseexportersandclientsideendpointaccessorsaredefinedusingmetadataforSpringIoCcontainer,youcaneasilyusedependencyinjectiononthemtosetinitialstateandto'wireup'thepresentationtier,suchaswebforms,totheservice layer. In addition, youmay applyAOPaspects to the exported classesand/or service endpoints to apply behavior such as logging, security, or othercustombehaviorthatmaynotbeprovidedbythetargetdistributedtechnology.TheSpringspecificterminologyforthisapproachtoobjectdistributionisknownasPortableServiceAbstractions (PSA).As a result of this approach, you candecidemuch later in thedevelopmentprocess the technicaldetailsofhowyouwilldistributeyourobjectsascomparedto traditionalcodecentricapproaches.Changing of the implementation is done though configuration of the IoCcontainerandnotby recompilation.Ofcourse,youmaychoose tonotuse theIoCcontainertomanagetheseobjectsandusetheexporterandserviceendpointsprogramatically.Thediagramshownbelowisausefulwaytodemonstratethekeyabstractionsinthe Spring tool chest and their interrelationships. The four key concepts are;plain .NET objects, Dependency Injection, AOP, and Portable ServiceAbstractions.Attheheartsitstheplain.NETobjectthatcanbeinstantiatedandconfiguredusingdependencyinjection.Then,optionally,theplainobjectcanbeadapted toa specificdistributed technology.Lastly, additionalbehavior canbeappliedtoobjects.Thisbehavioristypicallythatwhichcannotbeeasilyaddressby traditionalOOapproaches such as inheritance. In the caseof service layer,common requirements such as 'the service layer must be transactional' areimplementedinamannerthatnaturallyexpressesthatintentioninasingleplace,ascomparedtoscatteredcodeacrosstheservicelayer.

Page 600: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Springimplementsthisexporterfunctionalitybycreatingaproxyatruntimethatmeets the implementation requirementsof a specificdistributed technology. Inthe case of .NET Remoting the proxy will inherit from MarshalByRef, forEnterpriseServices it will inherit from ServicedComponent and for aspx webservices, WebMethod attributes will be added to methods. Client sidefunctionality is often implemented by a thin layer over the client accessmechanismoftheunderlyingdistributedtechnology,thoughinsomecasessuchasclientsideaccesstowebservices,youhavetheoptiontocreateaproxyonthefly from the .wsdl definition, much like you would have done using thecommandlinetools.The common implementation theme for you as a provider of these serviceobjectsistoimplementaninterface.Thisisgenerallyconsideredabestpracticeinitsownright,youwillseemostpureWCFexamplesfollowingthispractice,and also lends itself to a straightforward approach to unit testing businessfunctionality as stub or mock implementations may be defined for testingpurposes.The assembly Spring.Services.dll contains support for .NET

Remoting,EnterpriseServices andASMXWeb Services. Support forWCF services isplannedforSpring1.2andiscurrentlyintheCVSrepositoryifyoucaretotakeanearlylook.

Page 601: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter25..NETRemoting

Page 602: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.1.IntroductionSpring's.NETRemotingsupportallowsyoutoexporta'plain.NETobject'asa.NET Remoted object. By "plain .NET object" we mean classes that do notinheritfromaspecificinfrastructurebaseclasssuchasMarshalByRefObject.Onthe server side, Spring's .NETRemoting exporters will automatically create aproxy that implementsMarshalByRefObject.You registerSAO types as eitherSingleCall or Singleton and also configure on a per-object basis lifetime andleasingparameters.OntheclientsideyoucanobtainCAOreferencestoserverproxy objects in amanner that promotes interface based design best practiceswhen developing .NET remoting applications. The current implementationrequires that your plain .NET objects implements a business service interface.AdditionallyyoucanaddAOPadvicetobothSAOandCAOobjects.You can leverage the IoC container to configure the exporter and serviceendpoints.Aremotingspecificxml-schemaisprovidedtosimplifytheremotingconfiguration but you can still use the standard reflection-like property basedconfiguration schema. You may also opt to not use the IoC container toconfigure theobjectsanduseSpring's .NETRemotingclassesProgramatically,asyouwouldwithanythirdpartylibrary.A sample application, often referred to in this documentation, is in thedistribution under the directory "examples\Spring\Spring.Calculator" and mayalsobefoundviathestartmenubyselectingthe'Calculator'item.

Page 603: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.2.PublishingSAOsontheServerExposingaSingletonSAOservicecanbedoneintwoways.Thefirstisthroughprogrammatic or administrative type registration that makes calls toRemotingConfiguration.RegisterWellKnownServiceType

Thismethodhasthelimitationthatyoumustuseadefaultconstructorandyoucan not easily configure the singleton state at runtime since it is created ondemand. The second way is to publish an object instance usingRemotingServices.Marshal. This method overcomes thelimitationsofthefirstmethod.ExampleserversidecodeforpublishinganSAOsingletonobjectwithapredefinedstateisshownbelow

AdvancedMBRCalculatorcalc=newAdvancedMBRCalculator(217);

RemotingServices.Marshal(calc,"MyRemotedCalculator");

The class AdvancedMBRCalculator used above inherits fromMarshalByRefObject.If your design calls for configuring a singleton SAO, or using a non-defaultconstructor, you can use theSpring IoC container to create theSAO instance,configure it, and register it with the .NET remoting infrastructure. TheSaoExporter class performs this task and most importantly, willautomaticallycreateaproxyclassthatinheritsfromMarshalbyRefObjectifyourbusiness object does not already do so. The following XML taken from theRemotingQuickStartdemonstratesitsusagetoanSAOSingletonobject

25.2.1.SAOSingleton

<objectid="singletonCalculator"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

<constructor-argtype="int"value="217"/>

</object>

<!--RegistersthecalculatorserviceasaSAOin'Singleton'mode.-->

<objectname="saoSingletonCalculator"type="Spring.Remoting.SaoExporter,Spring.Services"

<propertyname="TargetName"value="singletonCalculator"/>

<propertyname="ServiceName"value="RemotedSaoSingletonCalculator"

</object>

ThisXMLfragmentshowshowanexistingobject"singletonCalculator"defined

Page 604: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

in the Spring context is exposed under the url-path name"RemotedSaoSingletonCalculator". (The fully qualified url istcp://localhost:8005/RemotedSaoSingleCallCalculator using the standard .NETchannel configuration shown further below.) AdvancedCalculatorclass implements the business interfaceIAdvancedCalculator. Thecurrentproxyimplementationrequires thatyourbusinessobjects implementaninterface. The interfaces' methods will be the ones exposed in the generated.NETremotingproxy.Theinitialmemoryofthecalculatorissetto217viatheconstructor. The class AdvancedCalculator does not inherit fromMarshalByRefObject.Also note that the exporter sets the lifetime oftheSAOSingletontoinfinitesothatthesingletonwillnotbegarbagecollectedafter 5 minutes (the .NET default lease time). If you would like to vary thelifetime properties, they are InitialLeaseTime, RenewOnCallTime, andSponsorshipTimeout.A custom schema is provided to make the object declaration even easier andwithintellisensesupportfortheattributes.Thisisshownbelow

<objectsxmlns="http://www.springframework.net"

xmlns:r="http://www.springframework.net/remoting">

<r:saoExportertargetName="singletonCalculator"

serviceName="RemotedSaoSingletonCalculator"

...otherobjectdefinitions

</objects>

RefertotheendofthischapterformoreinformationonSpring's .NETcustomschema.

25.2.2.SAOSingleCallThe following XML fragment shows how to expose the calculator service inSAO'SingleCall'mode.

<objectid="prototypeCalculator"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

singleton="false">

<constructor-argtype="int"value="217"/>

</object>

Page 605: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectname="saoSingleCallCalculator"type="Spring.Remoting.SaoExporter,Spring.Services"

<propertyname="TargetName"value="prototypeCalculator"/>

<propertyname="ServiceName"value="RemotedSaoSingleCallCalculator"

</object>

Note that we change the singleton attribute of the plain .NET object asconfigured by Spring in the <object> definition and not an attribute on theSaoExporter.TheobjectreferredtointheTargetNameparametercanbeanAOPproxytoabusinessobject.Forexample,ifweweretoapplysomesimplelogging advice to the singleton calculator, the following standard AOPconfigurationisusedtocreatethetargetfortheSaoExporter

<objectid="singletonCalculatorWeaved"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="target"ref="singletonCalculator"/>

<propertyname="interceptorNames">

<list>

<value>Log4NetLoggingAroundAdvice</value>

</list>

</property>

</object>

<objectname="saoSingletonCalculatorWeaved"type="Spring.Remoting.SaoExporter,Spring.Services"

<propertyname="TargetName"value="singletonCalculatorWeaved"

<propertyname="ServiceName"value="RemotedSaoSingletonCalculatorWeaved"

</object>

NoteAsgenerallyrequiredwitha.NETRemotingapplication,theargumentstoyourservicemethodsshouldbeSerializable.

25.2.1.ConsoleApplicationConfigurationWhen using SaoExporter you can still use the standard remotingadministration section in the application configuration file to register thechannel.ChannelServicesasshownbelow

<system.runtime.remoting>

Page 606: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<application>

<channels>

<channelref="tcp"port="8005"/>

</channels>

</application>

</system.runtime.remoting>

Aconsoleapplication thatwillhost thisRemotedobjectneeds to initialize the.NETRemoting infrastructurewith a call toRemotingConfiguration (sinceweare using the .config file for channel registration) and then start the Springapplicationcontext.Thisisshownbelow

RemotingConfiguration.Configure("RemoteApp.exe.config");

IApplicationContextctx=ContextRegistry.GetContext();

Console.Out.WriteLine("Serverlistening...");

Console.ReadLine();

You can also put in the configuration file an instance of the objectSpring.Remoting.RemotingConfigurer to make theRemotingConfigurationcallshowaboveonyourbehalfduring initializationofthe IoC container. The RemotingConfigurer implements theIObjectFactoryPostProcessor interface,which gets called afterall object definitionshavebeen loadedbut before they have been instantiated,(SeeSection5.9.2,“CustomizingconfigurationmetadatawithObjectFactoryPostProcessors”formore information). The RemotingConfigurer has two properties you canconfigure.Filename, thatspecifies thefilenameto load the .NETremotingconfiguration from (if null the default file name is used) andEnsureSecuritywhichmakes sure the channel in encrypted (availableonlyon .NET2.0).Asaconvenience, thecustomSpringremotingschemacanbe used to define an instance of this class as shown below, taken from theRemotingQuickStart

<objectsxmlns="http://www.springframework.net"

xmlns:r="http://www.springframework.net/remoting">

Page 607: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<r:configurerfilename="Spring.Calculator.RemoteApp.exe.config"

</objects>

TheReadLinepreventstheconsoleapplicationfromexiting.YoucanrefertothecodeinRemoteAppintheRemotingQuickStarttoseethiscodeinaction.

25.2.3.IISApplicationConfigurationIf you are deploying a .NET remoting application inside IIS there is a sampleprojectthatdemonstratesthenecessaryconfigurationusingSpring.Web.Spring.Web ensures the application context is initialized, but if you don't useSpring.Web the idea is to start the initialization of the Spring IoC containerinsidetheapplicationstartmethoddefinedinGlobal.asax,asshownbelow

voidApplication_Start(objectsender,EventArgse)

{

//Codethatrunsonapplicationstartup

//EnsureSpringhasloadedconfigurationregisteringcontext

Spring.Context.IApplicationContextctx=newSpring.Context.Support.XmlApplicationContext(

HttpContext.Current.Server.MapPath(

Spring.Context.Support.ContextRegistry.RegisterContext(ctx);

}

In this example, the Spring configuration file is named Spring.Config. InsideWeb.config you add a standard <system.runtime.remoting> section. Note thatyoudonotneedtospecifytheportnumberofyourchannelsastheywillusetheportnumberofyourwebsite.Ambiguousresultshavebeenreportedifyoudospecifytheportnumber.Also,inorderforIIStorecognizetheremotingrequest,you should add the suffix '.rem' or '.soap' to the target nameof your exportedremoteobjectsothatthecorrectIIShandlercanbeinvoked.

Page 608: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.3.AccessingaSAOontheClientAdministrative type registration on the client side lets you easily obtain areferencetoaSAOobject.Whenatypeisregisteredontheclient,usingthenewoperator or using the reflection API will return a proxy to the remote objectinsteadofa localreference.Administrativetyperegistrationon theclient foraSAO object is performed using the wellknown element in the clientconfiguration section. However, this approach requires that you expose theimplementationof the class on the client side. Practically speaking thiswouldmean linking in the server assembly to the client application, a generallyrecognizedbadpractice.Thisdependencycanberemovedbydevelopingremoteservicesbasedonabusinessinterface.Asidefromremotingconsiderations,theseparationof interfaceand implementation isconsideredagoodpracticewhendesigningOOsystems.Inthecontextofremoting,thismeansthattheclientcanobtainaproxytoaspecificimplementationwithonlyareferencetotheinterfaceassembly.To achieve the decoupling of client and server, a separate assemblycontainingtheinterfacedefinitionsiscreatedandsharedbetweentheclientandserverapplications.There isa simplemeans for following thisdesignwhen the remoteobject isaSAO object. A call toActivator.GetObject will instantiate a SAOproxy on the client. For CAO objects another mechanism is used and isdiscussedlater.ThecodetoobtaintheSAOproxyisshownbelow

ICalculatorcalc=(ICalculator)Activator.GetObject(

typeof(ICalculator),

"tcp://localhost:8005/MyRemotedCalculator");

ToobtainareferencetoaSAOproxywithintheIoCcontainer,youcanusetheobject factorySaoFactoryObject in theSpring configuration file.ThefollowingXMLtakenfromtheRemotingQuickStartdemonstratesitsusage.

<objectid="calculatorService"type="Spring.Remoting.SaoFactoryObject,Spring.Services"

<propertyname="ServiceInterface"value="Spring.Calculator.Interfaces.IAdvancedCalculator,Spring.Calculator.Contract"

<propertyname="ServiceUrl"value="tcp://localhost:8005/RemotedSaoSingletonCalculator"

</object>

The ServiceInterface property specifies the type of proxy to create while the

Page 609: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ServiceUrlpropertycreatesaproxyboundtothespecifiedserverandpublishedobjectname.Other objects in the IoC container that depend on an implementation of theinterfaceICalculator can now refer to the object "calculatorService",thereby using a remote implementation of this interface. The exposure ofdependenciesamongobjectswithintheIoCcontainerletsyoueasilyswitchtheimplementationofICalculator.ByusingtheIoCcontainerchangingtheapplicationtousealocalinsteadofremoteimplementationisaconfigurationfilechange,notacodechange.Bypromotinginterfacebasedprograming,theabilitytoswitchimplementationmakesiteasiertounittesttheclientapplication,sinceunittestingcanbedonewithamockimplementationoftheinterface.Similarly,developmentoftheclientcanproceedindependentoftheserverimplementation.This increases productivity when there are separate client and serverdevelopment teams. The two teams agree on interfaces before startingdevelopment. The client team can quickly create a simple, but functionalimplementation and then integrate with the server implementation when it isready.

Page 610: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.4.CAObestpracticesCreatingaclientactivatedobject(CAO)istypicallydonebyadministrativetyperegistration, either Programatically or via the standard .NET remotingconfiguration section. The registration process allows you to use the 'new'operatortocreatetheremoteobjectandrequiresthattheimplementationoftheobjectbedistributed to theclient.Asmentionedbefore, this isnot adesirableapproach to developing distributed systems. The best practice approach thatavoids thisproblem is tocreate anSAObased factoryclasson the server thatwill returnCAO references to the client. In amanner similar to howSpring'sgenericobjectfactorycanbeusedasareplacementcreatingafactoryperclass,wecancreateagenericSAOobjectfactorytoreturnCAOreferencestoobjectsdefined in Spring's application context. This functionality is encapsulated inSpring'sCaoExporterclass.OntheclientsideareferenceisobtainedusingCaoFactoryObject. The client side factory object supports creation oftheCAOobjectusingconstructorarguments.Inadditiontoreducingtheclutterandtediumaroundcreatingfactoryclassesspecifictoeachobjecttypeyouwishtoexposeinthismanner,thisapproachhastheadditionalbenefitofnotrequiringany type registration on the client or server side. This is because the act ofreturninganinstanceofaclassthatinheritsfromMarshalByRefObjectacrossaremoting boundary automatically returns a CAO object reference. For moreinformationon thisbest-practice, refer to the last section,Section 25.8, “AdditionalResources”,forsomelinkstoadditionalresources.

Page 611: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.5.RegisteringaCAOobjectontheServerToexposeanobjectasaCAOontheserveryoushoulddeclareanobjectinthestandardSpringconfigurationthatisa'prototype',thatisthesingletonpropertyissettofalse.ThisresultsinanewobjectbeingcreatedeachtimeitisretrievedfromSpring'sIoCcontainer.AnimplementationofICaoRemoteFactoryiswhatisexportedviaacalltoRemotingServices.Marshal.ThisimplementationusesSpring'sIoCcontainertocreateobjectsandthendynamicallycreatea.NETremoting proxy for the retrieved object. Note that the default lifetime of theremote object is set to infinite (null is returned from the implementation ofInitializeLifetimeService()).ThisisbestshownusinganexamplefromtheRemotingQuickstartapplication.Hereisthedefinitionofasimplecalculatorobject,

<objectid="prototypeCalculator"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

singleton="false">

<constructor-argtype="int"value="217"/>

</object>

To export this as a CAO object we can declare theCaoExporter objectdirectlyintheserver'sXMLconfigurationfile,asshownbelow

<objectid="caoCalculator"type="Spring.Remoting.CaoExporter,Spring.Services"

<propertyname="TargetName"value="prototypeCalculator"/>

<propertyname="Infinite"value="false"/>

<propertyname="InitialLeaseTime"value="2m"/>

<propertyname="RenewOnCallTime"value="1m"/>

</object>

Notetheproperty'TargetName'issettothename,notthereference,ofthenon-singletondeclarationofthe'AdvancedCalculator'class.Alternatively,youcanusetheremotingschemaanddeclaretheCAOobjectasshownbelow

<r:caoExportertargetName="prototypeCalculator"infinite="false"

<r:lifeTimeinitialLeaseTime="2m"renewOnCallTime="1m"/>

</r:caoExporter>

Page 612: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.5.1.ApplyingAOPadvicetoexportedCAOobjectsApplying AOP advice to exported CAO objects is done by referencing theadvicedobjectname to theCAOexporter.Again, takinganexample from theRemoting QuickStart, a calculator with logging around advice is defined asshownbelow.

<objectid="prototypeCalculatorWeaved"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="targetSource">

<objecttype="Spring.Aop.Target.PrototypeTargetSource,Spring.Aop"

<propertyname="TargetObjectName"value="prototypeCalculator"

</object>

</property>

<propertyname="interceptorNames">

<list>

<value>ConsoleLoggingAroundAdvice</value>

</list>

</property>

</object>

If thisdeclaration isunfamiliar toyou,please refer toChapter13,AspectOrientedProgramming with Spring.NET for more information. The CAO exporter thenreferenceswiththename'prototypeCalculatorWeaved'asshownbelow.

<r:caoExportertargetName="prototypeCalculatorWeaved"infinite

<r:lifeTimeinitialLeaseTime="2m"renewOnCallTime="1m"/>

</r:caoExporter>

Page 613: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.6.AccessingaCAOontheClientOn the client side a CAO reference is obtained by using theCaoFactoryObjectasshownbelow

<objectid="calculatorService"type="Spring.Remoting.CaoFactoryObject,Spring.Services"

<propertyname="RemoteTargetName"value="prototypeCalculator"

<propertyname="ServiceUrl"value="tcp://localhost:8005"/>

</object>

Thisdefinitioncorrespondstotheexportedcalculatorfromtheprevioussection.Theproperty'RemoteTargetName'identifiestheobjectontheserverside.UsingthisapproachtheclientcanobtainanreferencethoughstandardDItechniquestoa remoteobject that implements theIAdvancedCalculator interface.(Asalways,thatdoesn'tmeantheclientshouldtreattheobjectasifitwasanin-processobject).Alternatively, you canuse theRemoting schema to shorten this definition andprovideintellisensecodecompletion

<r:caoFactoryid="calculatorService"

remoteTargetName="prototypeCalculator"

serviceUrl="tcp://localhost:8005"/>

25.6.1.ApplyingAOPadvicetoclientsideCAOobjects.ApplyingAOP advice to a client sideCAOobject is done just like anyotherobject.SimplyusetheidoftheobjectcreatedbytheCaoFactoryObjectastheAOPtarget,i.e.'calculatorService'inthepreviousexample.

Page 614: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.7.XMLSchemaforconfigurationPlease install theXSD schemas intoVS.NET as described inChapter 32,VisualStudio.NET Integration. XML intellisense for the attributes of the saoExporter,caoExporter and caoFactory should be self explanatory as they mimic thestandardpropertynamesusedtoconfigure.NETremoteobjects.

Page 615: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

25.8.AdditionalResourcesTwo articles that describe the process of creating a standard SAO factory forreturningCAOobjectsareImplementingBrokerwith.NETRemotingUsingClient-ActivatedObjectsonMSDNandStepbyStepguidetoCAOcreationthroughSAOclassfactoriesonGlacialComponentswebsite.

Page 616: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter26..NETEnterpriseServices

Page 617: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

26.1.IntroductionSpring's .NETEnterprise Services support allows you to export a 'plain .NETobject'asa.NETRemotedobject.By"plain.NETobject"wemeanclassesthatdo not inherit from a specific infrastructure base class such asServicedComponent..You can leverage the IoC container to configure the exporter and serviceendpoints.YoumayalsoopttonotusetheIoCcontainertoconfiguretheobjectsanduseSpring's.NETEnterpriseServicesclassesProgramatically,asyouwouldwithanythirdpartylibrary.

Page 618: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

26.2.ServicedComponentsServicescomponentsin.NETareabletouseCOM+servicessuchasdeclarativeand distributed transactions, role based security, object poolingmessaging. Toaccess these services your class needs to derive from the classSystem.EnterpriseServices.ServicedComponent,adornyour class and assemblies with relevant attributes, and configure yourapplication by registering your serviced components with the COM+ catalog.TheoveralllandscapeofaccessingandusingCOM+serviceswithin.NETgoesbythename.NETEnterpriseServices.Many of these services can be provided without the need to derive from aServicedComponent though the use of Spring'sAspect-Oriented Programmingfunctionality.Nevertheless,youmaybe interested inexportingyour class as aserviced component and having client access that component in a locationtransparent manner. By using Spring'sServicedComponentExporter,EnterpriseServicesExporter andServicedComponentFactory you can easily create and consumeserviced components without having your class inherit fromServicedComponentandautomatethemanualdeploymentprocessthatinvolvesstronglysigningyourassemblyandusingtheregsvcsutility.Note that the following sections do not delve into the details of programming.NET Enterprise Services. An excellent reference for such information isChristianNagel's "EnterpriseServiceswith the .NETFramework"Spring.NETincludes an example of using these classes, the 'calculator' example. Moreinformationcanbefoundinthesection,.NETEnterpriseServicesexample.

Page 619: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

26.3.ServerSideOneofthemainchallengesfortheexportingofaservicedcomponenttothehostis the need for them to be contained within a physical assembly on the filesysteminordertoberegisteredwiththeCOM+Services.Tomakethingsmorecomplicated, this assembly has to be strongly named before it can besuccessfullyregistered.Springprovidestwoclassesthatallowallofthistohappen.

Spring.Enterprise.ServicedComponentExporter

isresponsibleforexportingasinglecomponentandmakingsurethatitderivesfromServicedComponentclass.Italsoallowsyouto specify class-level and method-level attributes for thecomponent in order to define things such as transactionalbehavior,queuing,etc.Spring.Enterprise.EnterpriseServicesExporter

correspondstoaCOM+application,anditallowsyoutospecifylistofcomponents that shouldbe included in theapplication,aswellastheapplicationnameandotherassembly-levelattributes

Let'ssaythatwehaveasimpleserviceinterfaceandimplementationclass,suchasthese:

namespaceMyApp.Services

{

publicinterfaceIUserManager

{

UserGetUser(intuserId);

voidSaveUser(Useruser);

}

publicclassSimpleUserManager:IUserManager

{

privateIUserDaouserDao;

publicIUserDaoUserDao

{

get{returnuserDao;}

set{userDao=value;}

}

Page 620: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicUserGetUser(intuserId)

{

returnUserDao.FindUser(userId);

}

publicvoidSaveUser(Useruser)

{

if(user.IsValid)

{

UserDao.SaveUser(user);

}

}

}

}

Andthecorrespondingobjectdefinitionfor it in theapplicationcontextconfigfile:

<objectid="userManager"type="MyApp.Services.SimpleUserManager"

<propertyname="UserDao"ref="userDao"/>

</object>

Let'ssay thatwewant toexposeusermanagerasaservicedcomponentsowecan leverage its support for transactions. First we need to export our serviceusingtheexporterServicedComponentExporterasshownbelow

<objectid="MyApp.EnterpriseServices.UserManager"type="Spring.Enterprise.ServicedComponentExporter,Spring.Services"

<propertyname="TargetName"value="userManager"/>

<propertyname="TypeAttributes">

<list>

<objecttype="System.EnterpriseServices.TransactionAttribute,System.EnterpriseServices"

</list>

</property>

<propertyname="MemberAttributes">

<dictionary>

<entrykey="*">

<list>

<objecttype="System.EnterpriseServices.AutoCompleteAttribute,System.EnterpriseServices"

</list>

</entry>

Page 621: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</dictionary>

</property>

</object>

The exporter defined above will create a composition proxy for ourSimpleUserManager class that extends ServicedComponent anddelegatesmethod calls to SimpleUserManager instance. It will also adorn theproxy class with a TransactionAtribute and all methods with anAutoCompleteAttribute.ThenextthingweneedtodoisconfigureanexporterfortheCOM+applicationthatwillhostournewcomponent:

<objectid="MyComponentExporter"type="Spring.Enterprise.EnterpriseServicesExporter,Spring.Services"

<propertyname="ApplicationName"value="MyCOM+Application"

<propertyname="Description"value="Myenterpriseservicesapplication."

<propertyname="AccessControl">

<objecttype="System.EnterpriseServices.ApplicationAccessControlAttribute,System.EnterpriseServices"

<propertyname="AccessChecksLevel"value="ApplicationComponent"

</object>

</property>

<propertyname="Roles">

<list>

<value>Admin:Administratorrole</value>

<value>User:Userrole</value>

<value>Manager:Administratorrole</value>

</list>

</property>

<propertyname="Components">

<list>

<refobject="MyApp.EnterpriseServices.UserManager"

</list>

</property>

<propertyname="Assembly"value="MyComPlusApp"/>

</object>

Thisexporterwillputallproxyclassesforthespecifiedlistofcomponentsintothe specified assembly, sign the assembly, and register it with the specifiedCOM+ application name. If application does not exist it will create it andconfigure it using values specified for Description, AccessControl and Rolesproperties.

Page 622: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

26.4.ClientSideBecause servicedcomponentclassesaredynamicallygeneratedand registered,you cannot instantiate them inyour codeusing thenewoperator. Instead, youneed to useSpring.Enterprise.ServicedComponentFactory

definition,which also allowsyou to specify the configuration template for thecomponentaswellas thenameof theremoteserver thecomponent is runningon,ifnecessary.Anexampleisshownbelow

<objectid="enterpriseUserManager"type="Spring.Enterprise.ServicedComponentFactory,Spring.Services"

<propertyname="Name"value="MyApp.EnterpriseServices.UserManager"

<propertyname="Template"value="userManager"/>

</object>

YoucantheninjectthisinstanceoftheIUserManagerintoaclientclassanduseitjustlikeyouwoulduseoriginalSimpleUserManagerimplementation.Asyoucan see, by coding your services as plain .Net objects, against well definedservice interfaces, you gain easy pluggability for your service implementationthoughthisconfiguration,whilekeepingthecorebusinesslogicinatechnologyagnosticPONO,i.e.PlainOrdinary.NetObject.

Page 623: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter27.WebServices

Page 624: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

27.1.IntroductionWhiletheout-of-the-boxsupportforwebservicesin.NETisexcellent,therearea fewareas that theSpring.NET thoughtcoulduse some improvement.Springaddstheabilitytoperformdependencyinjectiononstandardasmxwebservices.Spring's .NETWeb Services support also allows you to export a 'plain .NETobject'asa .NETwebserviceBy"plain.NETobject"wemeanclassesthatdonotcontaininfrastructurespecificattributes,suchasWebMethod.Ontheserverside,Spring's.NETwebserviceexporterswillautomaticallycreateaproxythataddswebserviceattributes.OntheclientsideyoucanuseSpringIoCcontainertoconfigureaclientsideproxythatyougeneratedwithstandardcommandlinetools.Additionally,Springprovides the functionality to create theweb serviceproxydynamicallyatruntime(muchlikerunningthecommandlinetoolsbutatruntimeandwithoutsomeof thetoolsquirks)andusedependency injection toconfiguretheresultingproxyclass.Onboththeserverandclientside,youcanapplyAOPadvicetoaddbehaviorsuchaslogging,exceptionhandling,etc.thatisnoteasilyencapsulatedwithinaninheritancehierarchyacrosstheapplication.

Page 625: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

27.2.Server-sideOnethingthattheSpring.NETteamdidn'tlikemuchisthatwehadtohaveallthese.asmxfileslyingaroundwhenallsaidfilesdidwasspecifywhichclasstoinstantiatetohandlewebservicerequests.Second,theSpring.NETteamalsowantedtobeabletousetheSpring.NETIoCcontainertoinjectdependenciesintoourwebserviceinstances.Typically,awebservicewillrelyonotherobjects,serviceobjectsforexample,sobeingable toconfigurewhichserviceobjectimplementationtouseisveryuseful.Last,butnotleast,theSpring.NETteamdidnotlikethefactthatcreatingawebservice is an implementation task. Most (although not all) services are bestimplemented as normal classes that use coarse-grained service interfaces, andthe decision as towhether a particular service should be exposed as a remoteobject,webservice,orevenanenterprise(COM+)component,shouldonlybeamatterofconfiguration,andnotimplementation.Anexampleusingthewebserviceexportercanbefoundinquickstartexamplenamed'calculator'.Moreinformationcanbefoundhere'WebServicesexample'.

27.2.1.Removingtheneedfor.asmxfilesUnlikewebpages,whichuse.aspxfilestostorepresentationcode,andcode-behindclassesforthelogic,webservicesarecompletelyimplementedwithinthecode-behindclass.Thismeans that .asmxfilesservenousefulpurpose,andassuchtheyshouldneitherbenecessarynorindeedrequiredatall.Spring.NETallowsapplicationdeveloperstoexposeexistingwebserviceseasilyby registering a custom implementation of theWebServiceHandlerFactory class and by creating a standardSpring.NETobjectdefinitionfortheservice.Bywayofanexample,considerthefollowingwebservice...

namespaceMyComany.MyApp.Services

{

[WebService(Namespace="http://myCompany/services")]

publicclassHelloWorldService

{

[WebMethod]

publicstringHelloWorld()

Page 626: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

{

return"HelloWorld!";

}

}

}

ThisisjustastandardclassthathasmethodsdecoratedwiththeWebMethodattribute and (at the class-level) the WebService attribute. Applicationdeveloperscancreate thiswebservicewithinVisualStudio just likeanyotherclass.Allthatoneneedtodoinordertopublishthiswebserviceis:1. Register theSpring.Web.Services.WebServiceFactoryHandler astheHTTPhandlerfor*.asmxrequestswithinone'sweb.configfile.

<system.web>

<httpHandlers>

<addverb="*"path="*.asmx"type="Spring.Web.Services.WebServiceHandlerFactory,Spring.Web"

</httpHandlers>

</system.web>

Ofcourse,onecanregisteranyotherextensionaswell,buttypicallythereisnoneedasSpring.NET'shandlerfactorywillbehaveexactlythesameasastandardhandler factory if saidhandler factorycannot find theobjectdefinition for thespecifiedservicename.Inthatcasethehandlerfactorywillsimplylookforan.asmxfile.IfyouareusingIIS7thefollowingconfigurationisneeded

<system.webServer>

<validationvalidateIntegratedModeConfiguration="false"/>

<handlers>

<addname="SpringWebServiceSupport"verb="*"path="*.asmx"

</handlers>

</system.webServer>

2.Createanobjectdefinitionforone'swebservice.

Page 627: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectname="HelloWorld"type="MyComany.MyApp.Services.HelloWorldService,MyAssembly"

Note that one is not absolutely required to make the web service objectdefinitionabstract(viatheabstract="true"attribute),butthisisarecommendedbestpracticeinordertoavoidcreatinganunnecessaryinstanceof the service. Because the .NET infrastructure creates instances of the targetserviceobjectinternallyforeachrequest,allSpring.NETneedstoprovideistheSystem.Typeof theserviceclass,whichcanbe retrieved from theobjectdefinitionevenifitismarkedasabstract.That'sprettymuchitaswecanaccessthiswebserviceusingthevaluespecifiedforthenameattributeoftheobjectdefinitionastheservicename:

http://localhost/MyWebApp/HelloWorld.asmx

27.2.2.InjectingdependenciesintowebservicesForargumentssake,let'ssaythatwewanttochangetheimplementationoftheHelloWorldmethodtomakethereturnedmessageconfigurable.Oneway todo itwouldbe tousesomekindofmessage locator to retrieveanappropriate message, but that locator needs to implemented. Also, it wouldcertainlybe anoddarchitecture thatuseddependency injection throughout theapplicationtoconfigureobjects,butthatresortedtotheservicelocatorapproachwhendealingwithwebservices.Ideally,oneshouldbeabletodefineapropertyforthemessagewithinone'swebserviceclassandhaveSpring.NETinjectthemessagevalueintoit:

namespaceMyApp.Services

{

publicinterfaceIHelloWorld

{

stringHelloWorld();

}

[WebService(Namespace="http://myCompany/services")]

publicclassHelloWorldService:IHelloWorld

{

privatestringmessage;

Page 628: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicstringMessage

{

set{message=value;}

}

[WebMethod]

publicstringHelloWorld()

{

returnthis.message;

}

}

}

TheproblemwithstandardSpring.NETDIusageinthiscaseisthatSpring.NETdoesnotcontrol the instantiationof thewebservice.Thishappensdeep in theinternals of the .NET framework, thusmaking it quite difficult to plug in thecodethatwillperformtheconfiguration.The solution is to create a dynamic server-side proxy that will wrap the webservice and configure it. Thatway, the .NET framework gets a reference to aproxy type from Spring.NET and instantiates it. The proxy then asks aSpring.NET application context for the actual web service instance that willprocessrequests.This proxying requires that one export the web service explicitly using theSpring.Web.Services.WebServiceExporter class; in thespecific case of this example, one must also not forget to configure theMessagepropertyforsaidservice:

<objectid="HelloWorld"type="MyApp.Services.HelloWorldService,MyApp"

<propertyname="Message"value="Hello,World!"/>

</object>

<objectid="HelloWorldExporter"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

<propertyname="TargetName"value="HelloWorld"/>

</object>

TheWebServiceExportercopiestheexistingwebserviceandmethodattributevaluestotheproxyimplementation(ifindeedanyaredefined).Please

Page 629: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

notehoweverthatexistingvaluescanbeoverriddenbysettingpropertiesontheWebServiceExporter.

InterfaceRequirements

Inordertosupportsomeadvancedusagescenarios,suchastheabilitytoexposeanAOPproxyasawebservice(allowingtheadditionofAOPadvicestowebservicemethods),Spring.NETrequiresthoseobjectsthatneedtobeexportedaswebservicestoimplementa(service)interface.OnlymethodsthatbelongtoaninterfacewillbeexportedbytheWebServiceExporter.

27.2.3.ExposingPONOsasWebServicesNowthatwearegeneratingaserver-sideproxyfortheservice,thereisreallynoneed for it to have all the attributes that web services need to have, such asWebMethod.Because .NET infrastructure code never really sees the "real"service, those attributes are redundant as the proxy needs to have them on itsmethods,becausethat'swhat.NETdealswith,buttheyarenotnecessaryonthetargetservice'smethods.ThismeansthatwecansafelyremovetheWebServiceandWebMethodattributedeclarationsfromtheserviceimplementation,andwhatweareleftwithis a plain old .NET object (a PONO). The example above would still work,becausetheproxygeneratorwillautomaticallyaddWebMethodattributestoallmethodsoftheexportedinterfaces.However,thatisstillnottheidealsolution.YouwouldloseinformationthattheoptionalWebServiceandWebMethodattributesprovide,suchasservicenamespace,description,transactionmode,etc.Onewaytokeepthosevaluesistoleavethemwithintheserviceclassandtheproxygeneratorwillsimplycopythem to the proxy class instead of creating empty ones, but that really doesdefeatthepurpose.To add specific attributes to the exported web service, you can set all thenecessaryvalueswithinthedefinitionoftheserviceexporter,likeso...

<objectid="HelloWorldExporter"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

<propertyname="TargetName"value="HelloWorld"/>

<propertyname="Namespace"value="http://myCompany/services"

Page 630: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<propertyname="Description"value="MyexportedHelloWorldwebservice"

<propertyname="MemberAttributes">

<dictionary>

<entrykey="HelloWorld">

<objecttype="System.Web.Services.WebMethodAttribute,System.Web.Services"

<propertyname="Description"value="MySpring-configuredHelloWorldmethod."

<propertyname="MessageName"value="ZdravoSvete"

</object>

</entry>

</dictionary>

</property>

</object>

//or,onceconfigurationimprovementsareimplemented...

<web:servicetargetName="HelloWorld"namespace="http://myCompany/services"

<description>MyexportedHelloWorldwebservice.</description>

<methods>

<methodname="HelloWorld"messageName="ZdravoSvete">

<description>MySpring-configuredHelloWorldmethod.

</method>

</methods>

</web:service>

Basedontheconfigurationabove,Spring.NETwillgenerateawebserviceproxyfor all the interfaces implemented by a target and add attributes as necessary.This accomplishes the same goalwhile at the same timemovingweb servicemetadata from implementation class to configuration, which allows one toexportprettymuchanyclassasawebservice.TheWebServiceExporter also has aTypeAttributes IList property forapplyingattributesatthetypelevel.

Note

TheattributetoconfirmstotheWSIbasicprofile1.1isnotaddedbydefault.Thiswillbeaddedinafuturerelease.InthemeantimeusetheTypeAttributesIListpropertytoadd[WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]

tothegeneratedproxy.

Onecan also export only certain interfaces that a service class implements bysettingtheInterfacespropertyoftheWebServiceExporter.

Page 631: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

DistributedObjectsWarning

DistributedObjectsWarningJustbecauseyoucanexportanyobjectasawebservice,doesn'tmeanthatyoushould.DistributedcomputingprinciplesstillapplyandyouneedtomakesurethatyourservicesarenotchattyandthatargumentsandreturnvaluesareSerializable.Youstillneedtoexercisecommonsensewhendecidingwhethertousewebservices(orremotingingeneral)atall,oriflocalserviceobjectsareallyouneed.

27.2.4.ExportinganAOPProxyasaWebServiceIt is often useful to be able to export an AOP proxy as a web service. Forexample, consider the casewhere you have a service that iswrappedwith anAOPproxythatyouwanttoaccessbothlocallyandremotely(asawebservice).ThelocalclientwouldsimplyobtainareferencetoanAOPproxydirectly,butanyremoteclientneedstoobtainareferencetoanexportedwebserviceproxy,that delegates calls to an AOP proxy, that in turn delegates them to a targetobjectwhileapplyinganyconfiguredAOPadvice.Effectingthissetupisactuallyfairlystraightforward;becauseanAOPproxyisan object just like any other object, all you need to do is set theWebServiceExporter'sTargetNamepropertytotheid(orindeedthename oralias) of theAOP proxy. The following code snippets showhowtodothis...

<objectid="DebugAdvice"type="MyApp.AOP.DebugAdvice,MyApp"

<objectid="TimerAdvice"type="MyApp.AOP.TimerAdvice,MyApp"

<objectid="MyService"type="MyApp.Services.MyService,MyApp"

<objectid="MyServiceProxy"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="TargetName"value="MyService"/>

<propertyname="IsSingleton"value="true"/>

<propertyname="InterceptorNames">

<list>

<value>DebugAdvice</value>

<value>TimerAdvice</value>

Page 632: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</list>

</property>

</object>

<objectid="MyServiceExporter"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

<propertyname="TargetName"value="MyServiceProxy"/>

<propertyname="Name"value="MyService"/>

<propertyname="Namespace"value="http://myApp/webservices"

<propertyname="Description"value="Mywebservice"/>

</object>

That's it as every call to the methods of the exported web service will beintercepted by the target AOP proxy, which in turnwill apply the configureddebuggingandtimingadvicetoit.

Page 633: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

27.3.Client-sideOn the client side, themain objection the Spring.NET team has is that clientcodebecomes tied toaproxyclass,andnot toaservice interface.Unless youmaketheproxyclassimplementtheserviceinterfacemanually,asdescribedbyJuval Lowy in his book "Programming .NET Components", application codewill be less flexible and it becomes very difficult to plug in different serviceimplementation in thecasewhenonedecides touseanewand improvedwebserviceimplementationoralocalserviceinsteadofawebservice.ThegoalforSpring.NET'swebservicessupportistoenabletheeasygenerationofclient-sideproxiesthatimplementaspecificserviceinterface.

27.3.1.UsingVS.NETgeneratedproxyTheproblemwiththeweb-serviceproxyclassesthataregeneratedbyVS.NETor the WSDL command line utility is that they don't implement a serviceinterface. This tightly couples client code with web services and makes itimpossible tochangethe implementationata laterdatewithoutmodifyingandrecompilingtheclient.Spring.NETprovidesasimpleIFactoryObjectimplementationthatwillgenerate a "proxy for proxy" (however obtuse thatmay sound). Basically, theSpring.Web.Services.WebServiceProxyFactory classwillcreateaproxyfortheVS.NET-/WSDL-generatedproxythatimplementsaspecifiedserviceinterface(thussolvingtheproblemwiththeweb-serviceproxyclassesmentionedintheprecedingparagraph).At this point, an examplemaywell bemore illustrative in conveyingwhat ishappening;considerthefollowinginterfacedefinitionthatwewishtoexposeasawebservice...

namespaceMyCompany.Services

{

publicinterfaceIHelloWorld

{

stringHelloWorld();

}

}

Page 634: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

In order to be able to reference aweb service endpoint through this interface,youneedtoaddadefinitionsimilartotheexampleshownbelowtoyourclient'sapplicationcontext:

<objectid="HelloWorld"type="Spring.Web.Services.WebServiceProxyFactory,Spring.Services"

<propertyname="ProxyType"value="MyCompany.WebServices.HelloWorld,MyClientApp"

<propertyname="ServiceInterface"value="MyCompany.Services.IHelloWorld,MyServices"

</object>

What is important tonotice is that theunderlying implementationclass for theweb service does not have to implement the sameIHelloWorld serviceinterface...solongasmatchingmethodswithcompliantsignaturesexist(akindofducktyping),Spring.NETwillbeabletocreateaproxyanddelegatemethodcalls appropriately. If a matching method cannot be found, the Spring.NETinfrastructurecodewillthrowanexception.Thatsaid,ifyoucontrolboththeclientandtheserveritisprobablyagoodideatomake sure that the web service class on the server implements the serviceinterface, especially if you plan on exporting it using Spring.NET'sWebServiceExporter,whichrequiresaninterfaceinordertowork.

27.3.2.GeneratingproxiesdynamicallyTheWebServiceProxyFactorycanalsodynamicallygenerateaweb-serviceproxy.TheXMLobjectdefinitionforthisfactoryobjectisshownbelow

<objectid="calculatorService"type="Spring.Web.Services.WebServiceProxyFactory,Spring.Services"

<propertyname="ServiceUri"value="http://myServer/Calculator/calculatorService.asmx"

<!--<propertyname="ServiceUri"value="file://~/calculatorService.wsdl"/>-->

<propertyname="ServiceInterface"value="Spring.Calculator.Interfaces.IAdvancedCalculator,Spring.Calculator.Contract"

<!--DependencyinjectiononFactory'sproduct:theproxyinstanceoftypeSoapHttpClientProtocol-->

<propertyname="ProductTemplate">

<object>

<propertyname="Timeout"value="10000"/><!--10s-->

</object>

</property>

</object>

Page 635: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Oneuse-casewhere this proxy is veryuseful iswhendealingwith typed datasetsthroughawebservice.Leavingtheprosandconsofthisapproachaside,thecurrentbehaviorof theproxygenerator in .NET is tocreatewrapper types forthetypeddataset.Thisnotonlypollutesthesolutionwithextraneousclassesbutalso results inmultiplewrapper typesbeing created, one for eachweb servicethatusesthetypeddataset.Thiscanquicklygetconfusing.TheproxycreatedbySpringallowsyou to referenceyou typeddatasetsdirectly, avoiding theabovementionedissues.

27.3.3.ConfiguringtheproxyinstanceThe WebServiceProxyFactory also implements the interface,Spring.Objects.Factory.IConfigurableFactoryObject

allowing to specify configuration for the product that theWebServiceProxyFactory creates. This is done by specifying theProductTemplate property. This is particularly useful for securing the webservice.Anexampleisshownbelow.

<objectid="PublicarAltasWebService"type="Spring.Web.Services.WebServiceProxyFactory,Spring.Services"

<propertyname="ProxyType"value="My.WebService"/>

<propertyname="ServiceInterface"value="My.IWebServiceInterface"

<propertyname="ProductTemplate">

<object>

<!--ConfigurethewebserviceURL-->

<propertyname="Url"value="https://localhost/MyApp/webservice.jws"

<!--ConfiguretheUsernameandpasswordforthewebservice-->

<propertyname="Credentials">

<objecttype="System.Net.NetworkCredential,System"

<propertyname="UserName"value="user"/>

<propertyname="Password"value="password"/>

</object>

</property>

<!--Configureclientcertificateforthewebservice-->

<propertyname="ClientCertificates">

<list>

<objectid="MyCertificate"type="System.Security.Cryptography.X509Certificates.X509Certificate2,System"

<constructor-argname="fileName"value="Certificate.p12"

<constructor-argname="password"value="notgoingtotellyou"

</object>

</list>

Page 636: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</property>

</object>

</property>

</object>

For an example of how using SOAP headers for authentication using theWebServiceExporter andWebServiceProxyFactory, refer to this solution on ourwiki.

Page 637: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter28.WindowsCommunicationFoundation(WCF)

Page 638: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

28.1.IntroductionSpring's WCF support allows you to configure your WCF services viadependencyinjectionandaddadditionalbehaviortothemusingAspect-Orientedprogramming(AOP).For those who would like to get their feet wet right way, check out theWcfQuickStartapplicationintheexamplesdirectory.

Page 639: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

28.2.ConfiguringWCFservicesviaDependencyInjectionThe technical approach used to perform dependency injection is based ondynamically creating an implementation of your service interface (a dynamicproxy)thatretrievesaconfiguredinstanceofyourservicetypefromtheSpringcontainer.Thisdynamicproxyisthenthefinalservicetypethatishosted.

Note

AnalternativeimplementationapproachthatusesextensibilitypointsinWCFtodelegatetoSpringtocreateandconfigureyourWCFservicewastriedbutprovedtobelimitedinitsrangeofapproachwasfirsttaken(afaik)byOranDennisononhisblogandseveralotherfolksonthewebsincethen.Theissueinusingthisapproachisthatiftheserviceisconfiguredtobeasingleton,for[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]

thentheinvocationoftheIInstanceProviderisshort-circuited.SeethenotesontheMSDNclassdocumentationhere.Whilethiswouldbethepreferredapproach,noacceptableworkaround

28.2.1.DependencyInjectionInthisapproachyoudevelopyourWCFservicesasyouwouldnormallydo.Forexamplehereisasampleservicetypetakenfromthequickstartexample.

[ServiceContract(Namespace="http://Spring.WcfQuickStart"

publicinterfaceICalculator

{

[OperationContract]

doubleAdd(doublen1,doublen2);

[OperationContract]

doubleSubtract(doublen1,doublen2);

[OperationContract]

doubleMultiply(doublen1,doublen2);

[OperationContract]

doubleDivide(doublen1,doublen2);

[OperationContract]

stringGetName();

}

Theimplementationforthemethodsisfairlyobviousbutanadditionalproperty,SleepInSeconds, is present. This is the propertywewill configure viadependencyinjection.Hereisapartiallistingoftheimplementation

Page 640: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicclassCalculatorService:ICalculator

{

privateintsleepInSeconds;

publicintSleepInSeconds

{

get{returnsleepInSeconds;}

set{sleepInSeconds=value;}

}

publicdoubleAdd(doublen1,doublen2)

{

Thread.Sleep(sleepInSeconds*1000);

returnn1+n2;

}

//additionalimplementationnotshownforbrevity

}

Toconfigure thisobjectwithSpring,provide theXMLconfigurationmetadataasshownbelowasyouwouldwithanySpringmanagedobject.

<objectid="calculator"singleton="false"type="Spring.WcfQuickStart.CalculatorService,Spring.WcfQuickStart.ServerApp"

<propertyname="SleepInSeconds"value="1"/>

</object>

Note

Theobjectmustbedeclaredasa'prototype'object,i.e.notasingleton,inordertointeractcorrectlywithWCFinstancing.

To host this service type in a standalone application define an instance of aSpring.ServiceModel.Activation.ServiceHostFactoryObject

and set is propertyTargetName to the id value of the previously definedservice type. ServiceHostFactoryObject is a SpringIFactoryObject implementation. (See here for more information onIFactoryObjects and their interaction with the container.) The

Page 641: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ServiceHostFactoryObject will create an instance ofSpring.ServiceModel.Activation.SpringServiceHost

thatwill be the ServiceHost instance associated with your service type. Thisconfigurationforthisstepisshownbelow.

<objectid="calculatorServiceHost"type="Spring.ServiceModel.Activation.ServiceHostFactoryObject,Spring.Services"

<propertyname="TargetName"value="calculator"/>

</object>

Additional service configuration can be done declaratively in the standardApp.configfileasshownbelow

<system.serviceModel>

<services>

<servicename="calculator"behaviorConfiguration="DefaultBehavior"

<host>...</host>

<endpoint>...</endpoint>

</service>

...

</services>

</system.serviceModel>

Note

ItisimportantthatthenameoftheserviceintheWCFdeclarativeconfigurationsectionmatchthenameoftheSpringobjectdefinition

Spring.ServiceModel.Activation.SpringServiceHost

iswhere the dynamic proxy for your service type is generated. This dynamicproxywill implement a single 'WCF' interface, the same on that your servicetype implements. The implementation of the service interfacemethods on theproxy will delegate to a wrapped 'target' object which is the object instanceretrieved by name from the Spring container using the Spring API,ApplicationContext.GetObject(name). Since the objectretrievedinthismannerisfullyconfigured,yourWCFserviceisaswell.Outside of a standalone application you can also use the classSpring.ServiceModel.Activation.ServiceHostFactory

(which inherits from

Page 642: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

System.ServiceModel.Activation.ServiceHostFactory

tohostyourservicessothattheycanbeconfiguredviadependencyinjection.Touse thedynamicproxyapproacheddescribedhereyou should still refer to thenameof the service as thenameof theobject definitionused toconfigure theservicetypeintheSpringcontainer.TherearenotmanydisadvantagestothisapproachotherthantheneedtospecifytheservicenameasthenameoftheobjectdefinitionintheSpringcontainerandtoensure thatsingleton=false isusedin theobjectdefinition.YoucanalsouseSpring.ServiceModel.Activation.ServiceHostFactory

tohostyourserviceinsideIISbutshouldstillrefertotheservicebythenameoftheobjectintheSpringcontainer.

Page 643: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

28.3.ApplyAOPadvicetoWCFservicesIneitherapproachtoperformingdependencyinjectionyoucanapplyadditionalAOPadvicetoyourWCFservicesinthesamewayasyouhavealwaysdoneinSpring. The following configuration shows how to apply some simpleperformance monitoring advice to all services in theSpring.WcfQuickStartnamespaceand is taken from theQuickStartexample.

<objectid="serviceOperation"type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut,Spring.Aop"

<propertyname="pattern"value="Spring.WcfQuickStart.*"

</object>

<objectid="perfAdvice"type="Spring.WcfQuickStart.SimplePerformanceInterceptor,Spring.WcfQuickStart.ServerApp"

<propertyname="Prefix"value="ServiceLayerPerformance"

</object>

<aop:config>

<aop:advisorpointcut-ref="serviceOperation"advice-ref

</aop:config>

The aop:config section implicitly uses Spring's autoproxying features to addadditional behavior to any objects defined in the container that match thepointcutcriteria.

Page 644: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

28.4.CreatingclientsideproxiesdeclarativelyTocreateaclientsideproxybasedon theuseofChannelFactory<T>,youcanusethisratherugly'boilerplate'XMLsnippitthattakesusesSpring'ssupportforcallingfactorymethodsonobjectinstances.

<!--returnsChannelFactory<ICalculator>("calculatorEndpoint").CreateChannel()-->

<objectid="serverAppCalculator"type="Spring.WcfQuickStart.ICalculator,Spring.WcfQuickStart.ClientApp"

factory-object="serverAppCalculatorChannelFactory"

factory-method="CreateChannel"/>

<objectid="serverAppCalculatorChannelFactory"

type="System.ServiceModel.ChannelFactory&lt;Spring.WcfQuickStart.ICalculator>,System.ServiceModel"

<constructor-argname="endpointConfigurationName"value=

</object>

Note

Thiswillbeshortenedusingacustomnamespceinafuturerelease

Thevalue'serverAppCalculatorEndpoint'referstothenameofanenpointsinthe<client>sectionofthestandardWCFconfigurationinsideofApp.config.

Page 645: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

28.5.ExportingPONOsasWCFServicesMuch like the approach taken for .asmx web services Spring provides anexporter that will add [ServiceContract] and[OperationContract] attributes by default to all public interfacemethods on a given (PONO) class. The exporter class isSpring.ServiceModel.ServiceExporter and has variousoptionstofine-tunewhatinterfacesareexportedandthespecificattributesthatgetappliedtoeachmethodandonthatclass.Hereisasimpleexample

<objectid="HelloWorldExporter"type="Spring.ServiceModel.ServiceExporter,Spring.Services"

<propertyname="TargetName"value="HelloWorld"/>

<propertyname="MemberAttributes">

<dictionary>

<entrykey="SayHelloWorld">

<objecttype="System.ServiceModel.OperationContractAttribute,System.ServiceModel"

<propertyname="IsOneWay"value="false"/>

<!--configureanyotherOperationContractAttributepropertieshere-->

</object>

</entry>

</dictionary>

</property>

</object>

Spring does not provide any means to add [DataContract] or[DataMember]attributestomethodargumentsofyourserviceoperations.Assuch,eitheryouwilldothatyourselforyoumaychoose touseaserializerother than DataContractSerializer, for example one that relies on methodarguments that implement the ISerializable interface, having the[Serializable] attribute,orareserializablevia theXmlSerializer.Usethe latter serializers is a good way to migrate from an existing RCP basedapproach,suchasusing .NETremoting, toWCFinorder to takeadvantageofthe WCF runtime and avoid editing much existing code. You can thenincrementally refactor and/or create new operations that useDataContractSerializer.

Page 646: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PartV.IntegrationThis part of the reference documentation covers the Spring Framework'sintegrationwithanumberofrelatedenterprise.NETtechnologies.

Chapter29,MessageOrientedMiddleware-ApacheActiveMQ

Chapter30,MessageOrientedMiddleware-MSMQ

Chapter31,SchedulingandThreadPooling

Page 647: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter 29. Message Oriented Middleware - ApacheActiveMQ

Page 648: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

29.1.IntroductionThegoalofSpring'smessagingistoincreaseyourproductiviitywhenwritinganenterprise strength messaging middleware applications. Spring achieves thesegoalsinseveralways.First itprovidesseveralhelperclasses that removefromthe developer the incidental complexity and resource management issues thatarisewhenusingmessagingAPIs.Second,thedesignofthesemessaginghelperclasses promote best practices in designing a messaging application bypromotinga clear separationbetween themessagingmiddleware specific codeandbusinessprocessingthatistechnologyagnostic.Thisisgenerallyreferredtoa"plainold.NETobject"(orPONO)programmingmodel.ThischapterdiscussesSpring'smessagingsupportforproviderswhoseAPIwasmodeledaftertheJavaMessageService(JMS)API.VendorswhoprovideaJMSinspiredAPI includeApache,TIBCO,IBM,andProgressSoftware. IfyouareusingMicrosoft'sMessageQueue,pleaserefertothespecificMSMQsection.Asthereisnodefacto-standardcommonAPIacrossmessagingvendors,Springprovidesanimplementationofitshelperclassesforeachofthemajormessagingmiddleware vendors. The naming of the classes you will interact with mostfrequentlywill either be identical for each provider, but located in a differentnamespace,orhavetheirprefixchangetobethethree-letter-acronymcommonlyassociatedwiththemessageprovider.ThelistofproviderssupportedbySpringisshowbelowalongwiththeirnamespaceandprefix.

1. Apache ActiveMQ (NMS) in namespaceSpring.Messaging.Nms. 'Nms' is sometimes used as the classprefix

2. TIBCO EMS in namespace Spring.Messaging.Ems. 'Ems' issometimesusedastheclassprefix(tobecommericallyavailable)

3. SonicMQ in namespace Spring.Messaging.Sonic, 'Jms' issometimesusedastheclassprefix.(tobecommerciallyavailable)

4. WebsphereMQ in namespaceSpring.Messaging.Xms, 'Xms' issometimesusedastheclassprefix(tobecommericallyavailable)

JMS can be roughly divided into two areas of functionality, namely theproduction and consumption of messages. For message production and thesynchronous consumption of messages the a template class, named

Page 649: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

NmsTemplate, EmsTemplate (etc.) is used. Asynchronous messageconsumption is performed though amulti-threadedmessage listener container,SimpleMessageListenerContainer. This message listenercontainer is used to createMessage-Driven PONOs (MDPs) which refer to amessagingcallbackclassthatconsistsofjust'plain.NETobject'sandisdevoidof any specific messaging types or other artifacts. TheIMessageConverterinterfaceisusedbyboththetemplateclassandthemessage listener container to convert between provider message types andPONOs.ThenamespaceSpring.Messaging.<Vendor>.Corecontainsthemessing template class (e.g.NmsTemplate).The template class simplifiestheuseofthemessagingAPIsbyhandlingthecreationandreleaseofresources,much like theAdoTemplatedoes forADO.NET.The JMS inspiredAPIsare low-level API, much like ADO.NET. As such, even the simplest ofoperations requires 10s of lines of code with the bulk of that code related toresourcemanagementof intermediateAPI objects Spring'smessaging support,both in Javaand .NET, addresses the error-proneboilerplate coding styleoneneedswhenusingtheseAPIs.The design principle common to Spring template classes is to provide helpermethods to perform common operations and for more sophisticated usage,delegate the essence of the processing task to user implemented callbackinterfaces. The messaging template follows the same design. The messagetemplateclassoffervariousconveniencemethodsfor thesendingofmessages,consuming a message synchronously, and exposing the message Session andMessageProducertotheuser.The namespace Spring.Messaging.

<VendorAcronym>.Support.Converter provides aIMessageConverter abstraction to convert between .NET objects andmessages. The namespace Spring.Messaging.

<VendorAcronym>.Support.Destinations provides variousstrategies for managing destinations, such as providing a service locater fordestinationsstoredinadirectoryservice.Finally, the namespace Spring.Messaging.

<VendorAcronym>.Connections provides an implementations of

Page 650: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

theConnectionFactorysuitableforuseinstandaloneapplications.Therestofthesectionsinthischapterdiscusseseachofthemajorhelperclassesin detail. Please refer to the sample application that ships with Spring foradditionalhands-onusage.

Note

TosimplifydocumentingfeaturesthatarecommonacrossallproviderimplementationsofSpring'shelperclassesaspecificprovider,ApacheActiveMQ,wasselected.Assuchwhenyousee'NmsTemplate'inthedocumentation,italsoreferstoEmsTemplate,XmsTemplate,etc.unlessspecificallydocumentedotherwise.TheproviderspecificAPIclassesaretypicallynamedaftertheirJMScounterpartswiththepossibleexceptionofaleading'I'infrontofinterfacesinordertofollow.NETnamingconventions.InthedocumentationtheseAPIartifactsarereferredtoas'ConnectionFactory','Session','Message',etc.withouttheleading'I'.

29.1.1.SeparationofConcernsThe use of MessageConverters and a PONO programming model promotemessagingbestpracticesbyapplyingtheprincipalofSeparationofConcerns tomessaging based architectures. The infrastructure concern of publishing andconsuming messages is separated from the concern of business processing.These two concerns are reflected in the architecture as two distinct layers, amessage processing layer and a business processing layer. The benefit of thisapproach is that your business processing is decoupled from the messagingtechnology,making it more likely to survive technological changes over timeand also easier to test. Spring's MessageConverters provides support formappingmessagingdatatypestoPONOs.Asidefrombeingthelinkbetweenthetwolayers,MessageConvertersprovideapluggablestrategytohelpsupporttheevolution of a loosely coupled architecture over time. Message formats willchange over time, typically by the addition of new fields.MessageConverterscan be implemented to detect different versions ofmessages and perform theappropriatemappinglogictoPONOssuchsothatmultipleversionsofamessagecanbesupportedsimultaneously,acommonrequirementinenterprisemessagingarchitectures.

29.1.2.Interoperabilityandproviderportability

Page 651: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

MessagingisatraditionalareaofInteroperabilityacrossheterogeneoussystemswith messaging vendors providing support on multiple operating systems(Windows,UNIX,MainframesOS's)aswellasmultiple languagebindings(C,C++,Java,.NET,Perl,etc.).In199xtheJavaCommunityProcesscameupwithaspecificationtoprovideacommonAPIacrossmessagingprovidersaswellasdefinesomecommonmessagingfunctionality.ThisspecificationisknowastheJavaMessageService.FromtheAPIperspective,itcanroughlybethoughtofasthe messaging counterpart to the ADO.NET or JDBC APIs that provideportabilityacrossdifferentdatabaseproviders.Giventhishistory,whenmessagingvendorscreatedtheir.NETAPIs,manydidso by creating their own JMS inspired API in .NET. There is no de facto-standard common API across messaging vendors. As such, portability acrossvendors using Spring's helper classes is done by changing the configurationschema in your configuration to a particular vendor and doing a 'search-and-replace'onthecodebase,changingthenamespaceandafewclassnames.Whilenotideal,usingSpringwillpushyouinthedirectionofisolatingthemessagingspecific classes in its own layer and therefore will reduce the impact of thechangesyoumaketothecodewhenswitchproviders.YoubusinesslogicclassescalledintoviaSpring'smessaginginfrastructurewillremainthesame.The NMS project from Apache addresses the lack of a common API across.NET messaging providers by providing an abstract interface based API formessaging and several implementations for different providers.At the time ofthis writing, the project is close to releasing a 1.0 version that supportsApacheMQ,MSMQ,andTIBCOEMS.Thereareafewoutstandingissuesatthemoment that prevent one using NMS as a common API for all messagingproviders but hopefully these issues will be resolved. Note, that NMS serves'double' duty as the preferredAPI formessagingwithActiveMQaswell as aprovidingportabilityacrossdifferentmessagingproviders.

29.1.3.TheroleofMessagingAPIina'WCFworld'Windows Communication Foundation (WCF) also supports message orientedmiddleware.Notsurprisingly,aMicrosoftMessageQueuing(MSMQ)bindingisprovidedaspartofWCF.TheWCFprogrammingmodelishigherlevelthanthetraditionalmessagingAPIssuchasJMSandNMSsinceyouareprogramingtoaservice interface and usemetadata (eitherXMLor attributes) to configure themessaging behavior. If you prefer to use this service-oriented, RPC style

Page 652: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

approach, then look to see if a vendor provides a WCF binding for yourmessagingprovider.NotethatevenwiththeoptionofusingWCF,manypeopleprefer to sit 'closer to themetal'whenusingmessagingmiddleware, to accessspecificfeaturesandfunctionalitynotavailableinWCF,orsimplybecausetheyaremorecomfortablewiththatprogrammingmodel.AWCFbindingforApacheNMSisbeingdevelopedasaseparateprojectundertheSpringExtensionsumbrellaproject.Staytunedfordetails.

Page 653: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

29.2.UsingSpringMessaging

29.2.1.MessagingTemplateoverviewCode that uses the messaging template classes (NmsTemplate,EmsTemplate,etc)onlyneedstoimplementcallbackinterfacesgivingthema clearly defined contract. The IMessageCreator callback interfacecreates a message given a Session provided by the calling code inNmsTemplate. In order to allow formore complex usage of the providermessagingAPI, thecallbackISessionCallbackprovidestheuserwiththe provider specific messaging Session and the callbackIProducerCallback exposes a provider specific Session andMessageProducerpair.ProvidermessagingAPIstypicallyexposetwotypesofsendmethods,one thattakes 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, thesettingoftheQOSparametershavebeenexposedaspropertiesonthetemplateclasstoavoidduplicationinthenumberofsendmethods.Similarly,thetimeoutvalue for synchronous receive calls is set using the propertyReceiveTimeout.

Note

InstancesoftheNmsTemplateclassarethread-safeonceconfigured.ThisisimportantbecauseitmeansthatyoucanconfigureasingleinstanceofaNmsTemplateandthensafelyinjectthissharedreferenceintomultiplecollaborators.Tobeclear,theNmsTemplateisstateful,inthatitmaintainsareferencetoaConnectionFactory,butthisstateisnotconversationalstate.

29.2.2.ConnectionsThe NmsTemplate requires a reference to a ConnectionFactory. TheConnectionFactory serves as the entry point for working with the provider'smessaging API. It is used by the client application as a factory to createconnections to the messaging server and encapsulates various configuration

Page 654: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

parameters, many of which are vendor specific such as SSL configurationoptions.

29.2.3.CachingMessagingResourcesThestandardAPIusageofNMSandotherJMSinspiredAPIsinvolvescreatingmany intermediate objects. To send a message the following 'API' walk isperformed

IConnectionFactory->IConnection->ISession->IMessageProducer->Send

Between the ConnectionFactory and the Send operation there are threeintermediate objects that are created and destroyed. To optimise the resourceusageandincreaseperformancetwoimplementationsofIConnectionFactoryareprovided.

29.2.3.1.SingleConnectionFactorySpring.Messaging.Nms.Connections.SingleConnectionFactory

willreturnthesameconnectiononallcallstoCreateConnectionandignorecallstoClose.

29.2.3.2.CachingConnectionFactorySpring.Messaging.Nms.Connections.CachingConnectionFactory

extends the functionality of SingleConnectionFactory and adds the caching ofSessions,MessageProducers,andMessageConsumers.Theinitialcachesizeissetto1,usethepropertySessionCacheSizetoincreasethenumberofcachedsessions.Note that thenumberofactualcachedsessionswill bemore than that number as sessions are cached based on theiracknowledgmentmode,so therecanbeup to4cachedsession instanceswhenSessionCacheSize is set to one, one for eachAcknowledgementMode.MessageProducers and MessageConsumers are cached withintheir owning session and also take into account the unique properties of theproducersandconsumerswhencaching.MessageProducers are cached based on their destination.MessageConsumers are cached based on a key composed of thedestination,selector,noLocaldeliveryflag,andthedurablesubscriptionname(if

Page 655: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

creatingdurableconsumers).

29.2.4.DestinationManagementInJavaimplementationsofJMS,ConnectionsandDestinationsare'administeredobjects'accessiblethoughJNDI-adirectoryservicemuchlikeActiveDirectory.In .NET each vendor has selected a different approach to destinationmanagement.SomeareJNDIinspired,allowingyoutoretrieveConnectionsandDestinations that were configured administratively. You can use these vendorspecificAPIstoperformdependencyinjectiononreferencestoJMSDestinationobjects in Spring's XML configuration file by creating am implementation ofIObjectFactory or alternatively configuring the specific concrete classimplementationforamessagingprovider.However, this approach of administered objects can be quite cumbersome ifthere are a large number of destinations in the application or if there areadvanced destination management features unique to the messaging provider.Examples of such advanced destinationmanagementwould be the creation ofdynamic destinations or support for a hierarchical namespace of destinations.The NmsTemplate delegates the resolution of a destination name to adestination object by delegating to an implementation of the interfaceIDestinationResolver. DynamicDestinationResolveris the default implementation used by NmsTemplate and accommodatesresolvingdynamicdestinations.Quiteoftenthedestinationsusedinamessagingapplicationareonlyknownatruntimeandthereforecannotbeadministrativelycreatedwhentheapplicationisdeployed. This is often because there is shared application logic betweeninteractingsystemcomponentsthatcreatedestinationsatruntimeaccordingtoawell-known naming convention. Even though the creation of dynamicdestinations are not part of the original JMS specification,most vendors haveprovided this functionality. Dynamic destinations are created with a namedefinedby theuserwhichdifferentiates them from temporarydestinations andareoftennotregistered inadirectoryservice.TheAPIused tocreatedynamicdestinationsvariesfromprovidertoprovidersincethepropertiesassociatedwiththe destination are vendor specific.However, a simple implementation choicethat is sometimesmade by vendors is to use theTopicSession methodCreateTopic(string topicName) or the QueueSession

Page 656: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

method CreateQueue(string queueName) to create a newdestination with default destination properties. Depending on the vendorimplementation, DynamicDestinationResolver may then alsocreateaphysicaldestinationinsteadofonlyresolvingone.The boolean property PubSubDomain is used to configure theNmsTemplatewith knowledge ofwhatmessaging 'domain' is beingused.Bydefault thevalueof thisproperty is false, indicating that thepoint-to-pointdomain,Queues,willbeused.Thispropertyisinfrequentlyusedastheprovidermessaging APIs are now largely agnostic as to which messaging 'domain' isused, referring to 'Destinations' rather than 'Queues' or 'Topics'. However, thisproperty does influence the behavior of dynamic destination resolution viaimplementationsoftheIDestinationResolverinterface.You can also configure the NmsTemplate with a default destination via thepropertyDefaultDestination. The default destination will be usedwithsendandreceiveoperationsthatdonotrefertoaspecificdestination.

29.2.5.MessageListenerContainersOne of the most common uses of JMS is to concurrently process messagesdelivered asynchronously. A message listener container is used to receivemessagesfromamessagequeueanddrivetheIMessageListenerthatisinjectedintoit.Thelistenercontainerisresponsibleforallthreadingofmessagereception and dispatches into the listener for processing. A message listenercontainer is the intermediarybetweenanMessage-DrivenPONO(MDP)andamessagingprovider,andtakescareofregisteringtoreceivemessages,resourceacquisitionand release,exceptionconversionandsuchlike.This allowsyouasan application developer to write the (possibly complex) business logicassociated with receiving a message (and possibly responding to it), anddelegatesboilerplatemessaginginfrastructureconcernstotheframework.A subclass ofAbstractMessageListenerContainer is used toreceivemessagesfromJMSanddrivetheMessage-DrivenPONOs(MDPs)thatare injected into it. There are one subclasses ofAbstractMessageListenerContainer packaged with Spring -SimpleMessageListenerContainer. Additional subclasses, inparticular toparticipate indistributed transactions (if the provider supports it),will be provided in future releases. SimpleMessageListenerContainer creates a

Page 657: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

fixednumberofJMSsessionsatstartupanduses themthroughout the lifespanofthecontainer.

29.2.6.TransactionManagementSpringprovidesaNmsTransactionManagerthatmanagestransactionsforasingleConnectionFactory.Thisallowsmessagingapplications to leveragethemanagedtransactionfeaturesofSpringasdescribedinChapter17,Transactionmanagement. The NmsTransactionManager performs local resourcetransactions, binding a Connection/Session pair from the specifiedConnectionFactory to the thread.NmsTemplateautomaticallydetectssuchtransactionalresourcesandoperatesonthemaccordingly.Using Spring's SingleConnectionFactory will result in a sharedConnection,witheachtransactionhavingitsownindependentSession.

Page 658: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

29.3.SendingaMessageTheNmsTemplatecontainsthreeconveniencemethodstosendamessage.Themethodsarelistedbelow.

void Send(IDestination destination,

IMessageCreatormessageCreator)

void Send(string destinationName,

IMessageCreatormessageCreator)

voidSend(IMessageCreatormessageCreator)

The method differ in how the destination is specified. In first case the JMSDestinationobjectisspecifieddirectly.Thesecondcasespecifiesthedestinationusing a string that is then resolved to a messagingDestination objectusing theIDestinationResolver associated with the template. Thelast method sends the message to the destination specified byNmsTemplate''sDefaultDestinationproperty.

AllmethodstakeasanargumentaninstanceofIMessageCreatorwhichdefines theAPI contract for you to create the JMSmessage. The interface isshowbelow

publicinterfaceIMessageCreator{

IMessageCreateMessage(ISessionsession);

}

Intermediate Sessions andMessageProducers needed to send themessage aremanagedbyNmsTemplate. The session passed in to themethod is nevernull.Thereisasimilarsetmethodsthatuseadelegateinsteadoftheinterface,whichcanbeconvenientwhenwritingsmallimplementationin.NET2.0usinganonymous delegates. Larger, more complex implementations of the method'CreateMessage'arebettersuitedtoaninterfacebasedimplementation.

void SendWithDelegate(IDestination

destination, MessageCreatorDelegate

messageCreatorDelegate)

void SendWithDelegate(string

Page 659: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

destinationName, MessageCreatorDelegate

messageCreatorDelegate)

voidSendWithDelegate(MessageCreatorDelegate

messageCreatorDelegate)

Thedeclarationofthedelegateis

publicdelegateIMessageMessageCreatorDelegate(ISessionsession);

The following class shows how to use the SendWithDelegatemethodwith ananonymousdelegatetocreateaMapMessagefromthesuppliedSessionobject.Theuseoftheanonymousdelegateallowsforverytersesyntaxandeasyaccesstolocalvariables.TheNmsTemplate isconstructedbypassingareferencetoaConnectionFactory.

publicclassSimplePublisher

{

privateNmsTemplatetemplate;

publicSimplePublisher()

{

template=newNmsTemplate(newConnectionFactory(

}

publicvoidPublish(stringticker,doubleprice)

{

template.SendWithDelegate("APP.STOCK.MARKETDATA"

delegate(ISessionsession)

{

IMapMessagemessage=session.CreateMapMessage();

message.Body.SetString("TICKER"

message.Body.SetDouble("PRICE"

message.NMSPriority=2;

returnmessage;

});

}

}

Page 660: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AzeroargumentconstructorandConnectionFactorypropertyarealsoprovided.Alternatively consider deriving from Spring's NmsGatewaySupportconveniencebase classwhichprovides aConnectionFactoryproperty thatwillinstantiate a NmsTemplate instance that is made available via the propertyNmsTemplate.

29.3.1.UsingMessageConvertersIn order to facilitate the sending of domain model objects, theNmsTemplate has various send methods that take a .NET object as anargument for a message's data content. The overloaded methodsConvertAndSendandReceiveAndConvertinNmsTemplatedelegate the conversion process to an instance of theIMessageConverter interface.This interfacedefinesa simplecontractto convert between .NET objects and JMS messages. The defaultimplementation SimpleMessageConverter supports conversionbetween String and TextMessage, byte[] and BytesMesssage, andSystem.Collections.IDictionary andMapMessage. By using the converter, youandyourapplicationcodecanfocusonthebusinessobjectthatisbeingsentorreceived via messaging and not be concerned with the details of how it isrepresentedasaJMSmessage.ThereisalsoanXmlMessageConverterthat converts objects to an XML string and vice-versa for sending via aTextMessage.ThefamilyofConvertAndSendmessagesaresimilar tothatof theSendmethod with the additional argument of type IMessagePostProcessor. Thesemethodsarelistedbelow.

voidConvertAndSend(objectmessage)

void ConvertAndSend(object message,

IMessagePostProcessorpostProcessor)

void ConvertAndSend(string destinationName,

objectmessage)

void ConvertAndSend(string destinationName,

object message, IMessagePostProcessor

postProcessor);

Page 661: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

voidConvertAndSend(Destinationdestination,

objectmessage)

voidConvertAndSend(Destinationdestination,

object message, IMessagePostProcessor

postProcessor)

TheexamplebelowusesthedefaultmessageconvertertosendaHashtableasamessagetothedestination"APP.STOCK".

publicvoidPublishUsingDict(stringticker,doubleprice)

{

IDictionarymarketData=newHashtable();

marketData.Add("TICKER",ticker);

marketData.Add("PRICE",price);

template.ConvertAndSend("APP.STOCK.MARKETDATA",marketData);

}

Toaccommodatethesettingofmessage'sproperties,headers,andbodythatcannot be generally encapsulated inside a converter class, theIMessageConverterPostProcessorinterfacegivesyouaccesstothemessageafterithasbeenconvertedbutbeforeitissent.TheexamplebelowdemonstrateshowtomodifyamessageheaderandapropertyafteraHashtableis converted to a message using the IMessagePostProcessor. The methodsConvertAndSendUsingDelegateallowfortheuseofadelegate toperformmessagepostprocessing.Thisfamilyofmethodsislistedbelow

void ConvertAndSendWithDelegate(object

message, MessagePostProcessorDelegate

postProcessor)

voidConvertAndSendWithDelegate(IDestination

destination, object message,

MessagePostProcessorDelegatepostProcessor)

void ConvertAndSendWithDelegate(string

destinationName, object message,

MessagePostProcessorDelegatepostProcessor)

Thedeclarationofthedelegateis

Page 662: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicdelegateIMessageMessagePostProcessorDelegate(IMessagemessage);

Thefollowingcodeshowsthisinaction.

publicvoidPublishUsingDict(stringticker,doubleprice)

{

IDictionarymarketData=newHashtable();

marketData.Add("TICKER",ticker);

marketData.Add("PRICE",price);

template.ConvertAndSendWithDelegate("APP.STOCK.MARKETDATA"

delegate(IMessagemessage)

{

message.NMSPriority=2;

message.NMSCorrelationID=newGuid().ToString();

returnmessage;

});

}

Page 663: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

29.4.SessionandProducerCallbackWhilethesendoperationscovermanycommonusagescenarios,therearecaseswhen you want to perform multiple operations on a JMS Session orMessageProducer. The SessionCallback and ProducerCallback expose theSessionandSession/MessageProducerpairrespectfully.TheExecute()methodsonNmsTemplateexecutethesecallbackmethods.

public object Execute(IProducerCallback

action)

public object Execute(ProducerDelegate

action)

public object Execute(ISessionCallback

action)

public object Execute(SessionDelegate

action)

WhereISessionCallbackandIProducerCallbackare

publicinterfaceIProducerCallback

{

objectDoInJms(Sessionsession,MessageProducerproducer);

}

and

publicinterfaceISessionCallback

{

objectDoInJms(Sessionsession);

}

The delegate signatures are listed below and mirror the interface methodsignature

publicdelegateobjectSessionDelegate(ISessionsession);

publicdelegateobjectProducerDelegate(ISessionsession,IMessageProducerproducer);

Page 664: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

29.5.Receivingamessage

29.5.1.SynchronousReceptionWhile messaging middleware is typically associated with asynchronousprocessing, it is possible to consumemessages synchronously.TheoverloadedReceive(..) methods on NmsTemplate provide this functionality.Duringasynchronousreceive,thecallingthreadblocksuntilamessagebecomesavailable. This can be a dangerous operation since the calling thread canpotentially be blocked indefinitely. The property ReceiveTimeout onNmsTemplatespecifieshowlongthereceivershouldwaitbeforegivingupwaitingforamessage.TheReceivemethodsarelistedbelow

publicMessageReceive()

public Message Receive(Destination

destination)

public Message Receive(string

destinationName)

public Message ReceiveSelected(string

messageSelector)

public Message ReceiveSelected(string

destinationName,stringmessageSelector)

public Message ReceiveSelected(Destination

destination,stringmessageSelector)

The Receive method without arguments will use theDefaultDestination. The ReceiveSelected methods apply theprovidedmessageselectorstringtotheMessageConsumerthatiscreated.

The ReceiveAndConvert methods apply the template's messageconverterwhenreceivingamessage.Themessageconvertertouseissetusingthe property MessageConverter and is theSimpleMessageConverterimplementationbydefault.Thesemethodsarelistedbelow.

Page 665: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicobjectReceiveAndConvert()

public object ReceiveAndConvert(Destination

destination)

public object ReceiveAndConvert(string

destinationName)

public object

ReceiveSelectedAndConvert(string

messageSelector)

public object

ReceiveSelectedAndConvert(string

destinationName,stringmessageSelector)

public object

ReceiveSelectedAndConvert(Destination

destination,stringmessageSelector)

29.5.2.AsynchronousReceptionAsynchronousreceptionofmessagesoccursbythemessagingproviderinvokingacallbackfunction.ThisiscommonlyaninterfacesuchastheIMessageListenerinterfaceshownbelow,takenfromtheTIBCOEMSprovider.

publicinterfaceIMessageListener

{

voidOnMessage(Messagemessage);

}

Other vendorsmay provide a delegate based version of this callback or evenboth a delegate and interface options. Apache ActiveMQ supports the use ofdelegates for message reception callbacks. As a programming convenience inSpring.Messaging.Nms.Core is an interfaceIMessageListenerthatcanbeusedwithNMS.

Below is a simple implementation of theIMessageListener interfacethatprocessesamessage.

usingSpring.Messaging.Nms.Core;

Page 666: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

usingApache.NMS;

usingCommon.Logging;

namespaceMyApp

{

publicclassSimpleMessageListener:IMessageListener

{

privatestaticreadonlyILogLOG=LogManager.GetLogger(

privateintmessageCount;

publicintMessageCount

{

get{returnmessageCount;}

}

publicvoidOnMessage(IMessagemessage)

{

messageCount++;

LOG.Debug("Messagelistenercount="+messageCount);

ITextMessagetextMessage=messageasITextMessage;

if(textMessage!=null)

{

LOG.Info("MessageText="+textMessage.Text);

}else

{

LOG.Warn("Cannotprocessmessageoftype"message.GetType());

}

}

}

Once you've implemented yourmessage listener, it's time to create amessagelistenercontainer.Youregisteryoulistenerwithamessagelistenercontainerthatspecifiesvariousmessaging configuration parameters, such as the ConnectionFactory, and thenumber of concurrent consumers to create. There is an abstract base class formessage listener containers,AbstractMessageListenerContainer, and one concreteimplementation, SimpleMessageListenerContainer.SimpleMessageListenerContainer creates a fixed number of

Page 667: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

JMS Sessions/MessageConsumer pairs as set by the propertyConcurrentConsumers.Hereisasampleconfiguration

<objectid="ConnectionFactory"type="Apache.NMS.ActiveMQ.ConnectionFactory,Apache.NMS.ActiveMQ"

<constructor-argindex="0"value="tcp://localhost:61616"

</object>

<objectid="MyMessageListener"type="MyApp.SimpleMessageListener,MyApp"

<objectid="MessageListenerContainer"type="Spring.Messaging.Nms.Listener.SimpleMessageListenerContainer,Spring.Messaging.Nms"

<propertyname="ConnectionFactory"ref="ConnectionFactory"

<propertyname="DestinationName"value="APP.REQUEST"/>

<propertyname="ConcurrentConsumers"value="10"/>

<propertyname="MessageListener"ref="MyMessageListener"

</object>

Theaboveconfigurationwillcreate10threadsthatprocessmessagesoffofthequeuenamed"APP.REQUEST".ThethreadsarethoseownedbythemessagingproviderasaresultofcreatingaMessageConsumer.Otherimportantpropertiesare ClientID, used to set the ClientID of the Connection andMessageSelector to specify the 'sql-like'message selector string.Durablesubscriptions are supported via the propertiesSubscriptionDurable andDurableSubscriptionName.Youmay also register an exception listenerusingthepropertyExceptionListener.

AcustomschematocreatetheSimpleMessageListenercontainerisalso provided. Using this schema the configuration above looks like thefollowing

<objectsxmlns="http://www.springframework.net"

xmlns:nms="http://www.springframework.net/nms">

<!--otherobjectdefinitions-->

<nms:listener-containerconnection-factory="ConnectionFactory"

<nms:listenerref="MyMessageListener"destination="APP.STOCK.REQUEST"

</nms:listener-container>

</objects>

Exceptions that are thrown during message processing can be passed to an

Page 668: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

implementation of IExceptionHandler and registered with thecontainer via the property ExceptionListener. The registeredIExceptionHandler will be invoked if the exception is of the typeNMSException(ortheequivalentrootexceptiontypeforotherproviders).TheSimpleMessageListenerContainerwill logstheexceptionaterrorlevelandnotpropagate theexception to theprovider.All handlingof acknowledgementand/or transactions is done by the listener container. You can override themethodHandleListenerExceptiontochangethisbehavior.Pleaserefer to theSpringSDKdocumentationforadditionaldescriptionofthefeaturesandpropertiesofSimpleMessageListenerContainer.

29.5.3.TheISessionAwareMessageListenerinterfaceThe ISessionAwareMessageListener interface is a Spring-specific interface that provides a similar contract to the messaging provider'sIMessageListener interface or Listener delegate/event, but alsoprovides themessage handlingmethodwith access to theSession fromwhichtheMessagewasreceived.

publicinterfaceISessionAwareMessageListener

{

voidOnMessage(IMessagemessage,ISessionsession);

}

Youcanalsochoosetoimplementthisinterfaceandregisteritwiththemessagelistenercontainer

29.5.4.MessageListenerAdapaterThe MessageListenerAdapter class is the final component in Spring'sasynchronousmessagingsupport: inanutshell, it allowsyou toexposealmostany class to be invoked as a messaging callback (there are of course someconstraints).Consider the following interface definition. Notice that although the interfaceextends neither the IMessageListener norISessionAwareMessageListenerinterfaces,itcanstillbeusedasa Message-Driven PONOs (MDP) via the use of the

Page 669: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

MessageListenerAdapter class. Notice also how the variousmessagehandlingmethods are strongly typed according to the contents of thevariousMessagetypesthattheycanreceiveandhandle.

publicinterfaceMessageHandler{

voidHandleMessage(stringmessage);

voidHandleMessage(Hashtablemessage);

voidHandleMessage(byte[]message);

}

andaclassthatimplementsthisinterface...

publicclassDefaultMessageHandler:IMessageHandler{

//stubimplementationselidedforbevity...

}

In particular, note how the above implementation of the IMessageHandlerinterface (the aboveDefaultMessageHandler class) has nomessaging providerAPIdependenciesatall.IttrulyisaPONOthatwewillmakeintoanMDPviathefollowingconfiguration.

<objectid="MessagleHandler"type="MyApp.DefaultMessageHandler,MyApp"

<objectid="MessageListenerAdapter"type="Spring.Messaging.Nms.Listener.Adapter.MessageListenerAdapter,Spring.Messaging.Nms"

<propertyname="HandlerObject"ref="MessagleHandler"/>

</object>

<objectid="MessageListenerContainer"type="Spring.Messaging.Nms.Listener.SimpleMessageListenerContainer,Spring.Messaging.Nms"

<propertyname="ConnectionFactory"ref="ConnectionFactory"

<propertyname="DestinationName"value="APP.REQUEST"/>

<propertyname="MessageListener"ref="MessageListenerAdapter"

</object>

The previous examples relies on the fact that the default IMessageConverterimplementationoftheMessageListenerAdapterisSimpleMessageConverterthatcanconvertfrommessages tostrings,byte[],andhashtablesandobject froma

Page 670: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ITextMessage,IBytesMessage,IMapMessage,andIObjectMessagerespectfully.BelowisanexampleofanotherMDPthatcanonlyhandlethereceivingofNMSITextMessagemessages.Notice how themessage handlingmethod is actuallycalled 'Receive' (the name of the message handling method in aMessageListenerAdapterdefaultsto'HandleMessage'),butitisconfigurable(asyouwillseebelow).Noticealsohowthe 'Receive(..)'methodisstronglytypedtoreceiveandrespondonlytoNMSITextMessagemessages.

publicinterfaceTextMessageHandler{

voidReceive(ITextMessagemessage);

}

publicclassTextMessageHandlerimplementsITextMessageHandler{

//implementationelidedforclarity...

}

Theconfigurationof theattendantMessageListenerAdapterwouldlooklikethis

<objectid="MessagleHandler"type="MyApp.DefaultMessageHandler,MyApp"

<objectid="MessageListenerAdapter"type="Spring.Messaging.Nms.Listener.Adapter.MessageListenerAdapter,Spring.Messaging.Nms"

<propertyname="HandlerObject"ref="TextMessagleHandler"

<propertyname="DefaultHandlerMethod"value="Receive"/>

<!--wedon'twantautomaticmessagecontextextraction-->

<propertyname="MessageConverter">

<null/>

</property>

</object>

Please note that if the above 'MessageListener' receives aMessage of a typeother than ITextMessage, aListenerExecutionFailedException will be thrown (andsubsequentlyhandledbythecontainerbyloggingtheexception).IfyourIMessageConverterimplementationwillreturnmultipleobjecttypes,overloadingthehandlermethodisperfectlyacceptable,themostspecificmatching method will be used. A method with an object signature would be

Page 671: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

considera'catch-all'methodoflastresort.Forexample,youcanhaveanhandlerinterfaceasshownbelow.

publicinterfaceIMyHandler

{

voidDoWork(stringtext);

voidDoWork(OrderRequestorderRequest);

voidDoWork(InvoiceRequestinvoiceRequest);

voidDoWork(objectobj);

}

AnotherofthecapabilitiesoftheMessageListenerAdapterclassistheabilitytoautomaticallysendbackaresponseMessageifahandlermethodreturnsanon-voidvalue.Theadapter'smessageconverterwillbeusedtoconvertthemethodsreturn value to a message. The resulting message will then be sent to theDestination defined in the JMSReply-To property of the originalMessage (ifoneexists),orthedefaultDestinationsetontheMessageListenerAdapter(ifonehas been configured). If no Destination is found then anInvalidDestinationException will be thrown (and please notethatthisexceptionwillnotbeswallowedandwillpropagateupthecallstack).An interface that is typicalwhen usedwith amessage converter that supportsmultipleobjecttypesandhasreturnvaluesisshownbelow.

publicinterfaceIMyHandler

{

stringDoWork(stringtext);

OrderResponseDoWork(OrderRequestorderRequest);

InvoiceResponseDoWork(InvoiceRequestinvoiceRequest);

voidDoWork(objectobj);

}

29.5.5. Processing messages within a messagingtransactionInvokingamessagelistenerwithinatransactiononlyrequiresreconfigurationofthelistenercontainer.Localmessagetransactionscanbeactivatedbysettingtheproperty SessionAcknowledgeMode which for NMS is of the enum typeAcknowledgementMode, to AcknowledgementMode.Transactional. Each

Page 672: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

message listener invocation will then operate within an active messagingtransaction, with message reception rolled back in case of listener executionfailure.Sendingaresponsemessage(viaISessionAwareMessageListener)willbepartofthesame local transaction,butanyother resourceoperations(suchasdatabaseaccess) will operate independently. This usually requires duplicate messagedetection in the listener implementation, covering the case where databaseprocessing has committed but message processing failed to commit. See thediscussionontheActiveMQwebsitehereformoreinformationcombininglocaldatabaseandmessagingtransactions.

29.5.6.MessagingNamespacesupportTo use the NMS namespace elements you will need to reference the NMSschema. For information on how to set this up refer to Section A.2.6, “The nmsmessagingschema”.Thenamespaceconsistsofone top levelelements:<listener-container/>whichcancontainoneormore<listener/>childelements.Hereisanexampleofabasicconfigurationfortwolisteners.

<nms:listener-container>

<nms:listenerdestination="queue.orders"ref="OrderService"

<nms:listenerdestination="queue.confirmations"ref="ConfirmationLogger"

</nms:listener-container>

Theexampleaboveisequivalenttocreatingtwodistinctlistenercontainerobjectdefinitions and two distinct MessageListenerAdapter object definitions asdemonstrated in the section entitled Section 29.5.4, “MessageListenerAdapater”. Inadditiontotheattributesshownabove,thelistenerelementmaycontainseveraloptionalones.Thefollowingtabledescribesallavailableattributes:

Table29.1.AttributesoftheNMS<listener>element

Attribute Description

id Aobjectnameforthehostinglistenercontainer.Ifnotspecified,aobjectnamewillbeautomaticallygenerated.

Page 673: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

destination(required)

Thedestinationnameforthislistener,resolvedthroughtheIDestinationResolverstrategy.

ref(required) Theobjectnameofthehandlerobject.

method Thenameofthehandlermethodtoinvoke.IftherefpointstoaIMessageListenerorSpringISessionAwareMessageListener,thisattributemaybeomitted.

response-destination

Thenameofthedefaultresponsedestinationtosendresponsemessagesto.Thiswillbeappliedincaseofarequestmessagethatdoesnotcarrya"NMSReplyTo"field.Thetypeofthisdestinationwillbedeterminedbythelistener-container's"destination-type"attribute.Note:Thisonlyappliestoalistenermethodwithareturnvalue,forwhicheachresultobjectwillbeconvertedintoaresponsemessage.

subscription Thenameofthedurablesubscription,ifany.

selector Anoptionalmessageselectorforthislistener.

pubsub-domain

Anoptionalbooleanvalue.Settotrueforthepublish-subscribedomain(Topics)orfalse(thedefault)forpoint-to-pointdomain(Queues).Thisisusefulwhenusingthedefaultimplementationfordestinationresolvers.

The<listener-container/> element also accepts several optional attributes.Thisallows for customization of the various strategies (for example,DestinationResolver) as well as basic messaging settings and resourcereferences. Using these attributes, it is possible to define highly-customizedlistenercontainerswhilestillbenefitingfromtheconvenienceofthenamespace.

<jms:listener-containerconnection-factory="MyConnectionFactory"

destination-resolver="MyDestinationResolver"

concurrency="10">

<jms:listenerdestination="queue.orders"ref="OrderService"

<jms:listenerdestination="queue.confirmations"ref="ConfirmationLogger"

</jms:listener-container>

The following table describes all available attributes. Consult the class-levelSDK documentation of theAbstractMessageListenerContainer and its subclass

Page 674: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

SimpleMessageListenerContainer for more detail on theindividualproperties.

Table 29.2. Attributes of the NMS <listener-

container>element

Attribute Descriptionconnection-factory

AreferencetotheNMSConnectionFactoryobject(thedefaultobjectnameis'ConnectionFactory').

destination-resolver

AreferencetotheIDestinationResolverstrategyforresolvingJMSDestinations.

message-converter

AreferencetotheIMessageConverterstrategyforconvertingNMSMessagestolistenermethodarguments.DefaultisaSimpleMessageConverter.

destination-type

TheNMSdestinationtypeforthislistener:queue,topicordurableTopic.Thedefaultisqueue.

client-id TheNMSclientidforthislistenercontainer.Needstobespecifiedwhenusingdurablesubscriptions.

acknowledgeThenativeNMSacknowledgemode:auto,client,dups-okortransacted.AvalueoftransactedactivatesalocallytransactedSession.Asanalternative,specifythetransaction-managerattributedescribedbelow.Defaultisauto.

concurrencyThenumberofconcurrentsessions/consumerstostartforeachlistener.Defaultis1;keepconcurrencylimitedto1incaseofatopiclistenerorifqueueorderingisimportant;considerraisingitforgeneralqueues.

recovery-interval

Thetimeintervalbetweenconnectionrecoveryattempts.Thedefaultis5seconds.SpecifyasaTimeSpanvalueusingSpring'sTimeSpanConverter(e.g.10s,10m,3h,etc)

max-recovery-time

Themaximumtimetryreconnectionattempts.Thedefaultis10minutes.SpecifyasaTimeSpanvalueusingSpring'sTimeSpanConverter(e.g.10s,10m,3h,etc)

auto-startup Setwhethertoautomaticallystartthelistenersafterinitialization.Defaultistrue,optionallysettofalse.

Page 675: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter30.MessageOrientedMiddleware-MSMQ

Page 676: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

30.1.IntroductionThe goals of Spring's MSMQ 3.0 messaging support is to raise the level ofabstractionwhenwritingMSMQapplications.TheSystem.MessagingAPI is a low-level API that provides the basis for creating a messagingapplication. However, 'Out-of-the-box', System.Messaging leaves theactofcreatingsophisticatedmulti-threadedmessagingserversandclientsasaninfrastructureactivityforthedeveloper.Springfillsthisgapbyprovingeasytousehelperclassesthatmakescreatinganenterprisemessagingapplicationeasy.These helper classes take into account the nuances of theSystem.MessagingAPI,suchasitslackofthread-safetyinmanycases,the handling of so-called 'poison messages' (messages that are endlesslyredeliveredduetoanunrecoverableexceptionduringmessageprocessing),andcombining database transactions with message transactions. Other goals ofSpring'sMSMQmessagingsupportare to supportmessagingbestpractices, inparticularencouragingacleanarchitecturallayeringthatseparatesthemessagingmiddlewarespecificsfromthecorebusinessprocessing.Spring'sapproachtodistributedcomputinghasalwaysbeentopromoteaplainold .NET object approach or a PONO programming model. In this approachplain .NET objects are those that are devoid of any reference to a particularmiddleware technology. Spring provides the 'adapter' classes that convertsbetween themiddlewareworld, in this caseMSMQ,and theoo-worldofyourbusiness processing. This is done through the use of Spring'sMessageListenerAdapterclassandIMessageConverters.

The namespaceSpring.Messaging provides the core functionality formessaging. It contains the class MessageQueueTemplate thatsimplifies the use of System.Messaging.MessageQueue byhandling the lack of thread-safety in most ofSystem.Messaging.MessageQueue's methods (for exampleSend). A single instance of MessageQueueTemplate can be usedthroughoutyourapplicationandSpringwillensurethatadifferentinstanceofaMessageQueue class is used per thread when usingMessageQueueTemplate's methods. This per-thread instance of aSystem.Messaging.MessageQueue is also available via itsproperty MessageQueue. The MessageQueueTemplate class is

Page 677: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

also aware of the presence of either an 'ambient'System.Transaction's transaction or a localSystem.Messaging.MessageQueueTransaction.As such ifyouuseMessageQueueTemplate'ssendandreceivemethods,unlikewithplainuseofSystem.Messaging.MessageQueue, youdonotneed tokeep trackof this informationyourself andcall thecorrectoverloadedSystem.Messaging.MessageQueue method for a specifictransaction environment. When using aSystem.Messaging.MessageQueueTransaction this wouldusually require you as a developer to come upwith your ownmechanism forpassingaroundaMessageQueueTransactiontomultipleclassesandlayers in your application.MessageQueueTemplate manages this foryou, so you don't have to do so yourself. These resource management andtransactionfeaturesofMessageQueueTemplatearequiteanalogoustothetransactionalfeaturesofSpring'sAdoTemplateincaseyouarealreadyfamiliarwiththatfunctionality.For asynchronous reception Spring provides several multi-threaded messagelistenercontainers.Youcanpickandconfigurethecontainerthatmatchesyourmessagetransactionalprocessingneedsandconfigurepoison-messagehandlingpolicies.ThemessagelistenercontainerleveragesSpring'ssupportformanagingtransactions. Both DTC, local messaging transactions, and local databasetransactionsare supported. Inparticular, you can easily coordinate the commitand rollback of a local MessageQueueTransaction and a local databasetransactionwhentheyareusedtogether.From a programming perspective, Spring's MSMQ support involves youconfiguring message listener containers and writing a callback function formessageprocessing.On the sending side, it involves you learning how to useMessageQueueTemplate. In both cases youwill quite likelywant totake advantage of usingMessageListenerConverters so you canbetter structure the translation from the System.Messaging.Message datastructure toyourbusinessobjects.After the initial learninghurdle, you shouldfindthatyouwillbemuchmoreproductiveleveragingSpring'shelperclassestowrite enterprise MSMQ applications than rolling your own infrastructure.Feedbackandnewfeaturerequestsarealwayswelcome.TheSpring.MsmqQuickstartapplicationlocatedintheexamplesdirectoryofthe

Page 678: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

distributionshowsthisfunctionalityinaction.

Page 679: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

30.2.AquicktourfortheimpatientHereisaquickexampleofhowtouseSpring'sMSMQsupporttocreateaclientthat sends amessage and amulti-threaded server application that receives themessage. (The client code could also be used as-is in a multi-threadedenvironmentbutthisisnotdemonstrated).On the client side you create an instance of theMessageQueueTemplate class and configure it to use aMessageQueue. This can be done programmatically but it is common tousedependencyinjectionandSpring'sXMLconfigurationfiletoconfigureyourclientclassasshownbelow.

<objectid='questionTxQueue'type='Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging'

<propertyname='Path'value='.\Private$\questionTxQueue'

<propertyname='MessageReadPropertyFilterSetAll'value='true'

</object>

<objectid="messageQueueTemplate"type="Spring.Messaging.Core.MessageQueueTemplate,Spring.Messaging"

<propertyname="MessageQueueObjectName"value="questionTxQueue"

</object>

<!--Classyouwrite-->

<objectid="questionService"type="MyNamespace.QuestionService,MyAssembly"

<propertyname="MessageQueueTemplate"ref="messageQueueTemplate"

<object>

The MessageQueue object is created via an instance ofMessageQueueFactoryObject and theMessageQueueTemplatereferstothisfactoryobjectbynameandnotbyreference.TheSimpleSenderclasslookslikethis

publicclassQuestionService:IQuestionService

{

privateMessageQueueTemplatemessageQueueTemplate;

publicMessageQueueTemplate{

get{returnmessageQueueTemplate;}

set{messageQueueTemplate=value;}

Page 680: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

publicvoidSendQuestion(stringquestion)

{

MessageQueueTemplate.ConvertAndSend(question);

}

}

This class can be shared across multiple threads and theMessageQueueTemplatewilltakecareofmanagingthreadlocalaccessto a System.Messaging.MessageQueue as well as anySystem.Messaging.IMessageFormatterinstances.Furthermore, since this isa transactionalqueue (only thenamegives itaway),the message will be sent using a single local messaging transaction. Theconversionfromthestringtotheunderlingmessageismanagedbyaninstanceof the IMessageConverter class. By default an implementation thatuses an XmlMessageFormatter with a TargetType ofSystem.String is used. You can configure theMessageQueueTemplate to use other IMessageConveterimplementations that do conversions above and beyond what the 'stock'IMessageFormatters do. See the section on MessageConverters formoredetails.On the receiving sidewewould like to consume themessages transactionallyfromthequeue.Sincenootherdatabaseoperationsarebeingperformed inourserver side processing, we select theTransactionMessageListenerContainer and configure it touse the MessageQueueTransactionManager. TheMessageQueueTransactionManager an implementation ofSpring'sIPlatformTransactionManagerabstractionthatprovidesa uniformAPI on top of various transactionmanager (ADO.NET,NHibernate,MSMQ, etc). Spring's MessageQueueTransactionManager isresponsible for createing, committing, and rolling back a MSMQMessageQueueTransaction.Whileyoucancreate themessage listenercontainerprogrammatically,wewillshowthedeclarativeconfigurationapproachbelow

Page 681: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--Queuetoreceivefrom-->

<objectid='questionTxQueue'type='Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging'

<propertyname='Path'value='.\Private$\questionTxQueue'

<propertyname='MessageReadPropertyFilterSetAll'value='true'

</object>

<!--MSMQTransactionManager-->

<objectid="messageQueueTransactionManager"type="Spring.Messaging.Core.MessageQueueTransactionManager,Spring.Messaging"

<!--MessageListenerContainerthatusesMSMQtransactionalforreceives-->

<objectid="transactionalMessageListenerContainer"type="Spring.Messaging.Listener.TransactionalMessageListenerContainer,Spring.Messaging"

<propertyname="MessageQueueObjectName"value="questionTxQueue"

<propertyname="PlatformTransactionManager"ref="messageQueueTransactionManager"

<propertyname="MaxConcurrentListeners"value="10"/>

<propertyname="MessageListener"ref="messageListenerAdapter"

</object>

<!--AdaptertocallaPONOasamessagingcallback-->

<objectid="messageListenerAdapter"type="Spring.Messaging.Listener.MessageListenerAdapter,Spring.Messaging"

<propertyname="HandlerObject"ref="questionHandler"/>

</object>

<!--ThePONOclassthatyouwrite-->

<objectid="questionHandler"type="MyNamespace.QuestionHandler,MyAssembly"

Wehave specified the queue to listen, thatwewant to consume themessagestransactionally,processmessagesfromthequeueusing10threads,andthatourplain object that will handle the business processing is of the typeQuestionHandler. The only class you need to write,QuestionHandler,lookslike

publicclassQuestionHandler:IQuestionHandler

{

publicvoidHandleObject(stringquestion)

{

//performmessageprocessinghere

Console.WriteLine("Receivedquestion:"+question);

//useaninstanceofMessageQueueTemplateandhaveotherMSQMsendoperations

Page 682: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

//partakeinthesamelocalmessagetransactionusedtoreceive

}

}

That is general idea. You write the sender class usingMessageQueueTemplateandtheconsumerclasswhichdoesnot referto anymessaging specific class. The rest is configuration of Spring providedhelperclasses.NotethatiftheHandleObjectmethodhasreturnedastringvalueareplymessagewouldbesenttoaresponsequeue.Theresponsequeuewouldbetakenfrom the Message's own ResponseQueue property or can be specifiedexplicitly using MessageListenerAdapter'sDefaultResponseQueueNameproperty.If an exception is thrown inside the QuestionHandler, then the MSMQtransactionisrolledback,puttingthemessagebackonthequeueforredelivery.If the exception is not due to a transient error in the system, but a logicalprocessing exception, then onewould get endless redelivery of themessage -clearlynotadesirablesituation.Thesemessagesaresocalled'poisonmessages'and a strategy needs to be developed to deal with them. This is left as adevelopment task if you when using the System.Messaging APIs but Springprovidesastrategyforhandlingpoisonmessages,bothforDTCbasedmessagereceptionaswellasforlocalmessagingtransactions.Inthelastpartthis'quicktour'wewillconfigurethemessagelistenercontainerto handle poison messages. This is done by creating an instance ofSendToQueueExceptionHandler and setting the propertyMaxRetrytobethenumberofexceptionsorretryattemptswearewillingtotoleratebeforetakingcorrectiveactions.Inthiscase, thecorrectiveactionis tosend themessage toanother queue.Wecan then create othermessage listenercontainerstoreadfromthosequeuesandhandle themessagesappropriatelyorperhapsyouwillavoidautomatedprocessingofthesemessagesandtakemanualcorrectiveactions.

<!--The'error'queuetosendpoisonmessages-->

<objectid='errorQuestionTxQueue'type='Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging'

<propertyname='Path'value='.\Private$\errorQuestionTxQueue'

<propertyname='MessageReadPropertyFilterSetAll'value='true'

Page 683: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</object>

<!--MessageListenerContainerthatusesMSMQtransactionalforreceives-->

<objectid="transactionalMessageListenerContainer"type="Spring.Messaging.Listener.TransactionalMessageListenerContainer,Spring.Messaging"

<!--asbeforebutadding-->

<propertyname="MessageTransactionExceptionHandler"ref=

</object>

<!--Poisonmessagehandlingpolicy-->

<objectid="messageTransactionExceptionHandler"type="Spring.Messaging.Listener.SendToQueueExceptionHandler,Spring.Messaging"

<propertyname="MaxRetry"value="5"/>

<propertyname="MessageQueueObjectName"value="errorQuestionTxQueue"

</object>

In the event of an exception while processing the message, the messagetransaction will be rolled back (putting the message back on the queuequestionTxQueue for redelivery). If the samemessage causes an exception inprocessing 5 times ,then it will be sent transactionally to theerrorQuestionTxQueue and the message transaction will commit (removing itfromthequeuequestionTxQueue).Youcanalsospecifythatcertainexceptionsshould commit the transaction (remove from the queue) but this is not shownhere ,see below for more informatio non this functionality TheSendToQueueExceptionHandler implements the interfaceIMessageTransactionExceptionHandler (discussed below)soyoucanwriteyourownimplementationsshouldtheprovidedonesnotmeetyourneeds.That's the quick tour folks. Hopefully you got a general feel for how thingswork,whatrequiresconfiguration,andwhatisthecodeyouneedtowrite.Thefollowing sectionsdescribeeachofSpring'shelper classes inmoredetail.ThesampleapplicationthatshipswithSpringisalsoagoodplacetogetstarted.

Page 684: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

30.3.UsingSpringMSMQ

30.3.1.MessageQueueTemplateTheMessageQueueTemplate is used for synchronously sending andreceiving messages. A single instance can be shared across multiple threads,unlike the standard System.Messaging.MessageQueue class.(Onelessresourcemanagementissuetoworryabout!)Athread-localinstanceofthe MessageQueue class is available viaMessageQueueTemplate's property MessageQueue. AMessageQueueTemplateiscreatedbypassingareferencetothenameofaMessageQueueFactoryObject,youcanthinkofitasafriendlyname for your MessagingQueue and the recipe of how to create aninstance of it. See the following section onMessageQueueFactoryObjectformoreinformation.

The MessageQueueTemplate also provides several conveniencemethods for sending and receiving messages. A family of overloadedConvertAndSendandReceiveAndConvertmethodsallowyoutosendandreceiveanobject.Thedefaultmessagequeuetosendandreceivefromis specified using the MessageQueueTemplate's propertyMessageQueueObjectName. The responsibility of converting theobject to a Message and vice versa is given to the template's associatedIMessageConverterimplementation.ThiscanbesetusingthepropertyMessageConverter. The default implementation,XmlMessageConverter, uses anXmlMessageFormatter withits TargetType set to System.String. Note thatSystem.Messaging.IMessageFormatter classes are also notthread safe, so MessageQueueTemplate ensures that thread-localinstances of IMessageConverter are used (as they generally wrapIMessageFormatter'sthatarenotthread-safe).

You can use theMessageQueueTemplate to send messages to otherMessageQueues by specifying their queue 'object name', the name of theMessageQueueFactoryObject.

Page 685: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The family of overloaded ConvertAndSend andReceiveAndConvertmethodsareshownbelow

voidConvertAndSend(objectobj);

voidConvertAndSend(objectobj,MessagePostProcessorDelegatemessagePostProcessorDelegate);

voidConvertAndSend(stringmessageQueueObjectName,objectmessage);

voidConvertAndSend(stringmessageQueueObjectName,objectobj,MessagePostProcessorDelegatemessagePostProcessorDelegate);

objectReceiveAndConvert();

objectReceiveAndConvert(stringmessageQueueObjectName);

The transactional settings of the underlying overloadedSystem.Messaging.MessageQueueSendmethodthatareusedarebasedonthefollowingalgorithm.

1. If the message queue is transactional and there is an ambientMessageQueueTransaction in thread local storage (put therevia the use of Spring'sMessageQueueTransactionManageror TransactionalMessageListenerContainer), themessage will be sent transactionally using theMessageQueueTransactionobjectinthreadlocalstorage.

Note

ThisletsyougrouptogethermultiplemessagingoperationswithinthesametransactionwithouthavingtoexplicitlypassaroundtheMessageQueueTransactionobject.

2. f the message queue is transactional but there is no ambientMessageQueueTransaction, then a singlemessage transactioniscreatedoneachmessagingoperation.(MessageQueueTransactionType=Single).

3. IfthereisanambientSystem.Transactionstransactionthenthat transactionwillbeused(MessageQueueTransactionType=Automatic).

4. If the queue is not transactional, then a non-transactional send

Page 686: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

(MessageQueueTransactionType=None)isused.ThedelegateMessagePostProcessorDelegate has the followingsignature

publicdelegateMessageMessagePostProcessorDelegate(Messagemessage);

Thisletsyoumodifythemessageafterithasbeenconvertedfromandobjecttoamessageusing theIMessageConverterbut before it is sent. This isuseful for setting Message properties (e.g. CorrelationId,AppSpecific,TimeToReachQueue).Usinganonymousdelegatesin.NET2.0makesthisaverysuccinctcodingtask.Ifyouhaveelaboratepropertiesthat need to be set, perhaps creating a custom IMessageConverterwouldbeappropriate.Overloaded Send and Receive operations that use the algorithm listedabove to set transactional delivery options are also available. These are listedbelow

MessageReceive();

MessageReceive(stringmessageQueueObjectName);

voidSend(Messagemessage);

voidSend(stringmessageQueueObjectName,Messagemessage);

voidSend(MessageQueuemessageQueue,Messagemessage);

NotethatinthelastSendmethodthattakesaMessageQueueinstance,itis the callers responsibility to ensure that this instance is not accessed frommultiple threads. This Send method is commonly used when getting theMessageQueue from theResponseQueuepropertyofaMessageduringanasynchronousreceiveprocess.ThereceivetimeoutoftheReceiveoperations is set using the ReceiveTimeout property ofMessageQueueTemplate. The default value isMessageQueue.InfiniteTimeout(whichisactually~3months).TheXMLconfigurationsnippitfordefiningaMessageQueueTemplateisshown

Page 687: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

in theprevioussectionandalso is located in theMSMQquickstartapplicationconfiguraitonfileMessaging.xml

30.3.2.MessageQueueFactoryObjectThe MessageQueueFactoryObject is responsible for creatingMessageQueue instances. You configure the factory with some basicinformation, namely the constructor parameters you are familiar with alreadywhen creating a standard MessageQueue instance, and then settingMessageQueueproperties,suchaLabeletc.SomeconfigurationtasksofaMessageQueue involve calling methods, for example to set whichproperties of themessage to read. These available as properties to set on theMessageQueueFactoryObject. An example declarativeconfigurationisshownbelow

<objectid='testqueue'type='Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging'

<!--propetiespassedtotheMessageQueueconstructor-->

<propertyname='Path'value='.\Private$\testqueue'/>

<propertyname='DenySharedReceive'value='true'/>

<propertyname='AccessMode'value='Receive'/>

<propertyname='EnableCache'value='true'/>

<!--propertiesthatcallconfigurationmethodsontheMessageQueue-->

<propertyname='MessageReadPropertyFilterSetAll'value='true'

<propertyname='ProductTemplate'>

<object>

<propertyname='Label'value='MyLabel'/>

<!--otherMessageQueuepropertiescanbesethere-->

</object>

</property>

</object>

Whenever an object reference is made to 'testqueue' an new instance of theMessageQueue class iscreated.ThisSpring's so-called 'prototype'model,whichdiffersfrom'singleton'mode.Inthesingletoncreationmodewheneveranobjectreferenceismadetoa 'testqueue'thesameMessageQueue instancewould be used. So that a new instance can be retrieved based on need, themessage listener containers take as an argument the name of theMessageQueueFactoryObject and not a reference. (i.e. use of'value'insteadof'ref'intheXML).

Page 688: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Note

TheMessageQueueFactoryObjectclassisanidealcandidateforuseofacustomnamespace.Thiswillbeprovidedfuture.ThiswillallowyoutouseVS.NETIntelliSensetoconfigurethiscommonlyusedobject.Anexampleofthepotentialisshownbelow

<mq:messageQueueid="testqueue"path=".\Private$\testqueue"

<mq:propertieslabel="MyLabel"/>

</mq:messageQueue>

30.3.3. MessageQueue and IMessageConverter resourcemanagementMessageQueues and IMessageFormatters (commonly used inIMessageConverterimplementations)arenotthread-safe.Forexample,only the following methods on MessageQueue are thread-safe,BeginPeek, BeginReceive, EndPeek, EndReceive,GetAllMessages,Peek,andReceive.To isolate the creation logic of these classes, the factory interfaceIMessageQueueFactoryisused.Theinterfaceisshownbelow

publicinterfaceIMessageQueueFactory

{

MessageQueueCreateMessageQueue(stringmessageQueueObjectName);

IMessageConverterCreateMessageConverter(stringmessageConverterObjectName);

}

A provided implementation, DefaultMessageQueueFactory willcreate an instance of each class per-thread. It delegates the creation of theMessageQueue instance to the Spring container. The argument,messageConverterObjectName, must be the id/name of aMessageQueueFactoryObjectdefinedintheSpringcontainer.

DefaultMessageQueueFactory leverages Spring's local threadstoragesupportsoitwillworkcorrectlyinstandaloneandwebapplications.YoucanusetheDefaultMessageQueueFactoryindependentofthe

Page 689: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

restofSpring'sMSMQsupportshouldyouneedonlythefunctionalityitoffers.MessageQueueTemplateandthelistenercontainerscreateaninstanceofDefaultMessageQueueFactory by default. Should youwant toshare the same instanceacross these twoclasses,orprovideyour owncustomimplementation, use the property MessageQueueFactory on eitherMessageQueueTemplateorthemessagelistenerclasse.s

30.3.4.MessageListenerContainersOneof themost commonusesofMSMQ is to concurrentlyprocessmessagesdeliveredasynchronously.ThissupportisprovidedinSpringbymessagelistenercontainers. A message listener container is the intermediary between anIMessageListenerandaMessageQueue. (Note,message listenercontainers are conceptually different than Spring's Inversion of Controlcontainer, though it integrates and leverages the IoC container.) The messagelistenercontainer takescareofregisteringtoreceivemessages,participating intransactions, resource acquisition and release, exception conversion andsuchlike. This allows you as an application developer to write the (possiblycomplex) business logic associated with receiving a message (and possiblyrespondingtoit),anddelegateboilerplateMSMQinfrastructureconcernstotheframework.A subclass ofAbstractMessageListenerContainer is used toreceivemessagesfromaMessageQueue.Whichsubclassyoupickdependson your transaction processing requirements. The following subclasses areavailableinthenamespaceSpring.Messaging.Listener

NonTransactionalMessageListenerContainer -doesnotsurroundthereceiveoperationwithatransaction

TransactionalMessageListenerContainer-surroundsthereceiveoperationwithlocal(non-DTC)basedtransaction(s).

DistributedTxMessageListenerContainer-surroundsthereceiveoperationwithadistributed(DTC)transaction

EachofthesecontainersuseanimplementationinwhichisbasedonPeekingformessages on a MessageQueue. Peeking is the only resource efficientapproach that can be used in order to have MessageQueue receipt inconjunctionwithtransactions,eitherlocalMSMQtransactions,localADO.NET

Page 690: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

basedtransactions,orDTCtransactions.EachcontainercanspecifythenumberofthreadsthatwillbecreatedforprocessingmessagesafterthePeekoccursviathepropertyMaxConcurrentListeners.Eachprocessing threadwillcontinue to listen for messages up until the timeout value specified byListenerTimeLimitoruntil therearenomoremessageson thequeue(whichever comes first). The default value ofListenerTimeLimit isTimeSpan.Zero,meaningthatonlyoneattempttoreceiveamessagefromthequeuewillbeperformedbyeachlistenerthread.Thecurrentimplementationuses thestandard .NET threadpool.Future implementationswilluseacustom(andpluggable)threadpool.

30.3.4.1.NonTransactionalMessageListenerContainerThiscontainerperformsaReceiveoperationontheMessageQueuewithoutany transactional settings. As such messages will not be redelivered if anexception is thrown during message processing. Exceptions during messageprocessing can be handled via an implementation of the interfaceIExceptionHandler. This can be set via the propertyExceptionHandler on the listener. The IExceptionHandlerinterfaceisshownbelow

publicinterfaceIExceptionHandler

{

voidOnException(Exceptionexception,Messagemessage);

}

An example of configuring aNonTransactionalMessageListenerContainer with anIExceptionHandlerisshownbelow

<!--Queuetoreceivefrom-->

<objectid='msmqTestQueue'type='Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging'

<propertyname='Path'value='.\Private$\testqueue'/>

<propertyname='MessageReadPropertyFilterSetAll'value='true'

<propertyname='ProductTemplate'>

<object>

<propertyname='Label'value='MyTestQueueLabel'/>

</object>

Page 691: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</property>

</object>

<!--Queuetorespondto-->

<objectid='msmqTestResponseQueue'type='Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging'

<propertyname='Path'value='.\Private$\testresponsequeue'

<propertyname='MessageReadPropertyFilterSetAll'value='true'

<propertyname='ProductTemplate'>

<object>

<propertyname='Label'value='MyTestResponseQueueLabel'

</object>

</property>

</object>

<!--Listenercontainer-->

<objectid="nonTransactionalMessageListenerContainer"type

<propertyname="MessageQueueObjectName"value="msmqTestQueue"

<propertyname="MaxConcurrentListeners"value="2"/>

<propertyname="ListenerTimeLimit"value="20s"/><!--20seconds-->

<propertyname="MessageListener"ref="messageListenerAdapter"

<propertyname="ExceptionHandler"ref="exceptionHandler"

</object>

<!--Delegatetoplain.NETobjectformessagehandling-->

<objectid="messageListenerAdapter"type="Spring.Messaging.Listener.MessageListenerAdapter,Spring.Messaging"

<propertyname="DefaultResponseQueueName"value="msmqTestResponseQueue"

<propertyname="HandlerObject"ref="simpleHandler"/>

</object>

<!--Classesyouneedtowrite-->

<objectid="simpleHandler"type="MyNamespace.SimpleHandler,MyAssembly"

<objectid="exceptionHandler"type="MyNamespace.SimpleExceptionHandler,MyAssembly"

TheSimpleHandlerclasswouldlooksomethinglikethis

publicclassSimpleHandler:ISimpleHandler

{

publicvoidHandleObject(stringtxt)

{

//performmessageprocessing...

Console.WriteLine("Receivedtext:"+txt);

Page 692: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

}

30.3.4.2.TransactionalMessageListenerContainerThismessage listenercontainerperforms receiveoperationswithin the contextof local transaction. This class requires an instance of Spring'sIPlatformTransactionManager, eitherAdoPlatformTransactionManager,HibernateTransactionManager, orMessageQueueTransactionManager.

If you specify a MessageQueueTransactionManager then aMessageQueueTransaction will be started before receiving themessage and used as part of the container's receive operation. As with otherIPlatformTransactionManager implementation's, thetransactional resources (in this case an instance of theMessageQueueTransaction class) is bound to thread local storage.MessageQueueTemplatewill lookinthread-localstorageandusethis'ambient' transaction if found for its sendand receiveoperations.Themessagelistener is invoked and if no exception occurs, then theMessageQueueTransactionManager will commit theMessageQueueTransaction.ThemessagelistenerimplementationcancallintoservicelayerclassesthataremadetransactionalusingstandardSpringdeclarativetransactionaltechniques.Incaseofexceptionsintheservicelayer,thedatabaseoperationwillberolledback(nothing new here), and theTransactionalMessageListenerContainer will call it'sIMessageTransactionExceptionHandler implementation todetermine if the MessageQueueTransaction should commit(removingthemessagefromthequeue)orrollback(leavingthemessageonthequeueforredelivery).

Note

TheuseofatransactionalservicelayerincombinationwithaMessageQueueTransactionManagerisapowerful

Page 693: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

combinationthatcanbeusedtoachieve"exactlyone"transactionmessageprocessingwithdatabaseoperations.Thisrequiresalittleextraprogrammingeffortandisamoreefficientalternativethanusingdistributedtransactionswhicharecommonlyassociatedwiththisfunctionalitysinceboththedatabaseandthemessagetransactioncommitorrollbacktogether.TheadditionalprogramminglogicneededtoachievethisistokeeptrackoftheMessage.Idthathasbeenprocessedsuccessfullywithinthetransactionalservicelayer.Thisisneededastheremaybeasystemfailure(e.g.powergoesoff)betweenthe'inner'databasecommitandthe'outer'messagingcommit,resultinginmessageredelivery.Thetransactionalservicelayerneedslogictodetectifincomingmessagewasprocessedsuccessfully.Itcandothisbycheckingthedatabaseforanindicationofsuccessfulprocessing,perhapsbyrecordingtheMessage.Iditselfinastatustable.Ifthetransactionalservicelayerdeterminesthatthemessagehasalreadybeenprocessed,itcanthrowaspecificexceptionforthiscase.Thecontainer'sexceptionhandlerwillrecognizethisexceptiontypeandvotetocommit(removefromthequeue)the'outer'messagingtransaction.Springprovidesanexceptionhandlerwiththisfunctionality,seeSendToQueueExceptionHandlerdescribedbelow.

An example of configuring theTransactionalMessageListenerContainer using aMessageQueueTransactionManagerisshownbelow

<!--Queuetoreceivefrom-->

<objectid='msmqTestQueue'type='Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging'

<propertyname='Path'value='.\Private$\testqueue'/>

<propertyname='MessageReadPropertyFilterSetAll'value='true'

<propertyname='ProductTemplate'>

<object>

<propertyname='Label'value='MyTestQueueLabel'/>

</object>

</property>

</object>

<!--Queuetorespondto-->

<objectid='msmqTestResponseQueue'type='Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging'

<propertyname='Path'value='.\Private$\testresponsequeue'

Page 694: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<propertyname='MessageReadPropertyFilterSetAll'value='true'

<propertyname='ProductTemplate'>

<object>

<propertyname='Label'value='MyTestResponseQueueLabel'

</object>

</property>

</object>

<!--TransactionManagerforMSMQMessaging-->

<objectid="messageQueueTransactionManager"type="Spring.Messaging.Core.MessageQueueTransactionManager,Spring.Messaging"

<!--Thetransactionmessagelistenercontainer-->

<objectid="transactionalMessageListenerContainer"type="Spring.Messaging.Listener.TransactionalMessageListenerContainer,Spring.Messaging"

<propertyname="MessageQueueObjectName"value="msmqTestQueue"

<propertyname="PlatformTransactionManager"ref="messageQueueTransactionManager"

<propertyname="MaxConcurrentListeners"value="5"/>

<propertyname="ListenerTimeLimitIn"value="20s"/>

<propertyname="MessageListener"ref="messageListenerAdapter"

<propertyname="MessageTransactionExceptionHandler"ref=

</object>

<!--Delegatetoplain.NETobjectformessagehandling-->

<objectid="messageListenerAdapter"type="Spring.Messaging.Listener.MessageListenerAdapter,Spring.Messaging"

<propertyname="DefaultResponseQueueName"value="msmqTestResponseQueue"

<propertyname="HandlerObject"ref="simpleHandler"/>

</object>

<!--Poisonmessagehandling-->

<objectid="messageTransactionExceptionHandler"type="Spring.Messaging.Listener.SendToQueueExceptionHandler,Spring.Messaging"

<propertyname="MaxRetry"value="5"/>

<propertyname="MessageQueueObjectName"value="testTxErrorQueue"

</object>

<!--Classesyouneedtowrite-->

<objectid="simpleHandler"type="MyNamespace.SimpleHandler,MyAssembly"

If you specify either AdoPlatformTransactionManager orHibernateTransactionManager then a local database transactionwillbestartedbefore the receiving themessage.Bydefault, thecontainerwill

Page 695: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

alsostartalocalMessageQueueTransactionafterthelocaldatabasetransaction has started, but before the receiving the message. ThisMessageQueueTransactionwillbeusedtoreceivethemessage.BydefaulttheMessageQueueTransactionwillbeboundtothreadlocalstoragesothatanyMessageQueueTemplatesendorreceiveoperationswill participate transparently in the sameMessageQueueTransaction.IfyoudonotwantthisbehaviorsetthepropertyExposeContainerManagedMessageQueueTransaction tofalse.IncaseofexceptionsduringIMessageListenerprocessingwhenusingeither either AdoPlatformTransactionManager orHibernateTransactionManager the container'sIMessageTransactionExceptionHandler will determine iftheMessageQueueTransactionshouldcommit(removingitfromthequeue) or rollback (placing it back on the queue for redelivery). The listenerexceptionwillalwaystriggerarollbackinthe'outer'databasetransaction.Poison message handing, that is, the endless redelivery of a message due toexceptions during processing, can be detected using implementations of theIMessageTransactionExceptionHandler. This interface isshownbelow

publicinterfaceIMessageTransactionExceptionHandler

{

TransactionActionOnException(Exceptionexception,Messagemessage,MessageQueueTransactionmessageQueueTransaction);

}

ThereturnvalueisanenumerationwiththevaluesCommitandRollback.A specific implementation is provided that will move the poison message toanother queue after a maximum number of redelivery attempts. SeeSendToQueueExceptionHandler described below. You can set aspecific implementation to by settingTransactionalMessageListenerContainer's propertyMessageTransactionExceptionHandler

TheIMessageTransactionExceptionHandlerimplementation

Page 696: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

SendToQueueExceptionHandlerkeepstrackof theMessage'sIdpropertyinmemorywithacountofhowmanytimesanexceptionhasoccurred.If thatcount isgreater than thehandler'sMaxRetry count itwillbesent toanother queue using the providedMessageQueueTransaction. Thequeue to send the message to is specified via the propertyMessageQueueObjectName.

30.3.4.3.DistributedTxMessageListenerContainerThismessage listenercontainerperforms receiveoperationswithin the contextofdistributedtransaction.Adistributedtransactionisstartedbeforeamessageisreceived. The receive operation participates in this transaction using byspecifyingMessageQueueTransactionType=Automatic.The transaction that isstarted is automatically promoted to two-phase-commit to avoid the defaultbehavioroftransactionpromotionsincetheonlyreasontousethiscontainer istousetwodifferentresourcemanagers(messaginganddatabasetypically).Thecommitandrollbacksemanticsaresimple,ifthemessagelistenerdoesnotthrowanexceptionthetransactioniscommitted,otherwiseitisrolledback.ExceptionsinmessagelistenerprocessingarehandledbyimplementationsoftheIDistributedTransactionExceptionHandler interface.Thisinterfaceisshownbelow

publicinterfaceIDistributedTransactionExceptionHandler

{

boolIsPoisonMessage(Messagemessage);

voidHandlePoisonMessage(MessagepoisonMessage);

voidOnException(Exceptionexception,Messagemessage);

}

theIsPoisonMessagemethoddetermineswhethertheincomingmessageis a poison message. This method is called before theIMessageListener is invoked. The container will callHandlePoisonMessage is IsPoisonMessage returns true andwill then commit the distributed transaction (removing the message from thequeue. Typical implementations ofHandlePoisonMessage will move

Page 697: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

the poison message to another queue (under the same distributed transactionused to receive the message). The classSendToQueueDistributedTransactionExceptionHandler

detectspoisonmessagesbytrackingtheMessageIdpropertyinmemorywithacountofhowmanytimesanexceptionhasoccurred.Ifthatcountisgreaterthanthehandler'sMaxRetrycountitwillbesenttoanotherqueue.Thequeuetosend the message to is specified via the propertyMessageQueueObjectName.

Page 698: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

30.4.MessageConverters

30.4.1.UsingMessageConvertersIn order to facilitate the sending of business model objects, theMessageQueueTemplate has various send methods that take a .NETobject as an argument for a message's data content. The overloaded methodsConvertAndSend andReceiveAndConvert inMessageQueue delegate theconversionprocesstoaninstanceoftheIMessageConverterinterface.This interface defines a simple contract to convert between .NET objects andJMSmessages.Theinterfaceisshownbelow

publicinterfaceIMessageConverter:ICloneable

{

MessageToMessage(objectobj);

objectFromMessage(Messagemessage);

}

There are a standard implementations provided the simply wrap existingIMessageFormatterimplementations.

XmlMessageConverter-usesaXmlMessageFormatter.

BinaryMessageConverter-usesaBinaryMessageFormatter

ActiveXMessageConverter-usesaActiveXMessageFormatter

The default implementation used inMessageQueueTemplate and themessagelistenercontainers isaninstanceofXmlMessageConverterconfiguredwith a TargetType to be System.String. You specify the types that theXmlMessageConverter can convert though either the array propertyTargetTypesorTargetTypeNames.HereisanexampletakenfromtheQuickStartapplication

<objectid="xmlMessageConverter"type="Spring.Messaging.Support.Converters.XmlMessageConverter,Spring.Messaging"

<propertyname="TargetTypes">

<list>

<value>Spring.MsmqQuickStart.Common.Data.TradeRequest,Spring.MsmqQuickStart.Common

<value>Spring.MsmqQuickStart.Common.Data.TradeResponse,Spring.MsmqQuickStart.Common

Page 699: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<value>System.String,mscorlib</value>

</list>

</property>

</object>

You can specify otherIMessageConverter implementations using theMessageConverterObjectName property on theMessageQueueTemplateandMessageListenerAdapter.Otherimplementationsprovidedare

XmlDocumentConverter - loads and saves an XmlDocument tothemessageBodyStream.Thisletsyoumanipulatedirectly theXMLdataindependent of type serialization issues. This is quite useful if you useXPath expressions to pick out the relevant information to construct yourbusinessobjects.

Otherpotentialimplementations:

RawBytesMessageConverter - directly write raw bytes to the messagestream,compress

CompressedMessageConverter-compressesthemessagepayload

EncryptedMessageConverter - encrypt the message (standard MSMQencryptionghasseverallimitations)

SoapMessageConverter-usesoapformatting.

Page 700: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

30.5.Interfacebasedmessageprocessing

30.5.1.1.MessageListenerAdapaterTheMessageListenerAdapter allowsmethods of a class that doesnot implement the IMessageListener interface to be invoked uponmessagedelivery.Letscallthisclassthe'messagehandler'class.Toachievethisgoal the MessageListenerAdapter implements the standardIMessageListenerinterfacetoreceiveamessageandthendelegatestheprocessing to themessagehandler class.Since themessagehandler classdoesnot contain methods that refer to MSMQ artifacts such as Message, theMessageListenerAdapter uses a IMessageConverter tobridge the MSMQ and 'plain object' worlds. As a reminder, the defaultXmlMessageConverter used inMessageQueueTemplateandthe message listener containers converts from Message to string. Once theincomingmessageisconvertedtoanobject(stringforexample)amethodwiththename 'HandleMessage' is invokedvia reflectionpassing in the stringas anargument.Using the default configuration of XmlMessageConverter in the messagelisteners,asimplestringbasedmessagehandlerwouldlooklikethis.

publicclassMyHandler

{

publicvoidHandleMessage(stringtext)

{

...

}

}

Thenext examplehas a similarmethod signature but thenameof the handlermethodnamehasbeenchangedto"DoWork",bysettingtheadapter'spropertyDefaultHandlerMethod.

publicinterfaceIMyHandler

{

voidDoWork(stringtext);

Page 701: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

If your IMessageConverter implementation will return multiple object types,overloading the handler method is perfectly acceptable, the most specificmatching method will be used. A method with an object signature would beconsidera'catch-all'methodoflastresort.

publicinterfaceIMyHandler

{

voidDoWork(stringtext);

voidDoWork(OrderRequestorderRequest);

voidDoWork(InvoiceRequestinvoiceRequest);

voidDoWork(objectobj);

}

Anotherof thecapabilitiesof theMessageListenerAdapterclass isthe ability to automatically send back a response Message if a handlermethod returnsanon-voidvalue.Anynon-nullvalue that is returnedfromtheexecutionofthehandlermethodwill(inthedefaultconfiguration)beconvertedto a string.The resulting stringwill then be sent to theResponseQueuedefined in the Message's ResponseQueue property of the originalMessage, or the DefaultResponseQueueName on theMessageListenerAdapter(ifonehasbeenconfigured)willbeused.If not ResponseQueue is found then an SpringMessagingException will be thrown. Please note that this exceptionwillnotbeswallowedandwillpropagateupthecallstack.HereisanexampleofHandlersignaturesthathavevariousreturntypes.

publicinterfaceIMyHandler

{

stringDoWork(stringtext);

OrderResponseDoWork(OrderRequestorderRequest);

InvoiceResponseDoWork(InvoiceRequestinvoiceRequest);

voidDoWork(objectobj);

}

The following configuration shows how to hook up the adapter to processincomingMSMQmessagesusingthedefaultmessageconverter.

Page 702: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--Delegatetoplain.NETobjectformessagehandling-->

<objectid="messageListenerAdapter"type="Spring.Messaging.Listener.MessageListenerAdapter,Spring.Messaging"

<propertyname="DefaultResponseQueueName"value="msmqTestResponseQueue"

<propertyname="HandlerObject"ref="myHandler"/>

</object>

Page 703: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

30.6.ComparisonwithusingWCFThe goals of Spring'sMSMQmessaging support are quite similar to those ofWCFwithitsMSMQrelatedbindings,inasmuchasaWCFservicecontractisaPONO(minustheattributesifyoureallypickyaboutwhatyoucallaPONO).Spring's messaging support can give you the programming convenience ofdealing with PONO contracts for message receiving but does not (at themoment) provide a similar PONO contract for sending, instead relying onexplicit use of the MessageQueueTemplate class. This feature exists - somequestion whether it should for messaging - in the Java version of the Springframework,seeJmsInvokerServiceExporterandJmsInvokerProxyFactoryBean.ThegoodnewsisthatifandwhenitcomestimetomovefromaSpringMSMQsolutiontoWCF,youwillbeinagreatpositionasthePONOinterfaceusedforbusiness processingwhen receiving in a Spring basedMSMQ application caneasily be adapted to a WCF environment. There may also be some featuresunique toMSMQand/orSpring'sMSMQsupport thatyoumayfindappealingoverWCF.Manymessagingapplicationsstillneedtobe'closertothemetal'andthis is not possible using theWCF bindings, for example Peeking and Label,AppSpecific properties,multicast..An interesting recent quote byYoelArnon(MSMQguru)"WithalltherespecttoWCF,System.MessagingisstillthemajorprogrammingmodelforMSMQprogrammers,andisprobablygoingtoremainsignificantfortheforeseeablefuture.Themessage-orientedprogrammingmodelis different from the service-oriented model of WCF, and many real-worldsolutionswouldalwayspreferit."

Page 704: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter31.SchedulingandThreadPooling

Page 705: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

31.1.IntroductionThe Spring Framework features integration classes for scheduling support.Currently, Spring supports the Quartz Scheduler (http://quartznet.sourceforge.net/).TheschedulerissetupusingaIFactoryObjectwithoptionalreferencestoTrigger instances,respectively.Furthermore,aconvenienceclassfortheQuartzSchedulerisavailablethatallowsyoutoinvokeamethodofanexistingtargetobject.

Page 706: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

31.2.UsingtheQuartz.NETSchedulerQuartzusesTrigger,JobandJobDetailobjectstorealizeschedulingof all kinds of jobs. For the basic concepts behind Quartz, have a look athttp://quartznet.sourceforge.net/.Forconveniencepurposes,SpringoffersacoupleofclassesthatsimplifytheusageofQuartzwithinSpring-basedapplications.

31.2.1.UsingtheJobDetailObjectJobDetailobjectscontainallinformationneededtorunajob.TheSpringFrameworkprovidesaJobDetailObjectthatmakestheJobDetaileasiertoconfigureandwithsensibledefaults.Let'shavealookatanexample:

<objectname="ExampleJob"type="Spring.Scheduling.Quartz.JobDetailObject,Spring.Scheduling.Quartz"

<propertyname="JobType"value="Example.Quartz.ExampleJob,Example.Quartz"

<propertyname="JobDataAsMap">

<dictionary>

<entrykey="Timeout"value="5"/>

</dictionary>

</property>

</object>

The job detail object has all information it needs to run the job(ExampleJob).Thetimeout isspecified in the jobdatadictionary.ThejobdatadictonaryisavailablethroughtheJobExecutionContext (passedto you at execution time), but the JobDetailObject also maps thepropertiesfromthejobdatamaptopropertiesoftheactualjob.Sointhiscase,ifthe ExampleJob contains a property named Timeout, theJobDetailObjectwillautomaticallyapplyit:

namespaceExample.Quartz;

publicclassExampleJobextendsQuartzJobObject{

privateinttimeout;

///<summary>

///SettercalledaftertheExampleJobisinstantiated

///withthevaluefromtheJobDetailObject(5)

Page 707: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

///</summary>

publicintTimeout{

set{timeout=value;};

}

protectedoverridevoidExecuteInternal(JobExecutionContextcontext){

//dotheactualwork

}

}

Alladditionalsettingsfromthejobdetailobjectareofcourseavailabletoyouaswell.Note:Usingthenameandgroupproperties,youcanmodify thenameandthegroupof the job, respectively.Bydefault, thenameof the jobmatches theobject name of the job detail object (in the example above, this isExampleJob).

31.2.2. Using theMethodInvokingJobDetailFactoryObject

Often you just need to invoke a method on a specific object. Using theMethodInvokingJobDetailFactoryObject you can doexactlythis:

<objectid="JobDetail"type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject,Spring.Scheduling.Quartz"

<propertyname="TargetObject"ref="ExampleBusinessObject"/>

<propertyname="TargetMethod"value="DoIt"/>

</object>

The above example will result in the doIt method being called on theexampleBusinessObjectmethod(seebelow):

publicclassExampleBusinessObject{

//propertiesandcollaborators

publicvoidDoIt(){

//dotheactualwork

}

Page 708: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

<objectid="ExampleBusinessObject"type="Examples.BusinessObjects.ExampleBusinessObject,Examples.BusinessObjects"

Using the MethodInvokingJobDetailFactoryObject, youdon'tneedtocreateone-linejobsthatjustinvokeamethod,andyouonlyneedtocreatetheactualbusinessobjectandwireupthedetailobject.By default, Quartz Jobs are stateless, resulting in the possibility of jobsinterfering with each other. If you specify two triggers for the sameJobDetail, itmight be possible that before the first job has finished, thesecond one will start. IfJobDetail classes implement theStatefulinterface,thiswon'thappen.Thesecondjobwillnotstartbeforethefirstonehasfinished. To make jobs resulting from theMethodInvokingJobDetailFactoryObject non-concurrent,settheconcurrentflagtofalse.

<objectid="JobDetail"type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject,Spring.Scheduling.Quartz"

<propertyname="TargetObject"ref="ExampleBusinessObject"/>

<propertyname="TargetMethod"value="DoIt"/>

<propertyname="Concurrent"value="false"/>

</object>

Note

Bydefault,jobswillruninaconcurrentfashion.AlsonotethatwhenusingMethodInvokingJobDetailFactoryObjectyoucan'tusedatabasepersistenceforJobs.Seetheclassdocumentationforadditionaldetails.

31.2.3. Wiring up jobs using triggers and theSchedulerFactoryObject

We'vecreated jobdetails and jobs.We've also reviewed the convenienceclassthatallowstoyouinvokeamethodonaspecificobject.Ofcourse,westillneedto schedule the jobs themselves. This is done using triggers and aSchedulerFactoryObject. Several triggers are available withinQuartz. Spring offers two subclassed triggers with convenient defaults:

Page 709: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

CronTriggerObjectandSimpleTriggerObjectTriggers need to be scheduled. Spring offers aSchedulerFactoryObject that exposes triggers to be set asproperties.SchedulerFactoryObject schedules theactual jobswiththosetriggers.Findbelowacoupleofexamples:

<objectid="SimpleTrigger"type="Spring.Scheduling.Quartz.SimpleTriggerObject,Spring.Scheduling.Quartz"

<!--seetheexampleofmethodinvokingjobabove-->

<propertyname="JobDetail"ref="ExampleJob"/>

<!--10seconds-->

<propertyname="StartDelay"value="10s"/>

<!--repeatevery50seconds-->

<propertyname="RepeatInterval"value="50s"/>

</object>

<objectid="CronTrigger"type="Spring.Scheduling.Quartz.CronTriggerObject,Spring.Scheduling.Quartz"

<propertyname="JobDetail"ref="ExampleJob"/>

<!--runeverymorningat6AM-->

<propertyname="CronExpressionString"value="006**?"

</object>

Nowwe've set up two triggers, one running every 50 secondswith a startingdelayof10secondsandoneeverymorningat6AM.Tofinalizeeverything,weneedtosetuptheSchedulerFactoryObject:

<objectid="quartzSchedulerFactory"type="Spring.Scheduling.Quartz.SchedulerFactoryObject,Spring.Scheduling.Quartz"

<propertyname="triggers">

<list>

<refobject="CronTrigger"/>

<refobject="SimpleTrigger"/>

</list>

</property>

</object>

MorepropertiesareavailablefortheSchedulerFactoryObjecctfor

Page 710: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

youtoset,suchasthecalendarsusedbythejobdetails,propertiestocustomizeQuartz with, etc. Have a look at the SchedulerFactoryObject SDK docs for moreinformation.

Page 711: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PartVI.VS.NETIntegrationThis part of the reference documentation covers the Spring Framework'sintegrationwithVS.NET

Chapter32,VisualStudio.NETIntegration

Page 712: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter32.VisualStudio.NETIntegration

Page 713: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

32.1.XMLEditingandValidationMost of this section is well travelled territory for those familiar with editingXML files in their favorite XML editor. The XML configuration data thatdefines the objects that Spring will manage for you are validated against theSpring.NETXMLSchema at runtime.The location of theXMLconfigurationdata to create anIApplicationContext can be any of the resourcelocations supported by Spring's IResource abstraction. (See Section 7.1,“Introduction”formoreinformation.)TocreateanIApplicationContextusinga"standalone"XMLconfigurationfilethecustomconfigurationsectioninthestandard.NETapplicationconfigurationwouldread:

<spring>

<context>

<resourceuri="file://objects.xml"/>

</context>

</spring>

The VS.NET 2005 XML editor can use the attributexsi:schemaLocationasahinttoassociatethephysicallocationof a schema file with the XML document being edited. VS.NET2002/2003 do not recognize thexsi:schemaLocation element.Ifyou reference theSpring.NETXMLschemaasshownbelow,youcan get intellisense and validation support while editing a SpringconfigurationfileinVS.NET2005.InordertogetthisfunctionalityinVS.NET 2002/2003 you will need to register the schema withVS.NETorincludetheschemaaspartofyourapplicationproject.

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.nethttp://www.springframework.net/xsd/spring-objects.xsd"

<objectid="..."type="...">

...

</object>

Page 714: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="..."type="...">

...

</object>

...

</objects>

It is typically more convenient to install the schema in VS.NET, even forVS.NET2005, as itmakes thexml a little less verbose andyoudon't need tokeep copying theXSD file for eachproject you create.ForVS.NET2003 theschemadirectorywillbeeitherC:\Program Files\Microsoft Visual Studio .NET

2003\Common7\Packages\schemas\xmlforVS2003orC:\Program Files\Microsoft Visual Studio

.NET\Common7\Packages\schemas\xmlforVS.NET2002TheVS.NET2005directoryforXMLschemasisC:\Program Files\Microsoft Visual Studio

8\Xml\Schemas

Spring's.xsdschemasarelocatedinthedirectorydoc/schema.Inthatdirectoryis also a NAnt build file to help copy over the .xsd files to the appropriateVS.NETlocations.Toexecutethisscriptsimplytype'nant'inthedoc/schemadirectory.Once you have registered the schema with VS.NET you can adding only thenamespacedeclarationtotheobjectselement,

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net">

<objectid="..."type="...">

...

</object>

<objectid="..."type="...">

...

</object>

...

</objects>

Page 715: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Onceregistered,thenamespacedeclarationaloneissufficienttogetintellisenseandvalidationoftheconfigurationfilefromwithinVS.NET.Alternatively,youcan select the .xsd file to use by setting the targetSchema property in thePropertySheetfortheconfigurationfile.As shown in the section Section 5.2.6, “Using the container” Spring.NET supportsusing .NET's application configuration file as the location to store the objectdefinitionsthatwillbemanagedbytheobjectfactory.

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<context>

<resourceuri="config://spring/objects"/>

</context>

<objectsxmlns="http://www.springframework.net">

...

</objects>

</spring>

</configuration>

InthiscaseVS.NET2002/2003willstillprovideyouwithintellisensehelpbutyou will not be able to fully validate the document as the entire schema forApp.configisnotknown.Tobeabletovalidatethisdocumentonewouldneedto install the .NET Configuration File schema and an additional schema thatincorporates the <spring> and <context> section in addition to the<objects>wouldneedtobecreated.ValidatingschemaisanewfeatureinVS2005itisvalidatingallthetimewhile

Page 716: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

youedit,youwillseeanyerrorsthatitfindsintheErrorListwindow.Keep these trade offs inmind as you decidewhere to place the bulk of yourconfiguration information. Conventional wisdom is do quick prototypingwithApp.config and use another IResource location, file or embedded assemblyresource,forseriousdevelopment.

Page 717: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

32.2.VersionsofXMLSchemaTheschemawasupdatedfromSpring1.0.1to1.0.2inordertosupportgenerics.The schema for version 1.0.1 is located underhttp://www.springframework.net/xsd/1.0.1/ Theschema for the latest version will always be located underhttp://www.springframework.net/xsd/

Page 718: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

32.3.IntegratedAPIhelpSpringprovidesAPIdocumentationthatcanbeintegratedwithinVisualStudio.There are twoversionsof thedocumentation, one forVS.NET2002/2003andtheotherforVS2005.Theydifferonlyintheformatapplied,VS2005usingthesexynewformat.Enjoy!

Page 719: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PartVII.QuickstartapplicationsThis part of the reference documentation covers the quickstart applicationsincludedwithSpringthatdemonstratefeaturesinacodecentricmanner.

Chapter33,IoCQuickstarts

Chapter34,AOPGuide

Chapter35,PortableServiceAbstractionQuickStart

Chapter36,WebQuickstarts

Chapter37,SpringAir-ReferenceApplication

Chapter38,DataAccessQuickStart

Chapter39,TransactionsQuickStart

Chapter40,NHibernateQuickStart

Chapter41,QuartzQuickStart

Chapter42,NMSQuickStart

Chapter43,MSMQQuickStart

Chapter44,WCFQuickStart

Page 720: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter33.IoCQuickstarts

Page 721: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

33.1.IntroductionThis chapter includes a grab bag of quickstart examples for using theSpring.NETframework.

Page 722: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

33.2.MovieFinderThesourcematerialforthissimpledemonstrationofSpring.NET'sIoCfeaturesis lifted straight from Martin Fowler's article that discussed the ideasunderpinning the IoCpattern.See Inversion ofControl Containers and theDependencyInjection pattern for more information. Themotivation for basing this quickstartexampleonsaidarticleisbecausethearticleisprettywidelyknown,andmostpeople who are looking at IoC for the first time typically will have read thearticle(atthetimeofwritingasimpleGooglesearchfor'IoC'yieldsthearticleinthefirstfiveresults).Fowler'sarticleusedtheexampleofasearchfacilityformoviestoillustrateIoCandDependencyInjection(DI).ThearticledescribedhowaMovieListerobject might receive a reference to an implementation of theIMovieFinderinterface(usingDI).

TheIMovieFinderreturnsalistofallmoviesandtheMovieListerfilters this list to return an array of Movieobjects that match a specifieddirectorsname.ThisexampledemonstrateshowtheSpring.NETIoCcontainercanbeusedtosupplyanappropriateIMovieFinderimplementationtoanarbitraryMovieListerinstance.The C# code listings for the MovieFinder application can be found in theexamples/Spring/Spring.Examples.MovieFinder

directoryoffthetopleveldirectoryoftheSpring.NETdistribution.

33.2.1.GettingStarted-MovieFinderThestartupclassfortheMovieFinderexampleistheMovieAppclass,whichisanordinary.NETclasswithasingleapplicationentrypoint...

Page 723: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

usingSystem;

namespaceSpring.Examples.MovieFinder

{

publicclassMovieApp

{

publicstaticvoidMain()

{

}

}

}

Whatwewanttodoisgetareferencetoaninstanceof theMovieListerclass... since this is a Spring.NET example we'll get this reference fromSpring.NET's IoC container, theIApplicationContext. There are anumber of ways to get a reference to an IApplicationContextinstance,butforthisexamplewe'llbeusinganIApplicationContextthat is instantiated from a custom configuration section in a standard .NETapplicationconfigfile...

<?xmlversion="1.0"encoding="utf-8"?>

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<context>

<resourceuri="config://spring/objects"/>

</context>

<objectsxmlns="http://www.springframework.net">

<description>AnexamplethatdemonstratessimpleIoCfeatures.

</objects>

</spring>

</configuration>

Theobjects thatwill beused in theexampleapplicationwillbe configured asXML<object/>elementsnestedinsidethe<objects/>element.

Page 724: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Thebodyof theMainmethod in theMovieApp classcannowbe fleshedoutalittlefurther...

usingSystem;

usingSpring.Context;

...

publicstaticvoidMain()

{

IApplicationContextctx=ContextRegistry.GetContext();

}

...

AscanbeseenintheaboveC#snippet,ausingstatementhasbeenaddedtothe MovieApp source. The Spring.Context namespace gives theapplicationaccesstotheIApplicationContextclassthatwillserveastheprimarymeans for the application to access the IoCcontainer.The lineofcode...

IApplicationContextctx=ContextRegistry.GetContext();

... retrieves a fully configuredIApplicationContext implementationthat has been configured using the named<objects/> section from theapplicationconfigfile.

33.2.2.FirstObjectDefinitionAsyet,noobjectshavebeendefinedintheapplicationconfigfile,solet'sdothatnow.TheverymiminalXMLdefinitionfortheMovieListerinstancethatwe are going to use in the application can be seen in the following XMLsnippet...

<objectsxmlns="http://www.springframework.net">

<objectname="MyMovieLister"

type="Spring.Examples.MovieFinder.MovieLister,Spring.Examples.MovieFinder"

</object>

</objects>

Noticethatthefull,assembly-qualifiednameoftheMovieListerclasshas

Page 725: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

been specified in the type attribute of the object definition, and that thedefinitionhasbeenassignedthe(unique)idofMyMovieLister.Usingthisid, an instance of the object so defined can be retrieved from theIApplicationContextreferencelikeso...

...

publicstaticvoidMain()

{

IApplicationContextctx=ContextRegistry.GetContext();

MovieListerlister=(MovieLister)ctx.GetObject("MyMovieLister"

}

...

Thelister instance has not yet had an appropriate implementation of theIMovieFinder interface injected into it. Attempting to use theMoviesDirectedBy method will most probably result in a nastyNullReferenceExceptionsincethelister instancedoesnotyethave a reference to an IMovieFinder. The XML configuration for theIMovieFinder implementation that is going to be injected into thelisterinstancelookslikethis...

<objectsxmlns="http://www.springframework.net">

<objectname="MyMovieFinder"

type="Spring.Examples.MovieFinder.SimpleMovieFinder,Spring.Examples.MovieFinder"

</object>

</objects>

33.2.3.SetterInjectionWhatwewanttodoisinjecttheIMovieFinderinstanceidentifiedbytheMyMovieFinder id into theMovieLister instance identified by theMyMovieListerid,whichcanbeaccomplishedusingSetterInjectionandthefollowingXML...

<objectsxmlns="http://www.springframework.net">

<objectname="MyMovieLister"

type="Spring.Examples.MovieFinder.MovieLister,Spring.Examples.MovieFinder"

Page 726: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--usingsetterinjection...-->

<propertyname="movieFinder"ref="MyMovieFinder"/>

</object>

<objectname="MyMovieFinder"

type="Spring.Examples.MovieFinder.SimpleMovieFinder,Spring.Examples.MovieFinder"

</object>

</objects>

WhentheMyMovieListerobjectisretrievedfrom(i.e.instantiatedby)theIApplicationContext in the application, the Spring.NET IoCcontainerwill inject the reference to theMyMovieFinder object into theMovieFinder property of the MyMovieLister object. TheMovieLister object that is referenced in the application is then fullyconfiguredandreadytobeusedintheapplicationtodowhatisdoesbest...listmoviesbydirector.

...

publicstaticvoidMain()

{

IApplicationContextctx=ContextRegistry.GetContext();

MovieListerlister=(MovieLister)ctx.GetObject("MyMovieLister"

Movie[]movies=lister.MoviesDirectedBy("RobertoBenigni"

Console.WriteLine("\nSearchingformovie...\n");

foreach(Moviemovieinmovies)

{

Console.WriteLine(

string.Format("MovieTitle='{0}',Director='{1}'."

movie.Title,movie.Director));

}

Console.WriteLine("\nMovieAppDone.\n\n");

}

...

TohelpensurethattheXMLconfigurationoftheMovieListerclassmustspecifyavaluefortheMovieFinderproperty,youcanaddthe[Required]attributetotheMovieLister's MovieFinder property. The example code shows uses thisattribute. For more information on using and configuring the [Required]attribute,refertothissectionofthereferencedocumentation.

Page 727: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

33.2.4.ConstructorInjectionLet'sdefineanotherimplementationoftheIMovieFinder interfaceintheapplicationconfigfile...

...

<objectname="AnotherMovieFinder"

type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder,Spring.Examples.MovieFinder"

</object>

...

ThisXMLsnippetdescribesanIMovieFinderimplementationthatusesacolondelimitedtextfileasit'smoviesource.TheC#sourcecodeforthisclassdefines a single constructor that takes aSystem.IO.FileInfo as it'ssingle constructor argument. As this object definition currently stands,attempting to get this object out of theIApplicationContext in theapplicationwithalineofcodelikeso...

IMovieFinderfinder=(IMovieFinder)ctx.GetObject("AnotherMovieFinder"

will result in a fatalSpring.Objects.Factory.ObjectCreationException,because theSpring.Examples.MovieFinder.ColonDelimitedMovieFinder

classdoesnothaveadefaultconstructorthattakesnoarguments.Ifwewanttouse this implementation of theIMovieFinder interface,wewill have tosupplyanappropriateconstructorargument...

...

<objectname="AnotherMovieFinder"

type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder,Spring.Examples.MovieFinder"

<constructor-argindex="0"value="movies.txt"/>

</object>

...

Unsurprisingly, the <constructor-arg/> element is used to supply constructorarguments to the constructors of managed objects. The Spring.NET IoCcontainer uses the functionality offered by

Page 728: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

System.ComponentModel.TypeConverter specializations toconvert the movies.txt string into an instance of theSystem.IO.FileInfo that is required by the single constructor of theSpring.Examples.MovieFinder.ColonDelimitedMovieFinder

(see Section 6.3, “Type conversion” for a more in depth treatment concerning theautomatictypeconversionfunctionalityofferedbySpring.NET).SonowwehavetwoimplementationsoftheIMovieFinderinterfacethathavebeendefinedasdistinctobjectdefinitionsintheconfigfileoftheexampleapplication; if we wanted to, we could switch the implementation that theMyMovieListerobjectuseslikeso...

...

<objectname="MyMovieLister"

type="Spring.Examples.MovieFinder.MovieLister,Spring.Examples.MovieFinder"

<!--letsusethecolondelimitedimplementationinstead-->

<propertyname="movieFinder"ref="AnotherMovieFinder"/>

</object>

<objectname="MyMovieFinder"

type="Spring.Examples.MovieFinder.SimpleMovieFinder,Spring.Examples.MovieFinder"

</object>

<objectname="AnotherMovieFinder"

type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder,Spring.Examples.MovieFinder"

<constructor-argindex="0"value="movies.txt"/>

</object>

...

Note that there isnoneed to recompile theapplication toeffect thischangeofimplementation...simplychangingtheapplicationconfigfileandthenrestartingtheapplicationwill result in theSpring.NET IoCcontainer injecting the colondelimited implementation of the IMovieFinder interface into theMyMovieListerobject.

33.2.5.SummaryThisexampleapplication isquite simple, andadmittedly itdoesn't doawholelot. Itdoeshoweverdemonstrate thebasicsofwiring together anobjectgraphusinganintuitiveXMLformat.Thesesimplefeatureswillgetyouthroughprettymuch 80% of your object wiring needs. The remaining 20% of the available

Page 729: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

configurationoptionsare there to cover corner cases such as factorymethods,lazyinitialization,andsuchlike(alloftheconfigurationoptionsaredescribedindetailintheChapter5,TheIoCcontainer).

33.2.6.LoggingOftenenoughthefirstuseofSpring.NETisalsoafirstintroductiontolog4net.Tokickstartyourunderstandingoflog4netthissectiongivesaquickoverview.The authoritative place for information on log4net is the log4net website. Othergoodonline tutorials areUsing log4net (OnDotNet article) andQuick andDirtyGuide toConfiguringLog4NetForWebApplications.Spring.NETisusingversion1.2.9whereasmostofthedocumentationoutthereisforversion1.2.0.Therehavebeensomechanges between the two so always double check at the log4net web site fordefinitive information.Alsonote thatwe are investigatingusing a "commons"logginglibrarysothatSpring.NETwillnotbeexplicitytiedtolog4netbutwillbe able to use other logging packages such asNLog andMicrosoft enterpriseloggingapplicationblock.The general usage pattern for log4net is to configure your loggers, (either inApp/Web.configora seperate file), initialize log4net inyourmainapplication,declaresomeloggersincode,andthenlogloglog.(Singalong...)WeareusingApp.config to configure the loggers. As such, we declare the log4netconfigurationsectionhandlerasshownbelow

<sectionname="log4net"type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"

Thecorrespondingconfigurationsectionlookslikethis

<log4net>

<appendername="ConsoleAppender"type="log4net.Appender.ConsoleAppender"

<layouttype="log4net.Layout.PatternLayout">

<conversionPatternvalue="%date[%thread]%-5level%logger-%message%newline"

</layout>

</appender>

<!--SetdefaultloggingleveltoDEBUG-->

<root>

<levelvalue="DEBUG"/>

<appender-refref="ConsoleAppender"/>

</root>

Page 730: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--SetloggingforSpringtoINFO.LoggernamesinSpringcorrespondtothenamespace-->

<loggername="Spring">

<levelvalue="INFO"/>

</logger>

</log4net>

The appender is the output sink - in this case the console. There are a largevarietyofoutput sinks suchas files,databases, etc.Refer to the log4netConfigExamples formore information. Of interest aswell is the PatternLayoutwhichdefinesexactlytheinformationandformatofwhatgets logged.Usually this isthedate, thread, logging level, loggername, and then finally the logmessage.RefertoPatternLayoutDocumentationforinformationonhowtocustomize.Theloggingnameisuptoyoutodecidewhenyoudeclaretheloggerincode.Inthecaseofthisexampleweusedtheconventionofgivingtheloggingnamethenameofthefullyqualifiedclassname.

privatestaticreadonlyILogLOG=LogManager.GetLogger(typeof

Otherconventionsaretogivethesameloggernameacrossmultipleclassesthatconstitutealogicalcomponentorsubsystemwithintheapplication,forexamplea data access layer. One tip in selecting the pattern layout is to shorten thelogging name to only the last 2 parts of the fully qualified name to avoid themessagesneakingofftotherighttoomuch(wherecan'tseeit)becauseofalltheotherinformationloggedthatprecedes it.Shorteningthe loggingnameisdoneusingtheformat%logger{2}.Toinitializetheloggingsystemaddthefollowingtothestartofyourapplication

XmlConfigurator.Configure();

Notethatifyouareusingorreadinginformationonversion1.2.0thisusedtobecalledDOMConfigurator.Configure();The loggersectionsassociate loggernameswith logging levelsandappenders.Youhavegreatflexibilitytomixandmatchnames,levels,andappenders.Inthiscasewe have defined the root logger (using the special tag root) to be at thedebuglevelandhaveanconsolesink.Wecanthenspecializeotherloggerswith

Page 731: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

differentsetting.Inthiscase, loggers thatstartwith"Spring" in theirnamearelogged at the info level and also sent to the console. Setting the value of thisloggerfromINFOtoDEBUGwillshowyoudetailedlogginginformationastheSpring container goes about its job of creating and configuring your objects.Coincidentally, theexamplecode itselfusesSpring in the loggername, so thislogger also controls the output level you see from runningMainApp. Finally,youarereadytousethesimpleloggerapitolog,i.e.

LOG.Info("Searchingformovie...");

Loggingexceptionsisanothercommontask,whichcanbedoneusingtheerrorlevel

try{

//dowork

{

catch(Exceptione)

{

LOG.Error("MovieFinderisbroken.",e);

}

Page 732: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

33.3.ApplicationContextandIMessageSource

33.3.1.IntroductionThe example program Spring.Examples.AppContext shows theuseoftheapplicationcontextfortextlocalization,retrievingobjectscontainedinResourceSets, and applying the values of embedded resource properties to anobject.Thevaluesthatareretrievedaredisplayedinawindow.Theapplicationcontextconfigurationfilecontainsanobjectdefinitionwiththename messageSource of the typeSpring.Context.Support.ResourceSetMessageSource

whichimplementstheinterfaceIMessageSource.Thisinterfaceprovidesvariousmethods for retrieving localized resources such as text and images asdescribed in Section 5.12.2, “Using IMessageSource”. When creating an instance ofIApplicationContext, an objectwith the name 'messageSource' is searched forandusedastheimplementationforthecontext'sIMessageSourcefunctionality.TheResourceSetMessageSource takesa listofResourceManagerstodefinethecollectionofculture-specificresources.TheResourceManagercanbe contructed in two ways. The first way is to specifying a two part stringconsisting of the base resource name and the containing assembly. In thisexample there is an embedded resource file, Images.resx in the project. Thesecond way is to use helper factory classResourceManagerFactoryObjectthattakesaresourcebasenameand assembly name as properties. This second way of specifying aResourceManager is useful if you would like direct access to theResourceManagerinotherpartsofyourapplication.Intheexampleprogramanembedded resource file,MyResource.resxandaSpanishspecific resource file,MyResources.es.resx are declared in this manner. The corresponding XMLfragmentisshownbelow

...

<objectname="messageSource"type="Spring.Context.Support.ResourceSetMessageSource,Spring.Core"

<propertyname="resourceManagers">

<list>

<value>Spring.Examples.AppContext.Images,Spring.Examples.AppContext

<refobject="myResourceManager"/>

</list>

Page 733: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</property>

</object>

<objectname="myResourceManager"type="Spring.Objects.Factory.Config.ResourceManagerFactoryObject,Spring.Core"

<propertyname="baseName">

<value>Spring.Examples.AppContext.MyResource</value>

</property>

<propertyname="assemblyName">

<value>Spring.Examples.AppContext</value>

</property>

</object>

...

Themainapplicationcreates theapplicationcontextand then retrievesvariousresources via their key names. In the code all the key names are declared asstatic fields in theclassKeys.The resource file Images.resxcontains imagedata under the key name bubblechamber (akaKeys.BUBBLECHAMBER). The code Image image =

(Image)ctx.GetResourceObject(Keys.BUBBLECHAMBER);

is used to retrieve the image from the context. The resource filesMyResource.resxcontainsatextresource,Hello{0}{1}underthekeynameHelloMessage(akaKeys.HELLO_MESSAGE)thatcanbeusedforstringtextformattingpurposes.Theexamplecode

stringmsg=ctx.GetMessage(Keys.HELLO_MESSAGE,

CultureInfo.CurrentCulture,

"Mr.","Anderson");

retrieves the text string and replaces the placeholders in the string with thepassedargumentvaluesresultinginthetext,"HelloMr.Anderson".ThecurrentcultureisusedtoselecttheresourcefileMyResource.resx.IfinsteadtheSpanishcultureisspecified

CultureInfospanishCultureInfo=newCultureInfo("es");

stringesMsg=ctx.GetMessage(Keys.HELLO_MESSAGE,

spanishCultureInfo,

"Mr.","Anderson");

Then theresourcefileMyResource.es.resx isused insteadas instandard .NET

Page 734: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

localization.Springissimplydelegatingto.NETResourceManagertoselecttheappropriatelocalizedresource.TheSpanishversionoftheresourcediffersfromthe English one in that the text under the keyHelloMessage isHola{0}{1}resultinginthetext"HolaMr.Anderson".Asyoucanseeinthisexample,thetitle"Mr."shouldnotbeusedinthecaseofthe spanish localization.The title can be abstracted out into a key of its own,called FemaleGreeting (aka Keys.FEMALE_GREETING). Thereplacementvalueforthemessageargument{0}canthenbemadelocalizationawarebywrapping thekey ina convenience classDefaultMessageResolvable.Thecode

string[]codes={Keys.FEMALE_GREETING};

DefaultMessageResolvabledmr=newDefaultMessageResolvable(codes,

msg=ctx.GetMessage(Keys.HELLO_MESSAGE,

CultureInfo.CurrentCulture,

dmr,"Anderson");

will assign msg the value, Hello Mrs. Anderson, since the value for the keyFemaleGreetinginMyResource.resxis'Mrs.'Similarly,thecode

esMsg=ctx.GetMessage(Keys.HELLO_MESSAGE,

spanishCultureInfo,

dmr,"Anderson");

willassignesMsgthevalue,HolaSenoraAnderson,sincethevalueforthekeyFemaleGreetinginMyResource.es.resxis'Senora'.Localization can also apply to objects and not just strings. The .NET 1.1frameworkprovidestheutilityclassComponentResourceManagerthatcanapplymultipleresourcevaluestoobjectpropertiesinaperformantmanner. (VS.NET2005 makes heavy use of this class in the code it generates for winformapplications.) The example program has a simple class, Person, that has anintegerpropertyAgeandastringpropertyName.Theresourcefile,Person.resxcontainskeynamesthatfollowthepattern,person.<PropertyName>.Inthiscaseit contains person.Name and person.Age. The code to assign these resourcevaluestoanobjectisshownbelow

Page 735: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Personp=newPerson();

ctx.ApplyResources(p,"person",CultureInfo.CurrentUICulture);

WhileyoucouldalsousetheSpringitselftosetthepropertiesoftheseobjects,the configuration of simple properties using Springwill not take into accountlocalization. It may be convenient to combine approaches and use Spring toconfigurethePerson'sobjectreferenceswhileusingIApplicationContextinsideanAfterPropertiesSetcallback(seeIInitializingObject)tosetthePerson'scultureawareproperties.

Page 736: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

33.4.ApplicationContextandIEventRegistry

33.4.1.IntroductionThe example programSpring.Examples.EventRegistry showshow to use the application context to wire .NET events in a loosely coupledmanner.Loosely coupled eventing is normally associated with Message OrientedMiddleware(MOM)whereadaemonprocessactsasamessagebrokerbetweenotherindependentprocesses.Processescommunicateindirectlywitheachotherbysendingmessages though themessagebroker.Theprocess that initiates thecommunication is known as a publisher and the process that receives themessageisknownasthesubscriber.ByusinganAPIspecifictothemiddlewaretheseprocesses register themselvesaseitherpublishersor subscriberswith themessage broker. The communication between the publisher and subscriber isconsidered loosely coupled because neither the publisher nor subscriber has adirect reference to each other, the messages broker acts as an intermediarybetween the twoprocesses.TheIEventRegistry is theanalogueof themessagebrokerasapplied to .NETevents.Publishersareclasses that invokea.NETevent,subscribersaretheclassesthatregisterinterestintheseevents,andthe messages sent between them are instances of System.EventArgs. TheimplementationofIEventRegistrydeterminestheexactsemanticsofthenotificationstyleandcouplingbetweensubscribersandpublishers.The IApplicationContext interface extends theIEventRegistry interface and implementations ofIApplicationContext delegate the event registry functionality to aninstance ofSpring.Objects.Events.Support.EventRegistry.IEventRegistry is a simple intefacewithonepublishmethod and twosubscribemethods.RefertoSection5.12.4,“Looselycoupledevents”forareminderoftheir signatures. TheSpring.Objects.Events.Support.EventRegistry

implementationisessentiallyaconveniencetodecoupletheeventwiringprocessbetweenpublisherandsubscribers.Inthisimplementation,aftertheeventwiringis finished, publishers are directly coupled to the subscribers via the standard

Page 737: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

.NET eventing mechanisms. Alternate implementations could increase thedecoupling furtherbyhaving the event registry subscribe to the events andberesponsibleforthennotifyingthesubscribers.In this example the class MyClientEventArgs is a subclass ofSystem.EventArgs that defines a string property EventMessage. Theclass MyEventPublisher defines a public event with the delegatesignature void SimpleClientEvent( object sender,

MyClientEventArgs args ) The method void

ClientMethodThatTriggersEvent1() fires this event. On thesubscribing side, the class MyEventSubscriber contains a method,HandleClientEvents that matches the delegate signature and has abooleanpropertywhichissettotrueifthismethodiscalled.The publisher and subscriber classes are defined in an application contextconfiguration filebut that isnot required inorder toparticipatewith theeventregistry.Themainprogram,EventRegistryApp creates the applicationcontextandasksitforaninstanceofMyEventPublisherThepublisherisregisteredwith theeventregistryvia thecall,ctx.PublishEvents(publisher). The event registry keeps a reference to this publisher forlater use to register any subscribers that match its event signature. Twosubscribersarethencreatedandoneofthemiswiredtothepublisherbycallingthe method ctx.Subscribe( subscriber,

typeof(MyEventPublisher)) Specifying the type indicates thatthe subscriber should be registered only to events from objects of the typeMyEventPublisher. This acts as a simple filtering mechanism on thesubscriber.Thepublisherthenfirestheeventusingnormal.NETeventingsemanticsandthesubscriber is called.The subscriber prints amessage to the console and sets astatevariabletoindicateithasbeencalled.Theprogramthensimplyprintsthestatevariableofthetwosubscribers,showingthatonlyoneofthem(theonethatregisteredwiththeeventregistry)wascalled.

Page 738: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

33.5.PoolingexampleThe idea is to build an executor backedby a pool ofQueuedExecutor:this will show how Spring.NET provides some useful low-level/high-qualityreusablethreadingandpoolingabstractions.Thisexecutorwillprovideparallelexecutions(inourcasegrep-likefilescans).Note:Thisexampleisnotinthe1.0.0releasetoitsuseofclassesintheSpring.Threadingnamespacescheduledforrelease inSpring1.1.Toaccess thsexamplepleaseget thecode fromCVS(instructions)orfromthedownloadsectionoftheSpring.NETwebsitethatcontainsan.zipwiththefullCVStree.SomeinformationonQueuedExecutorishelpfultobetterunderstandtheimplementationandtopossiblydisagreewithit.Keepinmindthatthepointistoshowhowtodevelopyourownobject-pool.AQueuedExecutorisanexecutorwhereIRunnableinstancesarerunserialy by a worker thread. When you Execute with aQueuedExecutor,yourrequestisqueued;atsomepointinthefutureyourrequestwill be taken and executed by theworker thread: in case of error thethread is terminated. However this executor recreates its worker thread asneeded.Lastbutnotleast,thisexecutorcanbeshutdowninafewdifferentways(pleaserefer to the Spring.NET SDK documentation). Given its simplicity, it is verypowerful.The example project Spring.Examples.Pool provides animplementation of a pooled executor, backed by n instances ofSpring.Threading.QueuedExecutor:pleaseignorethefactthatSpring.Threading includesalreadyaverydifferent implementationofa PooledExecutor: here we wanto to use a pool ofQueuedExecutors.

Thisexecutorwillbeusedtoimplementaparallelrecursivegrep-likeconsoleexecutable.

33.5.1. ImplementingSpring.Pool.IPoolableObjectFactory

Inorder touse theSimplePool implementation, the first thing todo is to

Page 739: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

implement theIPoolableObjectFactory interface.This interface isintended to be implementedbyobjects that can create the type of objects thatshould be pooled. The SimplePool will call the lifecycle methods onIPoolableObjectFactory interface (MakeObject,ActivateObject, ValidateObject,

PassivateObject,andDestroyObject)asappropriatewhenthepooliscreated,objectsareborrowedandreturnedtothepool,andwhenthepoolisdestroyed.In our case, as already said, we want to to implement a pool ofQueuedExecutor.Ok,herethedeclaration:

publicclassQueuedExecutorPoolableFactory:IPoolableObjectFactory

{

thefirsttaskafactoryshoulddoistocreateobjects:

objectIPoolableObjectFactory.MakeObject()

{

//toactuallymakethisworkasapooledexecutor

//useaboundedqueueofcapacity1.

//Ifwedon'tdothisoneofthequeuedexecutors

//willacceptallthequeuedIRunnablesas,bydefault

//itsqueueisunbounded,andthePooledExecutor

//willhappentoalwaysrunonlyonethread...

returnnewQueuedExecutor(newBoundedBuffer(1));

}

andshouldbealsoabletodestroythem:

voidIPoolableObjectFactory.DestroyObject(objecto)

{

//ah,selfdocumentingcode:

//Hereyoucanseethatwedecidedtoletthe

//executorprocessallthecurrentlyqueuedtasks.

QueuedExecutorexecutor=oasQueuedExecutor;

executor.ShutdownAfterProcessingCurrentlyQueuedTasks();

}

Whenanobject is taken from thepool, to satisfy a client request,maybe the

Page 740: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

objectshouldbeactivated.Wecanpossiblyimplementtheactivationlikethis:

voidIPoolableObjectFactory.ActivateObject(objecto)

{

QueuedExecutorexecutor=oasQueuedExecutor;

executor.Restart();

}

even if a QueuedExecutor restarts itself as needed and so a validimplementationcouldleavethismethodempty.Afteractivation,andbeforethepooledobjectcanbesuccesfullyreturnedtotheclient,itisvalidated(shouldtheobjectbeinvalid,itwillbediscarded:thiscanleadtoanemptyunusablepool[5]).Herewecheckthattheworkerthreadexists:

boolIPoolableObjectFactory.ValidateObject(objecto)

{

QueuedExecutorexecutor=oasQueuedExecutor;

returnexecutor.Thread!=null;

}

Passivation,symmetricaltoactivation,istheprocessapooledobjectissubjecttowhentheobjectisreturnedtothepool.Inourcasewesimplydonothing:

voidIPoolableObjectFactory.PassivateObject(objecto)

{

}

Atthispoint,creatingapoolissimplyamatterofcreatinganSimplePoolasin:

pool=newSimplePool(newQueuedExecutorPoolableFactory(),size);

33.5.2.BeingsmartusingpooledobjectsTakingadvantageoftheusingkeywordseemstobeveryimportant in thesec# days, so we implement a very simple helper(PooledObjectHolder)thatcanallowustodothingslike:

Page 741: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

using(PooledObjectHolderholder=PooledObjectHolder.UseFrom(pool))

{

QueuedExecutorexecutor=(QueuedExecutor)holder.Pooled;

executor.Execute(runnable);

}

withoutworryingaboutobtainingandreturninganobjectfrom/tothepool.Hereistheimplementation:

publicclassPooledObjectHolder:IDisposable

{

IObjectPoolpool;

objectpooled;

///<summary>

///Buildsanew<seecref="PooledObjectHolder"/>

///tryingtoborrowanobjectformit

///</summary>

///<paramname="pool"></param>

privatePooledObjectHolder(IObjectPoolpool)

{

this.pool=pool;

this.pooled=pool.BorrowObject();

}

///<summary>

///Allowtoaccesstheborrowedpooledobject

///</summary>

publicobjectPooled

{

get

{

returnpooled;

}

}

///<summary>

///Returnstheborrowedobjecttothepool

///</summary>

publicvoidDispose()

{

Page 742: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

pool.ReturnObject(pooled);

}

///<summary>

///Createsanew<seecref="PooledObjectHolder"/>forthe

///givenpool.

///</summary>

publicstaticPooledObjectHolderUseFrom(IObjectPoolpool)

{

returnnewPooledObjectHolder(pool);

}

}

Please don't forget to destroy all the pooled istances once you have finished!How?WellusingsomethinglikethisinPooledQueuedExecutor:

publicvoidStop()

{

//waitsforallthegrep-tasktohavebeenqueued...

foreach(ISyncsyncinsyncs)

{

sync.Acquire();

}

pool.Close();

}

33.5.3.UsingtheexecutortodoaparallelgrepTheuseofthejustbuiltexecutorisquitestraigtforwardbutalittletrickyifwewanttoreallyexploitthepool.

privatePooledQueuedExecutorexecutor;

publicParallelGrep(intsize)

{

executor=newPooledQueuedExecutor(size);

}

publicvoidRecurse(stringstartPath,stringfilePattern,string

{

foreach(stringfileinDirectory.GetFiles(startPath,filePattern))

Page 743: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

{

executor.Execute(newGrep(file,regexPattern));

}

foreach(stringdirectoryinDirectory.GetDirectories(startPath))

{

Recurse(directory,filePattern,regexPattern);

}

}

publicvoidStop()

{

executor.Stop();

}

publicstaticvoidMain(string[]args)

{

if(args.Length<3)

{

Console.Out.WriteLine("usage:{0}regexdirectoryfile-pattern[pool-size]"

Environment.Exit(1);

}

stringregexPattern=args[0];

stringstartPath=args[1];

stringfilePattern=args[2];

intsize=10;

try

{

size=Int32.Parse(args[3]);

}

catch

{

}

Console.Out.WriteLine("poolsize{0}",size);

ParallelGrepgrep=newParallelGrep(size);

grep.Recurse(startPath,filePattern,regexPattern);

grep.Stop();

}

Page 744: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

33.6.AOPRefertoChapter34,AOPGuide.

[5]Youmay think that we can provide a smarter implementation and you areprobablyright.However,itisnotsodifficulttocreateanewpoolincasetheoldone became unusable. It could not be your preferred choice but surely itleveragessimplicityandobjectimmutability

Page 745: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter34.AOPGuide

Page 746: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

34.1.IntroductionThis is an introductory guide to Aspect Oriented Programming (AOP) withSpring.NET.ThisguideassumeslittletonopriorexperienceofhavingusedSpring.NETAOPonthepartofthereader.However,itdoesassumeacertainfamiliaritywiththeterminologyofAOPingeneral.Itisprobablybetterifyouhaveread(oratleasthave skimmed through) the AOP section of the reference documentationbeforehand,sothatyouarefamiliarwitha)justwhatAOPis,b)whatproblemsAOPisaddressing,andc)whattheAOPconceptsofadvice,pointcut,and joinpoint actually mean... this guide spends absolutely zero timedefiningthoseterms.Havingsaidallthat,ifyouarethekindofdeveloperwholearnsbestbyexample,thenbyallmeansfollowalong...youcanalwaysconsultthereferencedocumentationastheneedarises(seeSection13.1.1,“AOPconcepts”).Theexamplesinthisguideareintentionallysimplistic.Oneofthecoreaimsofthisguide is togetyouupandrunningwithSpring.NET's flavorofAOPinasshorta timeaspossible.Having tocomprehendevenasimpleobjectmodel inorder to understand the AOP examples would not be conducive to learningSpring.NET AOP. It is left as an exercise for the reader to take the conceptslearned from this guide and apply them to his or her own code base. Again,having said all of that, this guide concludeswith a number of cookbook-styleAOP 'recipes' that illustrate theapplicationofSpring.NET'sAOPoffering inarealworldcontext;additionally,theSpring.NETreferenceapplicationcontainsanumber of Spring.NETAOPaspects particular to it's own domainmodel (seeChapter37,SpringAir-ReferenceApplication).

Page 747: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

34.2.ThebasicsThis initial section introduces the basics of defining and then applying somesimpleadvice.

34.2.1.ApplyingadviceLets see (a very basic) example of using Spring.NET AOP. The followingexamplecodesimplyappliesadvicethatwritesthedetailsofanadvisedmethodcall to the systemconsole.Admittedly, this is not aparticularly compellingoreven useful application ofAOP, but havingworked through the example, youwill then hopefully be able to see how to apply your own custom advice toperform usefulwork (transactionmanagement, auditing, security enforcement,threadsafety,etc).Beforelookingat theAOPcodeproper letsquicklylookat thedomainclassesthatarethetargetoftheadvice(inSpring.NETAOPterminology,aninstanceofthefollowingclassisgoingtobetheadvisedobject.

publicinterfaceICommand

{

objectExecute(objectcontext);

}

publicclassServiceCommand:ICommand

{

publicobjectExecute(objectcontext)

{

Console.Out.WriteLine("Serviceimplementation:[{0}]"

returnnull;

}

}

Find below the advice that is going to be applied to the objectExecute(objectcontext) method of theServiceCommandclass. As you can see, this is an example ofaround advice (seeSection 13.3.2,“Advicetypes”).

publicclassConsoleLoggingAroundAdvice:IMethodInterceptor

{

Page 748: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicobjectInvoke(IMethodInvocationinvocation)

{

Console.Out.WriteLine("Adviceexecuting;callingtheadvisedmethod..."

objectreturnValue=invocation.Proceed();

Console.Out.WriteLine("Adviceexecuted;advisedmethodreturned"

returnreturnValue;

}

}

Somesimplecodethatmerelyprintsoutthefactthattheadviceisexecuting.

Theadvisedmethodisinvoked.

ThereturnvalueiscapturedinthereturnValuevariable.

ThevalueofthecapturedreturnValueisprintedout.

ThepreviouslycapturedreturnValueisreturned.

So thus far we have three artifacts: an interface (ICommand); animplementation of said interface (ServiceCommand); and some (trivial)advice(encapsulatedby theConsoleLoggingAroundAdviceclass).All that remains is to actually apply theConsoleLoggingAroundAdvice advice to the invocation of theExecute()methodoftheServiceCommandclass.Letslookathowtoeffectthisprogrammatically...

ProxyFactoryfactory=newProxyFactory(newServiceCommand());

factory.AddAdvice(newConsoleLoggingAroundAdvice());

ICommandcommand=(ICommand)factory.GetProxy();

command.Execute("Thisistheargument");

Theresultofexecutingtheabovesnippetofcodewilllooksomethinglikethis...

Adviceexecuting;callingtheadvisedmethod...

Serviceimplementation:[Thisistheargument]

Adviceexecuted;advisedmethodreturned

The output shows that the advice (theConsole.Out statements from theConsoleLoggingAroundAdvicewasappliedaround the invocation

Page 749: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

oftheadvisedmethod.Sowhatishappeninghere?ThefactthattheprecedingcodeusedaclasscalledProxyFactory may have clued you in. The constructor for theProxyFactory class took as an argument the object that we wanted toadvise (in thiscase,an instanceof theServiceCommand class).We thenadded some advice (a ConsoleLoggingAroundAdvice instance)using theAddAdvice() method of theProxyFactory instance.Wethen called theGetProxy() method of the ProxyFactory instancewhich gave us a proxy... an (AOP) proxy that proxied the target object (theServiceCommandinstance),andcalledtheadvice(asingleinstanceoftheConsoleLoggingAroundAdviceinthiscase).WhenweinvokedtheExecute(objectcontext) method of the proxy, the advice was'applied'(executed),ascanbeseenfromtheattendantoutput.ThefollowingimageshowsagraphicalviewoftheflowofexecutionthroughaSpring.NETAOPproxy.

OnethingtonotehereisthattheAOPproxythatwasreturnedfromthecalltotheGetProxy()methodoftheProxyFactoryinstancewascasttothe

Page 750: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ICommand interface that the ServiceCommand target objectimplemented. This is very important... currently, Spring.NET's AOPimplementationmandates the use of an interface for advised objects. In short,thismeansthatinorderforyourclassestoleverageSpring.NET'sAOPsupport,those classes that youwish to use with Spring.NETAOPmust implement atleastoneinterface.Inpracticethisrestrictionisnotasonerousasitsounds...inanycase,itisgenerallygoodpracticetoprogramtointerfacesanyway(supportforapplyingadvicetoclassesthatdonotimplementanyinterfacesisplannedforafuturepointreleaseofSpring.NETAOP).The remainder of this guide is concernedwith fleshing out some of the finerdetailsofSpring.NETAOP,butbasicallyspeaking,that'saboutit.As a first example of fleshing out one of those finer details, findbelow someSpring.NETXMLconfigurationthatdoesexactlythesamethingasthepreviousexample; it should also be added that this declarative style approach toSpring.NETAOPispreferredtotheprogrammaticstyle.

<objectid="consoleLoggingAroundAdvice"

type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"

<objectid="myServiceObject"type="Spring.Aop.Framework.ProxyFactoryObject"

<propertyname="target">

<objectid="myServiceObjectTarget"

type="Spring.Examples.AopQuickStart.ServiceCommand"

</property>

<propertyname="interceptorNames">

<list>

<value>consoleLoggingAroundAdvice</value>

</list>

</property>

</object>

ICommandcommand=(ICommand)ctx["myServiceObject"];

command.Execute();

Some comments are warranted concerning the above XML configurationsnippet. Firstly, note that the ConsoleLoggingAroundAdvice isitselfaplainvanillaobject,and iseligible forconfiguration just likeanyotherclass...iftheadviceitselfneededtobeinjectedwithanydependencies,anysuchdependenciescouldbeinjectedasnormal.

Page 751: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Secondly, notice that the object definition corresponding to the object that isretrieved from the IoC container is a ProxyFactoryObject. TheProxyFactoryObject class is an implementation of theIFactoryObject interface;IFactoryObject implementations aretreatedspeciallybytheSpring.NETIoCcontainer...inthisspecificcase,itisnotareferencetotheProxyFactoryObjectinstanceitself that isreturned,but rather the object that theProxyFactoryObject produces. In thiscase,itwillbeanadvisedinstanceoftheServiceCommandclass.

Thirdly,noticethatthetargetoftheProxyFactoryObjectisaninstanceoftheServiceCommandclass;thisistheobjectthatisgoingtobeadvised(i.e.invocationsofitsmethodsaregoingtobeintercepted).Thisobjectinstanceisdefinedasaninnerobjectdefinition...thisisthepreferredidiomforusingtheProxyFactoryObject, as itmeans that other objects cannot acquire areferencetotherawobject,butratheronlytheadvisedobject.Finally,noticethattheadvicethatistobeappliedtothetargetobjectisreferredto by its object name in the list of the names of interceptors for theProxyFactoryObject's interceptorNames property. In thisparticular case, there is only one instance of advice being applied... theConsoleLoggingAroundAdvice defined in an object definition ofthe same name. The reason for using a list of object names as opposed toreferences to the advice objects themselves is explained in the referencedocumentation...'... if theProxyFactoryObject's singleton property is set to false, itmustbeabletoreturnindependentproxyinstances.Ifanyoftheadvisorsisitselfa prototype, an independent instance would need to be returned, so it isnecessary to be able to obtain an instance of the prototype from the context;holdingareferenceisn'tsufficient.'

34.2.2.UsingPointcuts-thebasicsThe advice that was applied in the previous sectionwas rather indiscriminatewith regard towhichmethods on the advised objectwere to be advised... theConsoleLoggingAroundAdvice simply intercepted all methods(thatwerepartofaninterfaceimplementation)onthetargetobject.Thisisgreatforsimpleexamplesandsuchlike,butnotsogreatwhenyouonly

Page 752: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

want certainmethods of an object to be advised. For example, youmay onlywantthosemethodsbeginningwith'Start'tobeadvised;oryoumayonlywantthosemethodsthatarecalledwithspecificruntimeargumentvaluestobeadvised; or you may only want those methods that are decorated with aLockableattributetobeadvised.ThemechanismthatSpring.NETAOPusestodiscriminateaboutwhereadviceisapplied(i.e.whichmethodinvocationsareintercepted)isencapsulatedbytheIPointcutinterface(seeSection13.2,“PointcutAPI inSpring.NET”).Spring.NETprovidesmanyout-of-the-boximplementationsoftheIPointcutinterface...the implementation that is used if none is explicitly supplied (aswas the casewith the first example) is the canonical TruePointcut : as the namesuggests, this pointcut always matches, and hence all methods that can beadvisedwillbeadvised.So let's change the configuration of the advice such that it is only applied tomethodsthatcontaintheletters'Do'.We'llchangetheICommandinterface(andit'sattendantimplementation)toaccommodatethis...

publicinterfaceICommand

{

voidExecute();

voidDoExecute();

}

publicclassServiceCommand:ICommand

{

publicvoidExecute()

{

Console.Out.WriteLine("Serviceimplementation:Execute()..."

}

publicvoidDoExecute()

{

Console.Out.WriteLine("Serviceimplementation:DoExecute()..."

}

}

Please note that the advice itself (encapsulated within the

Page 753: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ConsoleLoggingAroundAdviceclass)doesnotneedtochange;wearechangingwherethisadviceisapplied,andnottheadviceitself.Programmaticconfigurationof theadvice, taking intoaccount the fact thatweonlywantmethodsthatcontaintheletters'Do'tobeadvised,lookslikethis...

ProxyFactoryfactory=newProxyFactory(newServiceCommand());

factory.AddAdvisor(newDefaultPointcutAdvisor(

newSdkRegularExpressionMethodPointcut("Do"),

newConsoleLoggingAroundAdvice()));

ICommandcommand=(ICommand)factory.GetProxy();

command.DoExecute();

Theresultofexecutingtheabovesnippetofcodewilllooksomethinglikethis...

Interceptedcall:abouttoinvokenextiteminchain...

Serviceimplementation...

Interceptedcall:returned

The output indicates that the advicewas applied around the invocationof theadvisedmethod, because thenameof themethod thatwas executed containedthe letters 'Do'. Try changing the pertinent code snippet to invoke theExecute()method,likeso...

ProxyFactoryfactory=newProxyFactory(newServiceCommand());

factory.AddAdvisor(

newDefaultPointcutAdvisor(

newSdkRegularExpressionMethodPointcut("Do"),

newConsoleLoggingAroundAdvice()));

ICommandcommand=(ICommand)factory.GetProxy();

//notethatthereisno'Do'inthismethodname

command.Execute();

Runthecodesnippetagain;youwillseethattheadvicewillnotbeapplied:thepointcut isnotmatched(themethodnamedoesnotcontain the letters'Do'),resultinginthefollowing(unadvised)output...

Serviceimplementation...

Page 754: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

XML configuration that accomplishes exactly the same thing as the previousprogrammaticconfigurationexamplecanbeseenbelow...

<objectid="consoleLoggingAroundAdvice"

type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor"

<propertyname="pattern"value="Do"/>

<propertyname="advice">

<objecttype="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"

</property>

</object>

<objectid="myServiceObject"

type="Spring.Aop.Framework.ProxyFactoryObject">

<propertyname="target">

<objectid="myServiceObjectTarget"

type="Spring.Examples.AopQuickStart.ServiceCommand"

</property>

<propertyname="interceptorNames">

<list>

<value>consoleLoggingAroundAdvice</value>

</list>

</property>

</object>

You'llwillperhapshavenoticed that this treatmentofpointcuts introduced theconceptofanadvisor(seeSection13.4,“AdvisorAPI inSpring.NET”).Anadvisorisnothingmorethecompositionofapointcut(i.e.whereadviceisgoingtobeapplied), and the advice itself (i.e.what isgoing to happen at the interceptionpoint). The consoleLoggingAroundAdvice object defines anadvisorthatwillapplytheadvicetoallthosemethodsoftheadvisedobjectthatmatchthepattern'Do'(thepointcut).Thepatterntomatchagainstissuppliedas a simple string value to the pattern property of theRegularExpressionMethodPointcutAdvisorclass.

Page 755: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

34.3.GoingdeeperThe first section should (hopefully) have demonstrated the basics of firstlydefiningadvice,andsecondly,ofchoosingwheretoapplythatadviceusingthenotionofapointcut.Ofcourse, thereisagreatdealmoretoSpring.NETAOPthantheaforementionedsingleadvicetypeandpointcut.Thissectioncontinuesthe exploration of Spring.NET AOP, and describes the various advice andpointcuts thatareavailable foryou touse (yes, there ismore thanone typeofadviceandpointcut).

34.3.1.OthertypesofAdviceTheadvicethatwasdemonstratedandexplainedintheprecedingsectioniswhatistermed'aroundadvice'.Thename 'aroundadvice' isusedbecausetheadviceis applied around the target method invocation. In the specific case of theConsoleLoggingAroundAdviceadvicethatwasdefinedpreviously,the targetwasmadeavailable to theadviceasanIMethodInvocationobject...acallwasmadetotheConsoleclassbeforethetargetwasinvoked,andacallwasmadetotheConsoleclassafterthetargetmethodinvocationwas invoked. The advice surrounded the target, one could even say that theadvicewastotally'around'thetarget...hencethename,'aroundadvice'.'aroundadvice'providesonewiththeopportunity todo thingsbothbefore thetargetgetsachancetodoanything,andafterthetargethasreturned:oneevengetsachancetoinspect(andpossiblyeventotallychange)thereturnvalue.Sometimesyoudon'tneedallthatpowerthough.IfwestickwiththeexampleoftheConsoleLoggingAroundAdviceadvice,what if one justwantsto log the fact that amethodwas called? In that case one doesn't need to doanythingafter the targetmethod invocation is tobe invoked, nordoyouneedaccesstothereturnvalueofthetargetmethodinvocation.Infact,youonlywantto do something before the target is to be invoked (in this case, print out amessage to the systemConsole detailing the name of themethod). In thetraditionofgoodprogrammingthatsaysoneshoulduseonlywhatoneneedsandnomore,Spring.NEThasanothertypeofadvicethatonecanuse... ifoneonlywants to do something before the target method invocation is invoked, whybother with having to manually call the Proceed() method? The mostexpedientsolutionsimplyistouse'beforeadvice'.

Page 756: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

34.3.1.1.Beforeadvice'before advice' is just that... it is advice that runs before the target methodinvocationis invoked.Onedoesnotgetaccess to thetargetmethodinvocationitself,andonecannotreturnavalue...thisisagoodthing,becauseitmeansthatyoucannotinadvertentlyforgettocalltheProceed()methodonthetarget,anditalsomeansthatyoucannotinadvertentlyforgettoreturnthereturnvalueofthetargetmethodinvocation.Ifyoudon'tneedtoinspectorchangethereturnvalue, or evendo anything after the successful executionof the targetmethodinvocation,then'beforeadvice'isjustwhatyouneed.'beforeadvice'inSpring.NETisdefinedbytheIMethodBeforeAdviceinterfaceintheSpring.Aopnamespace.Letsjustdiveinwithanexample...we'll use the same scenario as before to keep things simple. Let's define the'beforeadvice'implementationfirst.

publicclassConsoleLoggingBeforeAdvice:IMethodBeforeAdvice

{

publicvoidBefore(MethodInfomethod,object[]args,

{

Console.Out.WriteLine("Interceptedcalltothismethod:"

Console.Out.WriteLine("Thetargetis:"

Console.Out.WriteLine("Theargumentsare:"

if(args!=null)

{

foreach(objectarginargs)

{

Console.Out.WriteLine("\t:"+arg);

}

}

}

}

Let'sapplyasingleinstanceoftheConsoleLoggingBeforeAdviceadvice to the invocation of the Execute() method of theServiceCommand. What follows is programmatic configuration; as youcansee,itsprettymuchidenticaltothepreviousversion...theonlydifferenceisthat we're using our new 'before advice' (encapsulated as an instance of theConsoleLoggingBeforeAdviceclass).

Page 757: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

ProxyFactoryfactory=newProxyFactory(newServiceCommand());

factory.AddAdvice(newConsoleLoggingBeforeAdvice());

ICommandcommand=(ICommand)factory.GetProxy();

command.Execute();

Theresultofexecutingtheabovesnippetofcodewilllooksomethinglikethis...

Interceptedcalltothismethod:Execute

Thetargetis:Spring.Examples.AopQuickStart.ServiceCommand

Theargumentsare:

Theoutputclearlyindicatesthattheadvicewasappliedbeforetheinvocationofthe advised method. Notice that in contrast to 'around advice', with 'beforeadvice'thereisnochanceofforgettingtocalltheProceed()methodonthetarget,becauseonedoesnothaveaccesstotheIMethodInvocation(asis the case with 'around advice')... similarly, you cannot forget to return thereturnvalueeither.If you can use 'before advice', then do so. The simpler programming modeloffered by 'before advice' means that there is less to remember, and thuspotentiallylessthingstogetwrong.Here is the Spring.NET XML configuration for applying our 'before advice'declaratively...

<objectid="beforeAdvice"

type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"

<objectid="myServiceObject"

type="Spring.Aop.Framework.ProxyFactoryObject">

<propertyname="target">

<objectid="myServiceObjectTarget"

type="Spring.Examples.AopQuickStart.ServiceCommand"

</property>

<propertyname="interceptorNames">

<list>

<value>beforeAdvice</value>

</list>

</property>

</object>

Page 758: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

34.3.1.2.AfteradviceJust as 'before advice' defines advice that executes before an advised target,'afteradvice'isadvicethatexecutesafteratargethasbeenexecuted.'after advice' in Spring.NET is defined by theIAfterReturningAdvice interface in the Spring.Aop

namespace.Again,letsjustfireonaheadwithanexample...again,we'llusethesamescenarioasbeforetokeepthingssimple.

publicclassConsoleLoggingAfterAdvice:IAfterReturningAdvice

{

publicvoidAfterReturning(

objectreturnValue,MethodInfomethod,object[]args,

{

Console.Out.WriteLine("Thismethodcallreturnedsuccessfully:"

Console.Out.WriteLine("Thetargetwas:"

Console.Out.WriteLine("Theargumentswere:"

if(args!=null)

{

foreach(objectarginargs)

{

Console.Out.WriteLine("\t:"+arg);

}

}

Console.Out.WriteLine("Thereturnvalueis:"

}

}

Let's apply a single instance of theConsoleLoggingAfterAdviceadvice to the invocation of the Execute() method of theServiceCommand. What follows is programmatic configuration; as youcan, itsprettymuch identical to the 'beforeadvice' version (which in turnwaspretty much identical to the original 'around advice' version)... the only realdifferenceisthatwe'reusingournew'afteradvice'(encapsulatedasaninstanceoftheConsoleLoggingAfterAdviceclass).

ProxyFactoryfactory=newProxyFactory(newServiceCommand());

factory.AddAdvice(newConsoleLoggingAfterAdvice());

ICommandcommand=(ICommand)factory.GetProxy();

Page 759: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

command.Execute();

Theresultofexecutingtheabovesnippetofcodewilllooksomethinglikethis...

Thismethodcallreturnedsuccessfully:Execute

Thetargetwas:Spring.Examples.AopQuickStart.ServiceCommand

Theargumentswere:

Thereturnvalueis:null

Theoutputclearlyindicatesthattheadvicewasappliedafter theinvocationoftheadvisedmethod.Again,itbearsrepeatingthatyourrealworlddevelopmentwillactuallyhaveanadviceimplementationthatdoessomethingusefulaftertheinvocationofanadvisedmethod.Noticethatincontrastto'aroundadvice',with'afteradvice'thereisnochanceofforgettingtocalltheProceed()methodon the target, because just like 'before advice' you don't have access to theIMethodInvocation... similarly, although you get access to the returnvalueof the target,youcannotforget toreturnthereturnvalueeither.Youcanhowever change the state of the return value, typically by setting some of itsproperties,orbycallingmethodsonit.The best-practice rule for 'after advice' is much the same as it is for 'beforeadvice';namely that if you canuse 'afteradvice', thendo so (in preference tousing'aroundadvice').Thesimplerprogrammingmodelofferedby'afteradvice'means that there is less to remember, and thus less things to get potentiallywrong.Apossibleuse case for 'afteradvice'would includeperforming access controlchecksonthereturnvalueofanadvisedmethodinvocation;considerthecaseofaservicethatreturnsalistofdocumentURI's...dependingontheidentityofthe(Windows)userthatisrunningtheprogramthatiscallingthisservice,onecouldstripoutthoseURI'sthatcontainsensitivedataforwhichtheuserdoesnothavesufficientprivileges toaccess.That is justone (realworld) scenario... I'msureyou can think of plentymore that are awhole lotmore relevant to your owndevelopmentneeds.Here is the Spring.NET XML configuration for applying the 'after advice'declaratively...

<objectid="afterAdvice"

type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"

Page 760: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="myServiceObject"

type="Spring.Aop.Framework.ProxyFactoryObject">

<propertyname="target">

<objectid="myServiceObjectTarget"

type="Spring.Examples.AopQuickStart.ServiceCommand"

</property>

<propertyname="interceptorNames">

<list>

<value>afterAdvice</value>

</list>

</property>

</object>

34.3.1.3.ThrowsadviceSofarwe'vecovered 'aroundadvice', 'beforeadvice',and 'afteradvice'... theseadvicetypeswillseeyouthroughmostifnotallofyourAOPneeds.However,oneof the remainingadvice types thatSpring.NEThas in its locker is 'throwsadvice'.'throws advice' is advice that executes when an advised method invocationthrowsanexception..hencethename.Onebasicallyappliesthe 'throwsadvice'to a target object inmuch the same way as any of the previously mentionedadvice types. If during the execution of ones application none of any of theadvised methods throws an exception, then the 'throws advice' will neverexecute.However,ifduringtheexecutionofyourapplicationanadvisedmethoddoes throwanexception,thenthe 'throwsadvice'willkickinandbeexecuted.Youcanuse'throwsadvice'toapplyacommonexceptionhandlingpolicyacrossthevariousobjectsinyourapplication,ortoperformloggingofeveryexceptionthownbyanadvisedmethod,ortoalert(perhapsviaemail)thesupportteaminthecaseofparticularlyofcriticalexceptions...thelistofpossibleusescasesisofcourseendless.The'throwsadvice'typeinSpring.NETisdefinedbytheIThrowsAdviceinterface in theSpring.Aop namespace... basically, one defines on one's'throws advice' implementation class what types of exception are going to behandled.LetstakeaquicklookattheIThrowsAdviceinterface...

publicinterfaceIThrowsAdvice:IAdvice

Page 761: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

{

}

Yes,thatisreallyit...itisamarkerinterfacethathasnomethodsonit.YoumaybewonderinghowSpring.NETdetermineswhichmethods to call to effect therunning of one's 'throws advice'. An examplewould perhaps be illustrative atthispoint,sohereissomesimpleSpring.NETstyle'throwsadvice'...

publicclassConsoleLoggingThrowsAdvice:IThrowsAdvice

{

publicvoidAfterThrowing(Exceptionex)

{

Console.Out.WriteLine("Advisedmethodthrewthisexception:"

}

}

Lets also change the implementation of the Execute() method of theServiceCommand class such that it throwsanexception.Thiswill allowthe advice encapsulated by the aboveConsoleLoggingThrowsAdvicetokickin.

publicclassServiceCommand:ICommand

{

publicvoidExecute()

{

thrownewUnauthorizedAccessException();

}

}

Let's programmatically apply the 'throws advice' (an instance of ourConsoleLoggingThrowsAdvice) to the invocation of theExecute()methodoftheaboveServiceCommandclass;towit...

ProxyFactoryfactory=newProxyFactory(newServiceCommand());

factory.AddAdvice(newConsoleLoggingThrowsAdvice());

ICommandcommand=(ICommand)factory.GetProxy();

command.Execute();

Theresultofexecutingtheabovesnippetofcodewilllooksomethinglikethis...

Page 762: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Advisedmethodthrewthisexception:System.UnauthorizedAccessException:

Attemptedtoperformanunauthorizedoperation.

Ascanbeseenfromtheoutput,theConsoleLoggingThrowsAdvicekickedinwhentheadvisedmethodinvocationthrewanexception.ThereareanumberofthingstonoteabouttheConsoleLoggingThrowsAdviceadviceclass,soletstakethemeachinturn.In Spring.NET, 'throws advice' means that you have to define a class thatimplements the IThrowsAdvice interface. Then, for each type ofexception that your 'throws advice' is going to handle, you have to define amethodwiththissignature...

voidAfterThrowing(Exceptionex)

Basically, your exception handling method has to be namedAfterThrowing. This name is important... your exception handlingmethod(s) absolutely must be called AfterThrowing. If your handlermethodisnotcalledAfterThrowing,thenyour'throwsadvice'willneverbe called, it's as simple as that. Currently, this naming restriction is notconfigurable(althoughitmaywellbeopenedupforconfigurationinthefuture).Yourexceptionhandlingmethodmust(attheveryleast)declareaparameterthatisanExceptiontype...thisparametercanbetherootExceptionclass(asinthecaseoftheaboveexample),oritcanbeanExceptionsubclassifyouonlywanttohandlecertaintypesofexception.ItisgoodpracticetoalwaysmakeyourexceptionhandlingmethodshaveanExceptionparameterthatisthe most specialized Exception type possible... i.e. if you are applying'throws advice' to a method that could only ever throwArgumentExceptions, then declare the parameter of your exceptionhandlingmethodas...

voidAfterThrowing(ArgumentExceptionex)

Note that your exception handling method can have any return type, butreturninganyvaluefromaSpring.NET'throwsadvice'methodwouldbeawasteoftime...theSpring.NETAOPinfrastructurewillsimplyignorethereturnvalue,

Page 763: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

so always define the return type of your exception handling methods to bevoid.Finally, here is the Spring.NET XML configuration for applying the 'throwsadvice'declaratively...

<objectid="throwsAdvice"

type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"

<objectid="myServiceObject"

type="Spring.Aop.Framework.ProxyFactoryObject">

<propertyname="target">

<objectid="myServiceObjectTarget"

type="Spring.Examples.AopQuickStart.ServiceCommand"

</property>

<propertyname="interceptorNames">

<list>

<value>throwsAdvice</value>

</list>

</property>

</object>

Onethingthatcannotbedoneusing 'throwsadvice'isexceptionswallowing.Itis not possible to define an exception handling method in a 'throws advice'implementationthatwillswallowanyexceptionandpreventsaidexceptionfrombubbling up the call stack. The nearest thing that one can do is define anexception handlingmethod in a 'throwsadvice' implementation thatwillwrapthehandledexceptioninanotherexception;onewouldthenthrowthewrappedexceptionin thebodyofone'sexceptionhandlingmethod.Onecanuse this toimplementsomesortofexception translationorexception scrubbingpolicy, inwhich implementation specific exceptions (such as SqlException orOracleException exceptions being thrown by an advised data accessobject) get replacedwith abusiness exception that hasmeaning to the serviceobjectsinone'sbusinesslayer.Atoyexampleofthistypeof'throwsadvice'canbeseenbelow.

publicclassDataAccessExceptionScrubbingThrowsAdvice:IThrowsAdvice

{

publicvoidAfterThrowing(SqlExceptionex)

{

Page 764: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

//businessobjectsinhigherlevelservicelayerneedonlydealwithPersistenceException...

thrownewPersistenceException("Cannotaccesspersistentstorage."

}

}

Spring.NET'sdataaccesslibraryalreadyhasthiskindoffunctionality(andisawhole lot more sophisticated)... the above example is merely being used forillustrativepurposes.This treatmentof 'throwsadvice', andofSpring.NET's implementation of it israthersimplistic.'throwsadvice'featuresthathavebeenomittedincludethefactthatonecandefineexceptionhandlingmethodsthatpermitaccesstotheoriginalobject,method, andmethod arguments of the advisedmethod invocation thatthrewtheoriginalexception.Thisisaquickstartguidethough,andisnotmeantto be exhaustive... do consult the 'throws advice' section of the referencedocumentation,which describes how to declare an exception handlingmethodthat gives one access to the above extra objects, and how to declaremultipleexceptionhandlingmethodsonthesameIThrowsAdvice implementationclass(seeSection13.3.2.3,“Throwsadvice”).

34.3.1.4.Introductions(mixins)In a nutshell, introductions are all about adding new state and behaviour toarbitrary objects... transparently and at runtime. Introductions (also calledmixins)allowonetoemulatemultipleinheritance,typicallywithaneyetowardsapplyingcrosscutting state andoperations to awide swathe of objects in yourapplicationthatdon'tsharethesameinheritancehierarchy.

34.3.1.5.LayeringadviceThe examples shown so far have all demonstrated the application of a singleadvice instance to an advised object. Spring.NET's flavor of AOP would beprettypoorifonecouldonlyapplyasingleadviceinstanceperadvisedobject...itisperfectlyvalidtoapplymultipleadvicetoanadvisedobject.Forexample,one might apply transactional advice to a service object, and also apply asecurityaccesscheckingadvicetothatsameadvisedserviceobject.Intheinterestsofkeepingthissectionleanandtight,let'ssimplyapplyalloftheadvicetypesthathavebeenpreviouslydescribedtoasingleadvisedobject...inthis first instance we'll just use the default pointcut which means that every

Page 765: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

possible joinpoint will be advised, and you'll be able to see that the variousadviceinstancesareappliedinorder.Please do consult the class definitions for the following previously definedadvicetypestoseeexactlywhateachadvicetypeimplementationdoes...we'regoing to be using single instances of theConsoleLoggingAroundAdvice,ConsoleLoggingBeforeAdvice,ConsoleLoggingAfterAdvice, andConsoleLoggingThrowsAdvice advice to advise a single instanceoftheServiceCommandclass.You can find the following listing and executable application in theAopQuickStart solution in the projectSpring.AopQuickStart.Step1.

ProxyFactoryfactory=newProxyFactory(newServiceCommand());

factory.AddAdvice(newConsoleLoggingBeforeAdvice());

factory.AddAdvice(newConsoleLoggingAfterAdvice());

factory.AddAdvice(newConsoleLoggingThrowsAdvice());

factory.AddAdvice(newConsoleLoggingAroundAdvice());

ICommandcommand=(ICommand)factory.GetProxy();

command.Execute();

Hereis theSpring.NETXMLconfigurationfordeclarativelyapplyingmultipleadvice.You can find the following listing and executable application in theAopQuickStart solution in the projectSpring.AopQuickStart.Step2.

<objectid="throwsAdvice"

type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"

<objectid="afterAdvice"

type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"

<objectid="beforeAdvice"

type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"

<objectid="aroundAdvice"

type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"

<objectid="myServiceObject"

Page 766: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

type="Spring.Aop.Framework.ProxyFactoryObject">

<propertyname="target">

<objectid="myServiceObjectTarget"

type="Spring.Examples.AopQuickStart.ServiceCommand"

</property>

<propertyname="interceptorNames">

<list>

<value>throwsAdvice</value>

<value>afterAdvice</value>

<value>beforeAdvice</value>

<value>aroundAdvice</value>

</list>

</property>

</object>

34.3.1.6.ConfiguringadviceIncaseit isnot immediatelyapparent,rememberthatadviceis justaplainold.NETobject(aPONO);advicecanhaveconstructorsthatcantakeanynumberofparameters,andlikeanyother.NETclass,advicecanhaveproperties.WhatthismeansisthatonecanleveragethepoweroftheSpring.NETIoCcontainertoapplytheIoCprincipletoone'sadvice,andinsodoingreapall thebenefitsofDependencyInjection.Consider the case of throws advice that needs to report (fatal) exceptions to afirst line support centre. The throws advice could declare a dependency on areporting service via a .NET property, and the Spring.NET container coulddependencyinjectthereportingservicedependencyintothethrowsadvicewhenit is being created; the reporting dependency might be a simple Log4NETwrapper, or a Windows EventLog wrapper, or a custom reporting exceptionreportingservicethatsendsdetailedemailsconcerningthefatalexception.Also bear in mind the fact that Spring.NET's AOP implementation is quiteindependent of Spring.NET's IoC container. As you have seen, the variousexamplesused in thishave illustratedbothprogrammaticanddeclarativeAOPconfiguration (the latter being illustrated via Spring.NET's IoC XMLconfigurationmechanism).

34.3.2.UsingAttributestodefinePointcuts

Page 767: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

34.4.TheSpring.NETAOPCookbookThe preceding treatment of Spring.NET AOP has (quite intentionally) beendecidedly simple. The overarching aim was to convey the concepts ofSpring.NETAOP...thissectionoftheSpring.NETAOPguidecontainsanumberofrealworldexamplesoftheapplicationofSpring.NETAOP.

34.4.1.CachingThisexampleillustratesoneofthemorecommonusagesofAOP...caching.Letsconsiderthescenariowherewehavesomestaticreferencedatathatneedstobekeptaroundforthedurationofanapplication.Thedatawillalmostneverchangeover theuptimeofanapplication, and it exists only in thedatabase tosatisfyreferentialintegrityamongstthevariousrelationsinthedatabaseschema.Anexampleofsuchstatic(andtypicallyimmutable)referencedatawouldbeacollectionofCountryobjects(comprisingacountrynameandacode).WhatwewouldliketodoissuckinthecollectionofCountryobjectsandthenpinthem in a cache.This saves us having to hit the back end database again andagaineverytimeweneedtoreferenceacountryinourapplication(forexample,topopulatedropdowncontrolsinaWindowsFormsdesktopapplication).The Data Access Object (DAO) that will load the collection of Countryobjects is called AdoCountryDao (it is an implementation of the data-access-technology agnostic DAO interface called ICountryDao). TheimplementationoftheAdoCountryDao isquitesimple,inthateverytimetheFindAllCountriesinstancemethodiscalled,aninstancewillquerythe database for anIDataReader and hydrate zero or moreCountryobjectsusingthereturneddata.

publicclassAdoCountryDao:ICountryDao

{

publicIListFindAllCountries()

{

//implementationelidedforclarity...

returncountries;

}

}

Page 768: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Ideally,whatwewouldliketohavehappenisfortheresultsofthefirstcall totheFindAllCountries instance method to be cached.We would alsolike to do this in a non-invasive way, because caching is something that wemight want to apply at any number of points across the codebase of ourapplication.So, toaddresswhatwehave identifiedasacross cutting concern,wecanuseSpring.NETAOPtoimplementthecaching.Themechanismthatthisexampleisgoingtousetoidentify(orpickout)areasinourapplicationthatwewouldliketoapplycachingtoisa.NETAttribute.Spring.NET ships with a number of useful custom .NET Attributeimplementations,oneofwhichisthecunninglynamedCacheAttribute.In the specific case of this example, we are simply going to decorate thedefinition of the FindAllCountries instance method with theCacheAttribute.

publicclassAdoCountryDao:ICountryDao

{

[Cache]

publicIListFindAllCountries()

{

//implementationelidedforclarity...

returncountries;

}

}

TheSpringAirreferenceapplicationthatispackagedaspartoftheSpring.NETdistributioncomeswithaworkingexampleofcachingappliedusingSpring.NETAOP(seeChapter37,SpringAir-ReferenceApplication).

34.4.2.PerformanceMonitoringThis recipe show how easy it is to instrument the classes and objects in anapplication for performance monitoring. The performance monitoringimplementation uses one of the (many) Windows performance counters todisplayandtracktheperformancedata.

34.4.3.RetryRulesThisfinalrecipedescribesasimple(butreallyquiteuseful)aspect...retrylogic.Using Spring.NET AOP, it is quite easy to surround an operation such as a

Page 769: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

method thatopensaconnection toadatabasewitha (configurable)aspect thattries to obtain a database connection any number of times in the event of afailure.

Page 770: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

34.5.Spring.NETAOPBestPracticesSpring.NETAOPisan80%AOPsolution,inthatitonlytriestosolvethe80%ofthosecaseswhereAOPisagoodfit inatypicalenterpriseapplication.ThisfinalsectionoftheSpring.NETAOPguidedescribeswhereSpring.NETAOPistypicallyuseful(the80%),aswellaswhereSpring.NETAOPisnotagoodfit(the20%).

Page 771: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter35.PortableServiceAbstractionQuickStart

Page 772: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.1.IntroductionThis quickstart demonstrates the basic usage of Spring.NET's portable serviceabstraction functionality. Sections 2-5 demonstrate the use of .NETRemoting,Section6showstheuseoftheServicedComponentExporterfor.NETEnterpriseServices,andSection7showstheuseoftheWebServiceExporter.

Page 773: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.2..NETRemotingExampleTheinfrastructureclassesarelocatedintheSpring.Servicesassemblyunder the Spring.Services.Remoting namespace. The overallstrategy is to export .NET objects on the server side as either CAO or SAOobjectsusingCaoExporterorSaoExporterandobtainreferencestothese objects on the client side using CaoFactoryObject andSaoFactoryObject.Thisquickstartdoesassume familiaritywith .NETRemotingon thepartof thereader. Ifyouarenewto .NETremotingyoumayfind the links to introductory remotingmaterial presented at the conclusionofthisquickstartofsomehelp.As usual with quick start examples in Spring.NET, the classes used in thequickstart are intentionally simple. In the specific case of this remotingquickstart we are going to make a simple calculator that can be accessedremotely.Thesamecalculatorclasswillbeexportedinmultiplewaysreflectingthe variety of .NET remoting options available (CAO, SAO-SingleCall, SAO-Singleton)andalsotheuseofaddingAOPadvicetoSAOhostedobjects.The example solution is located in theexamples\Spring\Spring.Calculator directory and containsmultipleprojects.

TheSpring.Calculator.Contract project contains the interfaceICalculator thatdefinesthebasicoperationsofacalculatorandanotherinterfaceIAdvancedCalculatorthataddssupportformemorystorageforresults.(woohoo-bigfeature-HP-12Cbeware!)Theseinterfacesareshown

Page 774: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

below. The Spring.Calculator.Services project contains animplementationofthetheseinterfaces,namelytheclassesCalculatorandAdvancedCalculator. The purpose of theAdvancedCalculator implementation is to demonstrate theconfigurationofobjectstateforSAO-singletonobjects.Notethatthecalculatorimplementations do not inherit from theMarshalByRefObject class.The Spring.Calculator.ClientApp project contains the clientapplication and the Spring.Calculator.RemoteApp projectcontains a console application that will host a Remoted instance of theAdvancedCalculator class. The Spring.Aspects projectcontainssomeloggingadvicethatwillbeusedtodemonstratetheapplicationofaspects to remoted objects.Spring.Calculator.RegisterComponentServices isrelated to enterprise service exporters and is not relevant for this quickstart.Spring.Calculator.Web is related toweb services exporters and isnotrelevantforthisquickstart.

publicinterfaceICalculator

{

intAdd(intn1,intn2);

intSubtract(intn1,intn2);

DivisionResultDivide(intn1,intn2);

intMultiply(intn1,intn2);

}

[Serializable]

publicclassDivisionResult

{

privateint_quotient=0;

privateint_rest=0;

publicintQuotient

{

get{return_quotient;}

set{_quotient=value;}

}

Page 775: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicintRest

{

get{return_rest;}

set{_rest=value;}

}

}

Anextensionofthisinterfacethatsupportshavingaslotforcalculatormemoryisshownbelow

publicinterfaceIAdvancedCalculator:ICalculator

{

intGetMemory();

voidSetMemory(intmemoryValue);

voidMemoryClear();

voidMemoryAdd(intnum);

}

The structure of the VS.NET solution is a consequence of following the bestpracticeofusinginterfacestosharetypeinformationbetweena.NETremotingclientandserver.Thebenefitsofthisapproacharethattheclientdoesnotneedareference to the assembly that contains the implementation class. Having theclient reference the implementation assembly is undesirable for a variety ofreasons. One reason being security since an untrusted client could potentiallyobtainthesourcecodetotheimplementationsinceIntermediateLanguage(IL)code is easily reverse engineered. Another, more compelling, reason is toprovide a greater decoupling between the client and server so the server canupdateitsimplementationoftheinterfaceinamannerthatisquitetransparenttotheclient; i.e. theclient codeneednot change. Independentof .NET remotingbestpractices,usinganinterfacetoprovideaservicecontractisjustgoodobject-orienteddesign.Thisletstheclientchooseanotherimplementationunrelatedto.NETRemoting,forexamplealocal,test-stuborawebservicesimplementation.One of the major benefits of using Spring.NET is that it reduces the cost ofdoing 'interface based programming' to almost nothing. As such, this bestpractice approach to .NET remoting fits naturally into thegeneral approach to

Page 776: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

application development that Spring.NET encourages you to follow. Ok, withthatbarrageofOOdesignrantingfinished,ontotheimplementation!

Page 777: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.3.ImplementationThe implementation of the calculators contained in theSpring.Calculator.Serviesproject isquite straightforward.Theonlyinterestingmethodsarethosethatdealwiththememorystorage,whichisthe state that we will be configuring explicitly using constructor injection. Asubsetoftheimplementationisshownbelow.

publicclassCalculator:ICalculator

{

publicintAdd(intn1,intn2)

{

returnn1+n2;

}

publicintSubstract(intn1,intn2)

{

returnn1-n2;

}

publicDivisionResultDivide(intn1,intn2)

{

DivisionResultresult=newDivisionResult();

result.Quotient=n1/n2;

result.Rest=n1%n2;

returnresult;

}

publicintMultiply(intn1,intn2)

{

returnn1*n2;

}

}

publicclassAdvancedCalculator:Calculator,IAdvancedCalculator

{

privateintmemoryStore=0;

Page 778: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicAdvancedCalculator()

{}

publicAdvancedCalculator(intinitialMemory)

{

memoryStore=initialMemory;

}

publicintGetMemory()

{

returnmemoryStore;

}

//othermethodsomittedinthislisting...

}

The Spring.Calculator.RemotedApp project hosts remotedobjects inside a console application.The code is also quite simple and shownbelow

publicstaticvoidMain(string[]args)

{

try

{

//initializationofSpring.NET'sIoCcontainer

IApplicationContextctx=ContextRegistry.GetContext();

Console.Out.WriteLine("Serverlistening...");

}

catch(Exceptione)

{

Console.Out.WriteLine(e);

}

finally

{

Console.Out.WriteLine("---Press<return>toquit---"

Console.ReadLine();

}

}

Page 779: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The configuration of the .NET remoting channels is done using the standardsystem.runtime.remoting configuration section inside the .NETconfigurationfileoftheapplication(App.config).Inthiscaseweareusingthetcpchannelonport8005.

<system.runtime.remoting>

<application>

<channels>

<channelref="tcp"port="8005"/>

</channels>

</application>

</system.runtime.remoting>

The objects created in Spring's application context are shown below.Multipleresource files are used to export these objects under various remotingconfigurations.TheAOPadviceusedinthisexampleisasimpleLog4Netbasedaroundadvice.

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

<sectionname="log4net"type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"

</configSections>

<spring>

<parsers>

<parsertype="Spring.Remoting.Config.RemotingNamespaceParser,Spring.Services"

</parsers>

<context>

<resourceuri="config://spring/objects"/>

<resourceuri="assembly://RemoteServer/RemoteServer.Config/cao.xml"

<resourceuri="assembly://RemoteServer/RemoteServer.Config/saoSingleCall.xml"

<resourceuri="assembly://RemoteServer/RemoteServer.Config/saoSingleCall-aop.xml"

<resourceuri="assembly://RemoteServer/RemoteServer.Config/saoSingleton.xml"

<resourceuri="assembly://RemoteServer/RemoteServer.Config/saoSingleton-aop.xml"

</context>

<objectsxmlns="http://www.springframework.net">

Page 780: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<description>Definitionsofobjectstobeexported.

<objecttype="Spring.Remoting.RemotingConfigurer,Spring.Services"

<propertyname="Filename"value="Spring.Calculator.RemoteApp.exe.config"

</object>

<objectid="Log4NetLoggingAroundAdvice"type

<propertyname="Level"value="Debug"

</object>

<objectid="singletonCalculator"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

<constructor-argtype="int"value="217"

</object>

<objectid="singletonCalculatorWeaved"type=

<propertyname="target"ref="singletonCalculator"

<propertyname="interceptorNames">

<list>

<value>Log4NetLoggingAroundAdvice

</list>

</property>

</object>

<objectid="prototypeCalculator"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

<constructor-argtype="int"value="217"

</object>

<objectid="prototypeCalculatorWeaved"type=

<propertyname="targetSource">

<objecttype="Spring.Aop.Target.PrototypeTargetSource,Spring.Aop"

<propertyname="TargetObjectName"

</object>

</property>

<propertyname="interceptorNames">

<list>

<value>Log4NetLoggingAroundAdvice

</list>

</property>

</object>

</objects>

</spring>

Page 781: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The declaration of the calculator instance,singletonCalculator forexample,andthesettingofanypropertyvaluesand/orobjectreferencesisdoneas you would normally do for any object declared in the Spring.NETconfigurationfile.Toexposethecalculatorobjectsas.NETremotedobjectstheexporterSpring.Remoting.CaoExporterisusedforCAOobjectsand Spring.Remoting.SaoExporter is used for SAO objects.Bothexporters require the settingof aTargetNameproperty that refers tothe name of the object in Spring's IoC container that will be remoted. Thesemantics of SAO-SingleCall and CAO behavior are achieved by exporting atarget object that is declared as a "prototype" (i.e. singleton=false). For SAOobjects,theServiceNamepropertydefinesthenameoftheserviceasitwillappear in the URL that clients use to locate the remote object. To set theremotinglifetimeoftheobjectstobeinfinite,thepropertyInfiniteissettotrue.TheconfigurationfortheexportingaSAO-Singletonisshownbelow.

<objects

xmlns="http://www.springframework.net"

xmlns:r="http://www.springframework.net/remoting">

<description>RegistersthecalculatorserviceasaSAOin'Singleton'mode.

<r:saoExporter

targetName="singletonCalculator"

serviceName="RemotedSaoSingletonCalculator"/>

</objects>

Theconfigurationshownaboveuses theSpringRemotingschemabutyoucanalsochoosetousethestandard'generic'XMLconfigurationshownbelow.

<objectname="saoSingletonCalculator"type="Spring.Remoting.SaoExporter,Spring.Services"

<propertyname="TargetName"value="singletonCalculator"/>

<propertyname="ServiceName"value="RemotedSaoSingletonCalculator"

</object>

This will result in the remote object being identified by the URLtcp://localhost:8005/RemotedSaoSingletonCalculator

TheuseofSaoExporterandCaoExporterforotherconfigurationare

Page 782: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

similar, look at the configuration files in theSpring.Calculator.RemotedApp project files for moreinformation.On theclientside, theclientapplicationwillconnectaspecific typeof remotecalculator service, object, ask it for it's current memory value, which is pre-configuredto217,thenperformasimpleaddition.Asinthecaseoftheserver,the channel configuration is done using the standard .NET Remotingconfiguration section of the .NET application configuration file(App.config),ascanbeenseenbelow.

<system.runtime.remoting>

<application>

<channels>

<channelref="tcp"/>

</channels>

</application>

</system.runtime.remoting>

Theclientimplementationcodeisshownbelow.

publicstaticvoidMain(string[]args)

{

try

{

Pause();

IApplicationContextctx=ContextRegistry.GetContext();

Console.Out.WriteLine("GetCalculator...");

IAdvancedCalculatorfirstCalc=(IAdvancedCalculator)ctx.GetObject(

Console.WriteLine("Divide(11,2):"+firstCalc.Divide(11,2));

Console.Out.WriteLine("Memory="+firstCalc.GetMemory());

firstCalc.MemoryAdd(2);

Console.Out.WriteLine("Memory+2="+firstCalc.GetMemory());

Console.Out.WriteLine("GetCalculator...");

IAdvancedCalculatorsecondCalc=(IAdvancedCalculator)ctx.GetObject(

Console.Out.WriteLine("Memory="+secondCalc.GetMemory());

}

catch(Exceptione)

Page 783: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

{

Console.Out.WriteLine(e);

}

finally

{

Pause();

}

}

Notethattheclientapplicationcodeisnotawarethatitisusingaremoteobject.ThePause()methodsimplywaitsuntiltheReturnkeyispressedontheconsolesothattheclientdoesn'tmakearequesttotheserverbeforetheserverhas had a chance to start. The standard configuration and initialization of the.NETremotinginfrastructureisdonebeforethecreationoftheSpring.NETIoCcontainer. The configuration of the client application is constructed in such away that one can easily switch implementations of thecalculatorService retrieved from the application context. In morecomplexapplications thecalculator servicewouldbeadependencyonanotherobject in your application, say in aworkflow processing layer. The followinglistingshowsaconfigurationforuseofalocalimplementationandthenseveralremoteimplementations.ThesameExporterapproachcanbeusedtocreateWebServicesandServicedComponents(EnterpriseServices)ofthecalculatorobjectbutarenotdiscussedinthisQuickStart.

<spring>

<context>

<resourceuri="config://spring/objects"/>

<!--Onlyoneatatime!-->

<!--==================================-->

<!--Inprocess(local)implementations-->

<!--==================================-->

<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.InProcess/inProcess.xml"

<!--========================-->

<!--Remotingimplementations-->

<!--========================-->

<!--Makesure'RemoteApp'consoleapplicationisrunningandlistening.-->

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.Remoting/cao.xml"/>-->

Page 784: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.Remoting/cao-ctor.xml"/>-->

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.Remoting/saoSingleton.xml"/>-->

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.Remoting/saoSingleton-aop.xml"/>-->

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.Remoting/saoSingleCall.xml"/>-->

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.Remoting/saoSingleCall-aop.xml"/>-->

<!--===========================-->

<!--WebServiceimplementations-->

<!--===========================-->

<!--Makesure'http://localhost/SpringCalculator/'webapplicationisrunning-->

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.WebServices/webServices.xml"/>-->

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.WebServices/webServices-aop.xml"/>-->

<!--=================================-->

<!--EnterpriseServiceimplementations-->

<!--=================================-->

<!--Makesureyouregistercomponentswith'RegisterComponentServices'consoleapplication.-->

<!--<resourceuri="assembly://Spring.Calculator.ClientApp/Spring.Calculator.ClientApp.Config.EnterpriseServices/enterpriseServices.xml"/>-->

</context>

</spring>

TheinProcess.xmlconfigurationfilecreatesaninstanceofAdvancedCalculatordirectly

<objectsxmlns="http://www.springframework.net">

<description>inProcess</description>

<objectid="calculatorService"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

</objects>

Factoryclassesareused tocreateaclient side reference to the .NETremotingimplementations.ForSAOobjectsusetheSaoFactoryObjectclassandforCAOobjectsusetheCaoFactoryObjectclass.TheconfigurationforobtainingareferencetothepreviouslyexportedSAOsingletonimplementationisshownbelow

<objectsxmlns="http://www.springframework.net">

<description>saoSingleton</description>

Page 785: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="calculatorService"type="Spring.Remoting.SaoFactoryObject,Spring.Services"

<propertyname="ServiceInterface"value="Spring.Calculator.Interfaces.IAdvancedCalculator,Spring.Calculator.Contract"

<propertyname="ServiceUrl"value="tcp://localhost:8005/RemotedSaoSingletonCalculator"

</object>

</objects>

YoumustspecifythepropertyServiceInterfaceaswellasthelocationof the remote object via the ServiceUrl property. The propertyreplacement facilities ofSpring.NETcanbe leveragedhere tomake it easy toconfigure the URL value based on environment variable settings, a standard.NETconfigurationsection,oranexternalpropertyfile.Thisisusefultoeasilyswitchbetweentest,QA,andproduction(yeababy!)environments.Anexampleofhowthiswouldbeexpressedis...

<propertyname="ServiceUrl"value="${protocol}://${host}:${port}/RemotedSaoSingletonCalculator"

Thepropertyvaluesinthisexamplearedefinedelsewhere;refertoSection5.9.2.1,“Example:ThePropertyPlaceholderConfigurer”foradditionalinformation.Asmentionedpreviously,more important in termsof configuration flexibility is the fact thatnow you can swap out different implementations (.NET remoting based orotherwise)ofthisinterfacebymakingasimplechangetotheconfigurationfile.The configuration for obtaining a reference to the previously exported CAOimplementationisshownbelow

<objectsxmlns="http://www.springframework.net">

<description>cao</description>

<objectid="calculatorService"type="Spring.Remoting.CaoFactoryObject,Spring.Services"

<propertyname="RemoteTargetName"value="prototypeCalculator"

<propertyname="ServiceUrl"value="tcp://localhost:8005"

</object>

</objects>

Page 786: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.4.RunningtheapplicationNowthatwehavehadawalkthoughoftheimplementationandconfigurationitis finally time to run theapplication (ifyouhaven'tyetpulled the trigger).BesuretosetupVS.NETtorunmultipleapplicationsonstartupasshownbelow.

Runningthesolutionyieldsthefollowingoutputintheserverandclientwindow

SERVERWINDOW

Serverlistening...

---Press<return>toquit---

CLIENTWINDOW

---Press<return>tocontinue---(hitreturn...)

GetCalculator...

Divide(11,2):Quotient:'5';Rest:'1'

Memory=0

Page 787: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Memory+2=2

GetCalculator...

Memory=2

---Press<return>tocontinue---

Page 788: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.5.RemotingSchemaThe spring-remoting.xsd file in the doc directory provides a short syntax toconfigureSpring.NETremoting features.To install the schema in theVS.NETenvironmentruntheinstall-schemaNAntscriptinthedocdirectory.RefertotheChapteronVS.NETintegrationformoredetails.ThevariousconfigurationfilesintheRemoteServerandClientprojectsshowtheschemainaction.Hereisacondensedlistingofthosedefinitionswhichshouldgiveyouagoodfeelforhowtousetheschema.

<!--Calculatordefinitions-->

<objectid="singletonCalculator"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

<constructor-argtype="int"value="217"/>

</object>

<objectid="prototypeCalculator"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

<constructor-argtype="int"value="217"/>

</object>

<!--CAOobject-->

<r:caoExportertargetName="prototypeCalculator"infinite="false"

<r:lifeTimeinitialLeaseTime="2m"renewOnCallTime="1m"/>

</r:caoExporter>

<!--SAOSingleCall-->

<r:saoExporter

targetName="prototypeCalculator"

serviceName="RemotedSaoSingleCallCalculator"/>

<!--SAOSingleton-->

<r:saoExporter

targetName="singletonCalculator"

serviceName="RemotedSaoSingletonCalculator"/>

NotethatthesingletonnatureoftheremotedobjectisbasedontheSpringobjectdefinition. The "PrototypeCalculator" has its singleton property set to false tothat a new onewill be created every time amethod on the remoted object isinvokedfortheSAOcase.

Page 789: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.6..NETEnterpriseServicesExampleThe .NET Enterprise Services example is located in the projectSpring.Calculator.RegisterComponentServices.2005.csproj orSpring.Calculator.RegisterComponentServices.2003.csproj, depending on theuse of .NET 1.1 or 2.0. The example uses the previous AdvancedCalculatorimplementation and then imports the embedded configuration file'enterpriseServices.xml' from the namespaceSpring.Calculator.RegisterComponentServices.Config. The top levelconfigurationisshownbelow

<spring>

<context>

<resourceuri="config://spring/objects"

<resourceuri="assembly://Spring.Calculator.RegisterComponentServices/Spring.Calculator.RegisterComponentServices.Config/enterpriseServices.xml"

</context>

<objectsxmlns="http://www.springframework.net"

<description>Definitionsofobjectstoberegistered.

<objectid="calculatorService"type=

</objects>

</spring>

The exporter that adapts the AdvancedCalculator for use as an EnterpriseServicecomponentisdefinedfirst inenterpriseServices.xml.Secondisdefinedan exporter that will host the exported Enterprise Services componentapplication by signing the assembly, registering it with the specified COM+applicationname. Ifapplicationdoesnotexist itwill create it andconfigure itusingvaluesspecifiedforDescription,AccessControlandRolesproperties.TheconfigurationfileforenterpriseServices.xmlisshownbelow

<objectsxmlns="http://www.springframework.net">

<description>enterpriseService</description>

Page 790: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="calculatorComponent"type="Spring.EnterpriseServices.ServicedComponentExporter,Spring.Services"

<propertyname="TargetName"value="calculatorService"

<propertyname="TypeAttributes">

<list>

<objecttype="System.EnterpriseServices.TransactionAttribute,System.EnterpriseServices"

</list>

</property>

<propertyname="MemberAttributes">

<dictionary>

<entrykey="*">

<list>

<objecttype

</list>

</entry>

</dictionary>

</property>

</object>

<objecttype="Spring.EnterpriseServices.EnterpriseServicesExporter,Spring.Services"

<propertyname="ApplicationName">

<value>SpringCalculatorApplication

</property>

<propertyname="Description">

<value>SpringCalculatorapplication.

</property>

<propertyname="AccessControl">

<objecttype="System.EnterpriseServices.ApplicationAccessControlAttribute,System.EnterpriseServices"

<propertyname="AccessChecksLevel"

<value>ApplicationComponent

</property>

</object>

</property>

<propertyname="Roles">

<list>

<value>Admin:Administratorrole

<value>User:Userrole</value>

<value>Manager:Administratorrole

</list>

</property>

<propertyname="Components">

<list>

<refobject="calculatorComponent"

Page 791: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</list>

</property>

<propertyname="Assembly">

<value>Spring.Calculator.EnterpriseServices

</property>

</object>

</objects>

Page 792: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.7.WebServicesExampleTheWebServices example shows how to export theAdvancedCalculator as awebservicethatisanAOPproxyofAdvancedCalculatorthathasloggingadviceappliedtoit.Themainconfigurationfile,Web.config,includesinformationfromthreelocationsasshownbelow

<context>

<resourceuri="config://spring/objects"

<resourceuri="~/Config/webServices.xml"

<resourceuri="~/Config/webServices-aop.xml"

</context>

Theconfigsection 'spring/objects' inWeb.configcontainsthedefinitionforthe'plain'Advancedcalculator,aswellasthedefinitionstocreateanAOPproxyofanAdvancedCalculator that adds logging advice. These definitions are shownbelow

<objectsxmlns="http://www.springframework.net"

<!--Aspect-->

<objectid="CommonLoggingAroundAdvice"type="Spring.Aspects.Logging.CommonLoggingAroundAdvice,Spring.Aspects"

<propertyname="Level"value="Debug"/>

</object>

<!--Service-->

<!--'plainobject'forAdvancedCalculator-->

<objectid="calculator"type="Spring.Calculator.Services.AdvancedCalculator,Spring.Calculator.Services"

<!--AdvancedCalculatorobjectwithAOPloggingadviceapplied.-->

<objectid="calculatorWeaved"type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop"

<propertyname="target"

<propertyname="interceptorNames"

<list>

<value>

</list>

</property>

</object>

Page 793: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</objects>

The configuration file webService.xml simply exports the named calculatorobject

<objectid="calculatorService"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

<propertyname="TargetName"value="calculator"

<propertyname="Namespace"value="http://SpringCalculator/WebServices"

<propertyname="Description"value="SpringCalculatorWebServices"

</object>

Whereas thewebService-aop.xml exports the calculator instance thathasAOPadviceappliedtoit.

<objectid="calculatorServiceWeaved"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

<propertyname="TargetName"value="calculatorWeaved"

<propertyname="Namespace"value="http://SpringCalculator/WebServices"

<propertyname="Description"value="SpringCalculatorWebServices"

</object>

Settingthesolutiontorunthewebprojectasthestartup,youwillbepresentedwithascreenasshownbelow

Page 794: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Selecting the CalculatorService and CalculatorServiceWeaved links will bringyou to the standard user interface generated for browsing a web service, asshownbelow

AndsimilarlyforthecalculatorservicewithAOPapplied

Page 795: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

InvokingtheAddmethodforcalculatorServiceWeavedshowsthescreen

Page 796: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Invokingaddwillthenshowtheresult'4'inanewbrowserinstanceandthelogfilelog.txtwillcontainthefollowingentires

2007-10-1517:59:47,375[DEBUG]Spring.Aspects.Logging.CommonLoggingAroundAdvice-Interceptedcall:abouttoinvokemethod'Add'

2007-10-1517:59:47,421[DEBUG]Spring.Aspects.Logging.CommonLoggingAroundAdvice-Interceptedcall:returned'4'

Page 797: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

35.8.AdditionalResourcesSome introductory articles on .NET remoting can be found online atMSDN.IngoRammer is also a very good authority on .NET remoting, and the .NETRemotingFAQ(linkbelow)whichismaintainedbyIngoischockfullofusefulinformation.

AnIntroductiontoMicrosoft.NETRemotingFramework

Microsoft.NETRemoting:ATechnicalOverview

Advanced.NETRemoting(authoredbyIngoRammer)

.NETRemotingFAQ

Page 798: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter36.WebQuickstarts

Page 799: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

36.1.IntroductionTheWebQuickstart solution provides basic 'HelloWorld' examples for usingSpring.Webfeatures.YoucanusethissolutionasastartingpointandthenmoveontotheSpringAirapplicationthatusesawiderrangeofSpring.Webfeatures.

Page 800: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter37.SpringAir-ReferenceApplication

Page 801: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

37.1.IntroductionThe SpringAir sample application demonstrates a selection of Spring.NET'spowerful featuresmakinga .NETprogrammer's lifeeasier. Itdemonstrates thefollowingfeaturesofSpring.Web

Spring.NETIoCcontainerconfiguration

DependencyInjectionasappliedtoASP.NETpages

MasterPagesupport

WebServicesupport

Bi-directionaldatabinding

Declarativevalidationofdomainobjects

Internationalization

ResultmappingtobetterencapsulatepagenavigationflowsTheapplicationmodelsaflightreservationsystemwhereyoucanbrowseflights,book a trip and even attach your own clients by leveraging the web servicesexposedbytheSpringAirapplication.All pages within the application are fully Spring managed. Dependencies getinjected as configured within a Spring Application Context. For NET 1.1 itshowshowtoapplycentrallymanagedlayoutstoallpagesinanapplicationbyusingmasterpages-awell-knownfeaturefromNET2.0.Whenselectingyourflights,youarealreadyexperiencingafullylocalizedform.Select your preferred language from the bottomof the form and see, how thenewlanguageisimmediatelyapplied.Assoonasyousubmityourdesiredflight,the submitted values are automatically unbound from the form onto theapplication'sdatamodelby leveragingSpring.Web's support forDataBinding.With Data Binding you can easily associate properties on your PONOmodelwithelementsonyourASP.NETform.

Page 802: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

37.2.GettingStartedThe application is located in the installation directory under'examples/SpringAir.Thedirectory'SpringAir.Web.2003'containsthe.NET1.1version of the application and the directory 'SpringAir.Web.2005' contains the.NET2.0version.For.NET1.1youwillneedtocreateavirtualdirectorynamed'SpringAir.2003'usingIISAdministratorandpointit to thefollowingdirectoryexamples\Spring\SpringAir\src\SpringAir.Web.2003.Thesolution file for .NET1.1isexamples\Spring\SpringAir\SpringAir.2003.sln.For.NET2.0simplyopenthe solution examples\Spring\SpringAir\SpringAir.2005.sln. Set your startupprojecttobeSpringAir.Webandthestartpageto.\Web\Home.aspx

Page 803: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

37.3.ContainerconfigurationThewebproject'stoplevelWeb.configconfigurestheIoCcontainerthatisusedwithin the web application. You do not need to explicitly instantiate the IoCcontainer.Theimportantpartsofthatconfigurationareshownbelow

<spring>

<parsers>

<parsertype="Spring.Data.Config.DatabaseNamespaceParser,Spring.Data"

</parsers>

<context>

<resourceuri="~/Config/Aspects.xml"/>

<resourceuri="~/Config/Web.xml"/>

<resourceuri="~/Config/Services.xml"/>

<!--TESTCONFIGURATION-->

<resourceuri="~/Config/Test/Services.xml"/>

<resourceuri="~/Config/Test/Dao.xml"/>

<!--PRODUCTIONCONFIGURATION-->

<!--

<resourceuri="~/Config/Production/Services.xml"/>

<resourceuri="~/Config/Production/Dao.xml"/>

-->

</context>

</spring>

In this example there are separate configuration files for test and productionconfiguration.TheServices.xmlfileisinfactthesamebetweenthetwo,andtheexamplewillberefactoredinfuturetoremovethatduplication.TheDaolayerinthetestconfigurationisanin-memoryversion,fakingdatabaseaccess,whereastheproductionversionusesanADO.NETbasedsolution.The pages that comprise the application are located in the directory'Web/BookTrip'. In that directory is anotherWeb.config that is responsible forconfiguringthatdirectory's.aspxpages.Therearethreemainpagesintheflowoftheapplication.

Page 804: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TripForm-formtoenterinairports,times,round-triporone-way

SuggestedFlights-formtoselectflights

ReservationConfirmationPage - your confirmation ID from the bookingprocess.

TheXMLconfigurationtoconfiguretheTripFormformisshownbelow

<objecttype="TripForm.aspx"parent="standardPage">

<propertyname="BookingAgent"ref="bookingAgent"/>

<propertyname="AirportDao"ref="airportDao"/>

<propertyname="TripValidator"ref="tripValidator"/>

<propertyname="Results">

<dictionary>

<entrykey="displaySuggestedFlights"value="redirect:SuggestedFlights.aspx"

</dictionary>

</property>

</object>

AsyoucanseethevariousservicesitneedsaresetusingstandardDItechniques.TheResultspropertyexternalizesthepageflow,redirectingtothenextpageintheflow,SuggestedFlights.The'parent'attributeletsthispageinheritpropertiesfromatemplate.TheislocatedinthetoplevelWeb.configfile,packagedundertheConfigdirectory.ThestandardPagesetsuppropertiesofSpring'sbasepageclass, fromwhich all the pages in this application inherit from. (Note that toperform only dependency injection on pages you do not need to inherit fromSpring'sPageclass).

Page 805: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

37.4.Bi-directionaldatabindingTheTripFormpagedemonstratesthebi-directionaldatabindingfeatures.ATripobject isusedtobacktheinformationof theform.Thefamilyofmethods thatareoverriddentosupportthebi-directionaldatabindingarelistedbelow.

protectedoverridevoidInitializeModel()

{

trip=newTrip();

trip.Mode=TripMode.RoundTrip;

trip.StartingFrom.Date=DateTime.Today;

trip.ReturningFrom.Date=DateTime.Today.AddDays(1);

}

protectedoverridevoidLoadModel(objectsavedModel)

{

trip=(Trip)savedModel;

}

protectedoverrideobjectSaveModel()

{

returntrip;

}

protectedoverridevoidInitializeDataBindings()

{

BindingManager.AddBinding("tripMode.Value","Trip.Mode"

BindingManager.AddBinding("leavingFromAirportCode.SelectedValue"

BindingManager.AddBinding("goingToAirportCode.SelectedValue"

BindingManager.AddBinding("leavingFromDate.SelectedDate"

BindingManager.AddBinding("returningOnDate.SelectedDate"

}

This is all you need to set up in order to have values from the Trip object'marshaled'toandfromthewebcontrols.TheInitializeDataBindingsmethodsetthisup,usingtheSpringExpressionLanguagetodefinetheUIelementpropertythatisassociatewiththemodel(Trip)property.

Page 806: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

37.5.DeclarativeValidationThemethodcalledwhentheSearchbuttonisclickedwillperformvalidation.Ifvalidationsucceedsaswellasadditionalbusinesslogicchecks,thenextpageintheflowis loaded.This isshowninthecodebelow.Noticehowmuchcleanerand more business focused the code reads than if you were using standardASP.NETAPIs.

protectedvoidSearchForFlights(objectsender,EventArgse)

{

if(Validate(trip,tripValidator))

{

FlightSuggestionssuggestions=this.bookingAgent.SuggestFlights(Trip);

if(suggestions.HasOutboundFlights)

{

Session[Constants.SuggestedFlightsKey]=suggestions;

SetResult(DisplaySuggestedFlights);

}

}

}

The'Validate'methodofthepagetakesasargumentstheobjecttovalidateandaIValidatorinstance.TheTripFormpropertyTripValidatorissetviadependencyinjection(asshownabove).Thevalidation logic isdefineddeclaratively in theXMLconfigurationfileandisshownbelow.

<v:groupid="tripValidator">

<v:requiredid="departureAirportValidator"test="StartingFrom.AirportCode"

<v:messageid="error.departureAirport.required"

</v:required>

<v:groupid="destinationAirportValidator"

<v:requiredtest="ReturningFrom.AirportCode"

<v:messageid="error.destinationAirport.required"

</v:required>

<v:conditiontest="ReturningFrom.AirportCode!=StartingFrom.AirportCode"

<v:messageid="error.destinationAirport.sameAsDeparture"

</v:condition>

</v:group>

Page 807: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<v:groupid="departureDateValidator"

<v:requiredtest="StartingFrom.Date"

<v:messageid="error.departureDate.required"

</v:required>

<v:conditiontest="StartingFrom.Date>=DateTime.Today"

<v:messageid="error.departureDate.inThePast"

</v:condition>

</v:group>

<v:groupid="returnDateValidator"

<v:requiredtest="ReturningFrom.Date"

<v:messageid="error.returnDate.required"

</v:required>

<v:conditiontest="ReturningFrom.Date>=StartingFrom.Date"

<v:messageid="error.returnDate.beforeDeparture"

</v:condition>

</v:group>

</v:group>

Thevalidationlogichas'when'clausessothatreturndatescanbeignorediftheModepropertyoftheTripobjectissetto'RoundTrip'.

Page 808: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

37.6.InternationalizationBothimageandtextbasedinternationalizationaresupported.YoucanseethisinactionbyclickingontheEnglish,Srpski,orСрпскиlinksonthebottomofthepage.

Page 809: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

37.7.WebServicesTheclassBookingAgentthatwasusedbytheTripFormclassisastandard.NETclass,i.enoWebMethodattributesareonanyofitsmethods.SpringcanexposethisobjectasawebservicebydeclaringthefollowingXMLdefinedinthetoplevelConfig/Services.xmlfile

<objectid="bookingAgentWebService"type="Spring.Web.Services.WebServiceExporter,Spring.Web"

<propertyname="TargetName"value="bookingAgent"/>

<propertyname="Name"value="BookingAgent"/>

<propertyname="Namespace"value="http://SpringAir/WebServices"

<propertyname="Description"value="SpringAirBookingAgentWebService"

<propertyname="MemberAttributes">

<dictionary>

<entrykey="SuggestFlights">

<objecttype="System.Web.Services.WebMethodAttribute,System.Web.Services"

<propertyname="Description"value="Getsthoseflightsuggestionsthatareapplicableforthesuppliedtrip."

</object>

</entry>

<entrykey="Book">

<objecttype="System.Web.Services.WebMethodAttribute,System.Web.Services"

<propertyname="Description"value="Goesaheadandactuallybookswhatupuntilthispointhasbeenatransientreservation."

</object>

</entry>

<entrykey="GetAirportList">

<objecttype="System.Web.Services.WebMethodAttribute,System.Web.Services"

<propertyname="Description"value="Returnacollectionofallthoseairportsthatcanbeusedforthepurposesofbooking."

</object>

</entry>

</dictionary>

</property>

</object>

Page 810: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter38.DataAccessQuickStart

Page 811: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

38.1.IntroductionThedataaccessquick startdemonstrates theAPIusageofAdoTemplate (bothgeneric and non-generic versions) aswell as the use of the object based dataaccessclassescontainedinSpring.Data.Objects.ItusestheNorthwinddatabaseandislocatedunderthedirectoryexamples/DataAccessQuickStart.ThequickstartcontainspseudoDAOobjectsandacollectionofNUnitteststoexercisethemratherthanafullblownapplication.TorunthetestsfromwithinVS.NETinstallTestDriven.NET,ReSharper, or anequivalent .The listingofDAOclassesandthepartsofSpring.Datathattheydemonstrateisshownbelow.

CommandCallbackDao - Use of the ICommandCallback andCommandCallbackDelegate

ResultSetExtractorDao - Use of IResultSetExtractor andResultSetExtractorDelegate

RowCallbackDao-UseofIRowCallbackandRowCallbackDelegate

RowMapperDao-UseofIRowMapperandRowMapperDelegate

QueryForObject-UseofQueryForObjectmethod.

StoredProcDao-UseofSpring.Data.Objects.StoredProcedureThe are simple domain objects in the Spring.DataQuickStart.Domainnamespace,collectionsofwhicharegenerallyreturnedfromtheDAOmethods.

38.1.1.DatabaseconfigurationTo get started running the 'unit test' you should configure the databaseconnection string. The listing inDataQuickStart.GenericTemplate.ExampleTests.xmlisshownbelow

<objectsxmlns="http://www.springframework.net"

xmlns:db="http://www.springframework.net/database">

<db:providerid="dbProvider"

provider="SqlServer-1.1"

connectionString="DataSource=(local);Database=Northwind;UserID=springqa;Password=springqa;Trusted_Connection=False"

<!--otherdefinitionsnotshown

Page 812: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</objects>

You should change the value of the provider element to correspond to youdatabase and the connection string as appropriate. Please refer to thedocumentationontheDbProviderabstractionfordetailsparticulartoyourdatabaseconfiguration.YoushouldalsoinstalltheNorthwinddatabase,whichisavailableforSqlServer 2005 from this download location. Theminimal schema to supportotherdatabaseprovidersmaybesupportedinthefuture.

38.1.1.1.AdoTemplateConfigurationThe various DAO objects refer to an instance of AdoTemplate which isresponsible for performing data access operations. This is declared inExampleTest.xmlasshownbelow

<objectid="adoTemplate"type="Spring.Data.Generic.AdoTemplate,Spring.Data"

<propertyname="DbProvider"ref="dbProvider"/>

<propertyname="DataReaderWrapperType"value="Spring.Data.Support.NullMappingDataReader,Spring.Data"

</object>

The property DbProvider refers to the database configuration you previouslydefined. Also the property DataReaderWrapper is set to theNullMappingDataReader that ships with Spring. This provides convenientdefault values for null values returned from the database. To readmore aboutAdoTemplate,refertothechapter,DataaccessusingADO.NET.

38.1.2.CommandCallbackThecodethatexercisestheuseofaCommandCallbackisshownbelow

[Test]

publicvoidCallbackDaoTest()

{

CommandCallbackDaocommandCallbackDao=ctx["commandCallbackDao"

intcount=commandCallbackDao.FindCountWithPostalCode(

Assert.AreEqual(3,count);

}

Page 813: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheconfigurationoftheCommandCallbackDaoisshownbelow

<objectid="commandCallbackDao"type="Spring.DataQuickStart.Dao.GenericTemplate.CommandCallbackDao,Spring.DataQuickStart"

<propertyname="AdoTemplate"ref="adoTemplate"/>

</object>

This the minimal configuration required for a DAO object, typically DAOobjects in your application will include other configuraiton information, forexampleproperties to specify themaximumsizeof the result set returned etc.TheimplementationoftheFindCountWithPostalCodeisshownbelow

publicvirtualintFindCountWithPostalCodeWithDelegate(

{

//Usinganonymousdelegatesallowsyoutoeasilyreferencethe

//surroundingparametersforusewiththeDbCommandprocessing.

returnAdoTemplate.Execute<int>(delegate(DbCommandcommand)

{

//DowhateveryoulikewiththeDbCommand...downcasttoget

//providerspecificfuntionalityifnecesary.

command.CommandText=cmdText;

DbParameterp=command.CreateParameter();

p.ParameterName="@PostalCode";

p.Value=postalCode;

command.Parameters.Add(p);

return(int)command.ExecuteScalar();

});

}

Anonymous delegates are used to specify the implementation of the callbackfunctionthatpassesinaDbCommandobject.YoucanthenusetheDbCommandobjectasyouseefittoaccessthedatabase.IfyouareusingSpring'sdelcarativetransaction management features then this DbCommand would have itstransaction and connection properties based on the context of the surroundingtransaction.AllresourcemanagementfortheDbCommandarehandledforyou

Page 814: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

bytheframework,aswellaserrorreportingonerroretc.Ifyouexecutethetest,itwillpass,assumingyouhaven'tmodifiedanydataintheNorthwinddatabasefromitsrawinstallation.

Page 815: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter39.TransactionsQuickStart

Page 816: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

39.1.IntroductionThe Transaction Quickstart demonstrates Spring's transaction managementfeatures. The database schema are two simple tables, credit and debit, whichcontain an Identifier and an Amount. The quick start shows the use ofdeclarative transactions using attributes and also the ability to change thetransactionmanager(localordistributed)viachangestoonly theconfigurationfiles - no code changes are required. It alsodemonstrates some techniques forunit and integration testing an application as well as separating Spring'sconfiguration files so that one is responsible for describing how the corebusinessclassesareconfiguredandothers thatareresponsiblefor thedatabaseenvironmentandapplicationofAOP.ThisquickstartassumesyouhaveinstalledawaytorunNUnittestswithinyourIDE.SomeexcellenttoolsthatletyoudothisareTestDriven.NETandReSharper.

Page 817: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

39.2.ApplicationOverviewThedesignoftheapplicationisverysimpleandconsistsoftwologicallayers,abusiness service layer in the namespace Spring.TxQuickStart.Services and aDAO layer in the namespace Spring.TxQuickStart.Dao. As this is just a toyexample the business service layer does nothing more than call two DAOobjects. The business service is to transfer money in a bank account and isblatantlytakenfromthebookProADO.NETbySahilMalik.Thetransferserviceisdefined by the interface IAccountManager with the implementationAccountManager located in the namespaceSpring.TxQuickStart.Services. The money is recorded in acreditanddebit tableinthedatabase.TheSQLServerschemafor the tables islocatedinthefileCreditsDebitsSchema.sql.TransferringthemoneyrequiresanACID operation on these two tables. The credit operation is defined via aIAccountCreditDao interface and the debit operation via anIAccountDebitDaointerface. Implementationsof these interfacesusingAdoTemplateareinthenamespaceSpring.TxQuickStart.Dao.Ado.

39.2.1.InterfacesTheManagerandDAOinterfacesareshownbelow

publicinterfaceIAccountManager

{

voidDoTransfer(floatcreditAmount,floatdebitAmount);

}

publicinterfaceIAccountCreditDao

{

voidCreateCredit(floatcreditAmount);

}

publicinterfaceIAccountDebitDao

{

voidDebitAccount(floatdebitAmount);

}

Page 818: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

39.3.ImplementationTheimplementationoftheAccountCreditDAOisshownbelow

publicclassAccountCreditDao:AdoDaoSupport,IAccountCreditDao

{

publicvoidCreateCredit(floatcreditAmount)

{

AdoTemplate.ExecuteNonQuery(CommandType.Text,

"insertintoCredits(CreditAmount)VALUES(@amount)"

creditAmount);

}

}

andfortheDebitDAO

publicclassAccountDebitDao:AdoDaoSupport,IAccountDebitDao

{

publicvoidDebitAccount(floatdebitAmount)

{

AdoTemplate.ExecuteNonQuery(CommandType.Text,

"insertintodbo.Debits(DebitAmount)VALUES(@amount)"

debitAmount);

}

}

BothoftheseDAOimplementationsinheritfromSpring'sAdoDaoSupportclass that provides convenient access to anAdoTemplate for performingdataaccessoperations.Withnootherpropertiesthatcanbeconfiguredintheseimplementations,theonlyconfigurationrequiredissettingofAdoDaoSupport'sDbProviderpropertyrepresentingtheconnectiontothedatabase.

Theimplementationof theservice layer interface,IAccountManager, isshownbelow.

publicclassAccountManager:IAccountManager

{

privateIAccountCreditDaoaccountCreditDao;

privateIAccountDebitDaoaccountDebitDao;

Page 819: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

privatefloatmaxTransferAmount=1000000;

publicAccountManager(IAccountCreditDaoaccountCreditDao,IAccountDebitDaoaccountDebitDao)

{

this.accountCreditDao=accountCreditDao;

this.accountDebitDao=accountDebitDao;

}

publicfloatMaxTransferAmount

{

get{returnmaxTransferAmount;}

set{maxTransferAmount=value;}

}

[Transaction]

publicvoidDoTransfer(floatcreditAmount,floatdebitAmount)

{

accountCreditDao.CreateCredit(creditAmount);

if(creditAmount>maxTransferAmount||debitAmount>maxTransferAmount)

{

thrownewArithmeticException("seeatellerbigspender..."

}

accountDebitDao.DebitAccount(debitAmount);

}

}

The if statement is a poor-mans representation of business logic, namely thatthere is apolicy thatdoesnot allow theuseof this service for amounts largerthan$1,000,000.Ifthecreditordebitamountislargerthan1,000,000thenandexceptionwillbethrown.WecanwriteaunittestthatwilltestforthisbusinesslogicandprovidestubimplementationsoftheDAOobjectssothatourtestsarenotonlyindependentofthedatabasebutwillalsoexecuteveryquickly.

Note

NoticetheTransactionattributeontheDoTransfermethod.ThisattributecanbereadbySpringandusedtocreateatransactional

Page 820: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

proxytoAccountManagerinordertoperformdeclarativetransactionmanagement.

TheNUnitunittestforAccountManagerisshownbelow

publicclassAccountManagerUnitTests

{

privateIAccountManageraccountManager;

[SetUp]

publicvoidSetup()

{

IAccountCreditDaostubCreditDao=newStubAccountCreditDao();

IAccountDebitDaostubDebitDao=newStubAccountDebitDao();

accountManager=newAccountManager(stubCreditDao,stubDebitDao);

}

[Test]

publicvoidTransferBelowMaxAmount()

{

accountManager.DoTransfer(217,217);

}

[Test]

[ExpectedException(typeof(ArithmeticException))]

publicvoidTransferAboveMaxAmount()

{

accountManager.DoTransfer(2000000,200000);

}

}

Running these tests we exercise both code pathways through the methodDoTransfer.NothingwehavedonesofarisSpringspecific(asidefromthepresence of the [Transaction] attribute.Now thatwe know the classworks inisolation, we can now 'wire' up the application for use in production byspecifyinghowtheserviceandDAOlayersarerelated.Thisconfigurationfileisshownbelowandcanlooselybereferredtoasyour'applicationblueprint'.Thisconfigurationfileisnamedapplication-config.xmlandisanembeddedresourceinsidethe'main'project,Spring.TxQuickStart.

<objectsxmlns='http://www.springframework.net'>

Page 821: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--DAOImplementations-->

<objectid="accountCreditDao"type="Spring.TxQuickStart.Dao.Ado.AccountCreditDao,Spring.TxQuickStart"

<propertyname="DbProvider"ref="CreditDbProvider"/>

</object>

<objectid="accountDebitDao"type="Spring.TxQuickStart.Dao.Ado.AccountDebitDao,Spring.TxQuickStart"

<propertyname="DbProvider"ref="DebitDbProvider"/>

</object>

<!--Theservicethatperformsmultipledataaccessoperations-->

<objectid="accountManager"

type="Spring.TxQuickStart.Services.AccountManager,Spring.TxQuickStart"

<constructor-argname="accountCreditDao"ref="accountCreditDao"

<constructor-argname="accountDebitDao"ref="accountDebitDao"

</object>

</objects>

This configuration is selecting the real ADO.NET implementations that willinsertrecordsintothedatabase.WecannowwriteaNUnitintegrationtestthatwill test the service and DAO layers. To do this we add on configurationinformation specific to our test environment. This extra configurationinformation will determine what databases we speak to and what transactionmanager(localordistribute)touse.ThecodeforthisintegrationstyleNUnittestisshownbelow

[TestFixture]

publicclassAccountManagerTests

{

privateAdoTemplateadoTemplateCredit;

privateAdoTemplateadoTemplateDebit;

privateIAccountManageraccountManager;

[SetUp]

publicvoidSetUp()

{

//ConfigureSpringprogrammatically

NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));

Page 822: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));

NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));

IApplicationContextcontext=newXmlApplicationContext(

"assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/system-test-local-config.xml"

);

accountManager=context["accountManager"]asIAccountManager;

CleanDb(context);

}

[Test]

publicvoidTransferBelowMaxAmount()

{

accountManager.DoTransfer(217,217);

intnumCreditRecords=(int)adoTemplateCredit.ExecuteScalar(CommandType.Text,

intnumDebitRecords=(int)adoTemplateDebit.ExecuteScalar(CommandType.Text,

Assert.AreEqual(1,numCreditRecords);

Assert.AreEqual(1,numDebitRecords);

}

[Test]

[ExpectedException(typeof(ArithmeticException))]

publicvoidTransferAboveMaxAmount()

{

accountManager.DoTransfer(2000000,200000);

}

privatevoidCleanDb(IApplicationContextcontext)

{

IDbProviderdbProvider=(IDbProvider)context["DebitDbProvider"

adoTemplateDebit=newAdoTemplate(dbProvider);

adoTemplateDebit.ExecuteNonQuery(CommandType.Text,

dbProvider=(IDbProvider)context["CreditDbProvider"

adoTemplateCredit=newAdoTemplate(dbProvider);

adoTemplateCredit.ExecuteNonQuery(CommandType.Text,

}

}

The essential element is to create an instance of Spring's application context

Page 823: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

where the relevant layers of the application are 'wired' together. TheIAccountManager implementation is retrieved from the IoC containerandstoredasafieldofthetestclass.Thebasiclogicofthetestisthesameasintheunittestbutinadditionthereistheverificationofactionsperformedinthedatabase.Thesetupmethodputsthedatabasetablesintoaknownstatebeforerunning the tests. Other techniques for performing integration testing that canalleviatetheneedtodoextensivedatabasestatemanagementforintegrationtestsisdescribedinthetestingsection.

Page 824: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

39.4.ConfigurationThe configuration file system-test-local-config.xml shown in the previousprogramlistingincludesapplication-config.xmlandspecifiesthedatabasetouseand the local (not distributed) transaction managerAdoPlatformTransactionManager.Thisconfigurationfileisshownbelow

<objectsxmlns="http://www.springframework.net"

xmlns:db="http://www.springframework.net/database"

xmlns:tx="http://www.springframework.net/tx">

<!--Importsapplicationconfiguration-->

<importresource="assembly://Spring.TxQuickStart/Spring.TxQuickStart/application-config.xml"

<!--Importsadditionalaspects-->

<!--

<importresource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"/>

-->

<!--DatabaseProviders-->

<db:providerid="DebitDbProvider"

provider="System.Data.SqlClient"

connectionString="DataSource=MARKT60\SQL2005;InitialCatalog=CreditsAndDebits;UserID=springqa;Password=springqa"

<db:providerid="CreditDbProvider"

provider="System.Data.SqlClient"

connectionString="DataSource=MARKT60\SQL2005;InitialCatalog=CreditsAndDebits;UserID=springqa;Password=springqa"

<aliasname="DebitDbProvider"alias="CreditDbProvider"/>

<!--TransactionManagerifusingasingledatabasethatcontainbothcreditanddebittables-->

<objectid="transactionManager"

type="Spring.Data.Core.AdoPlatformTransactionManager,Spring.Data"

<propertyname="DbProvider"ref="DebitDbProvider"/>

</object>

<!--Transactionaspect-->

Page 825: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<tx:attribute-driven/>

</objects>

Movingfromtop tobottom in theconfiguration file, the 'application-blueprint'configurationfileisincluded.Thenthedatabasetypeandconnectionparametersare specified for the twodatabases.The namesof theseprovidersmustmatchthosespecificinapplication-config.xml.Sincethetwonamespointtothesamedatabase,analiasconfigurationelementisusedtohavethempointtothesamedbProvider under different names. The type of transaction manager is thenselected, in this case we are showing the use of local transactions withAdoPlatformTransactionManager. Running the tests will result in 217 beingenteredintotheCreditsandDebitstableofeachdatabase.YoucanfireupSQLServerManagementStudioorequivalenttoverifythis.To switch to a distributed transaction you can refer to the configuration filesystem-test-dtc-config.xml,whichisshownbelow

<objectsxmlns='http://www.springframework.net'

xmlns:db="http://www.springframework.net/database"

xmlns:tx="http://www.springframework.net/tx">

<!--Importsapplicationconfiguration-->

<importresource="assembly://Spring.TxQuickStart/Spring.TxQuickStart/application-config.xml"

<!--Importsadditionalaspects-->

<!--

<importresource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"/>

-->

<db:providerid="DebitDbProvider"

provider="System.Data.SqlClient"

connectionString="DataSource=MARKT60\SQL2005;InitialCatalog=Debits;UserID=springqa;Password=springqa"

<db:providerid="CreditDbProvider"

provider="System.Data.SqlClient"

connectionString="DataSource=MARKT60\SQL2005;InitialCatalog=Credits;UserID=springqa;Password=springqa"

Page 826: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--TransactionManagerifusingtwodatabases,onecontainingthecredittableandtheotheradebittable-->

<objectid="transactionManager"

type="Spring.Data.Core.TxScopeTransactionManager,Spring.Data"

</object>

<!--Transactionaspect-->

<tx:attribute-driven/>

</objects>

TxScopeTransactionManager uses .NET 2.0 System.Transactions as theimplementation,allowingfordistributedtransactionsbetweenthe twodifferentdatabases listed. In a larger application the different layerswould typically bebroken up into individual configuration files and imported into the mainconfigurationfile.Thisallowsyourconfigurationtomirroryourarchitecture.You can also use the configuration file system-test-dtc-es-config.xml that willuseEnterpriseServicestoperformtransactionmanagement.

39.4.1.RollbackRulesUsingRollback rules allows you to specifywhich exceptionswill not cause arollbackandinsteadonlystopexecutionflow,committingtheworkdoneuptotheexception.Analternative implementationofAccountManager'sDoTransfermethod(includedinthesamplecode)isshownbelow.

[Transaction(NoRollbackFor=newType[]{typeof(ArithmeticException)})]

publicvoidDoTransfer(floatcreditAmount,floatdebitAmount)

{

accountCreditDao.CreateCredit(creditAmount);

if(creditAmount>maxTransferAmount||debitAmount>maxTransferAmount)

{

thrownewArithmeticException("seeatellerbigspender..."

}

accountDebitDao.DebitAccount(debitAmount);

}

Page 827: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AllthathaschangedistheuseoftheNoRollbackForpropertyonthetransactionattribute.Theexpectedbehavior is that thecredit tablewillbeupdatedeven though theexception is thrown. This is due to specifying that exceptions of the typeArithmethicExceptionshouldnotrollbackthedatabasetransaction.Runningthetestcodebelowverifiesthattheexceptionstillpropagatesoutofthemethod.

[Test]

publicvoidDeclarativeWithAttributesNoRollbackFor()

{

try

{

accountManager.DoTransfer(2000000,2000000);

Assert.Fail("ShouldhavethrownArithmeticException"

}catch(ArithmeticException){

intnumCreditRecords=(int)adoTemplateCredit.ExecuteScalar(CommandType.Text,

intnumDebitRecords=(int)adoTemplateDebit.ExecuteScalar(CommandType.Text,

Assert.AreEqual(1,numCreditRecords);

Assert.AreEqual(0,numDebitRecords);

}

}

Page 828: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

39.5.AddingadditionalAspectsTransactionaladviceisjustonetypeofadvicethatcanbeappliedtotheservicelayer.Youcanalsoconfigureotherpiecesofadvicetobeexecutedaspartofthegeneral advicechain that is associatedwithmethods that have theTransactionattribute applied. In this example we will add logging of thrown exceptionsusingSpring'sExceptionHandlerAdviceaswell as loggingof the service layermethod invocation. No code is required to be changed in order to have thisadditionalfunctionality.Insteadallyouhavetodoisuncommenttheline

<importresource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"

in either system-test-dtc-config.xml or system-test-local-config.xmlThe aspectconfigurationfileisshownbelow

<objectsxmlns='http://www.springframework.net'

xmlns:aop="http://www.springframework.net/aop">

<objectname="exceptionAdvice"type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice,Spring.Aop"

<propertyname="exceptionHandlers">

<list>

<value>onexceptionnameArithmeticExceptionlog'Logginganexceptionthrownfrommethod'+#method.Name

</list>

</property>

</object>

<objectname="loggingAdvice"type="Spring.Aspects.Logging.SimpleLoggingAdvice,Spring.Aop"

<propertyname="logUniqueIdentifier"value="true"/>

<propertyname="logExecutionTime"value="true"/>

<propertyname="logMethodArguments"value="true"/>

<propertyname="Separator"value=";"/>

<propertyname="HideProxyTypeNames"value="true"/>

<propertyname="UseDynamicLogger"value="true"/>

<propertyname="LogLevel"value="Info"/>

</object>

Page 829: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectid="txAttributePointcut"type="Spring.Aop.Support.AttributeMatchMethodPointcut,Spring.Aop"

<propertyname="Attribute"value="Spring.Transaction.Interceptor.TransactionAttribute,Spring.Data"

</object>

<aop:config>

<aop:advisorid="exceptionProcessAdvisor"order="1"

advice-ref="exceptionAdvice"

pointcut-ref="txAttributePointcut"/>

<aop:advisorid="loggingAdvisor"order="2"

advice-ref="loggingAdvice"

pointcut-ref="txAttributePointcut"/>

</aop:config>

</objects>

The transaction aspect is now additionally configured with an order value of"10",whichwill place it after the execution of the exception aspect,which isconfiguredtouseanordervalueof1.Thebehaviorforloggingtheexceptionisspecified by creating and configuring an instance ofSpring.Aspects.Exceptions.ExceptionHandlerAdvice

The location where that behavior is applied, the pointcut, is the Transactionattribute.The loggingofmethodargumentsandexecution time is specifiedbyconfiguring an instance ofSpring.Aspects.Logging.SimpleLoggingAdvice.TheAOPconfigurationsectiononthebottomiswhattiestogetherthebehaviorand where it will take place in the program flow. Under the covers thetransaction configuration, <tx:attribute-driven/> creates similar advice andpointcutdefinitions.Running the testTransferBelowMaxAmountwill then logthefollowingmessages

INFO-EnteringDoTransfer;45b6af04-b736-4efa-a489-45462726ddf2;creditAmount=217;debitAmount=217

INFO-ExitingDoTransfer;45b6af04-b736-4efa-a489-45462726ddf2;1328.125ms;return=

When the test caseof the testTransferAboveMaxAmount is run the followingmessagesarelogged

Page 830: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

INFO-EnteringDoTransfer;d94bc81b-a4ff-4ca1-9aaa-f2834f262307;creditAmount=2000000;debitAmount=200000

INFO-ExceptionthrowninDoTransferDoTransfer;d94bc81b-a4ff-4ca1-9aaa-f2834f262307;1140.625

System.ArithmeticException:seeatellerbigspender...

atSpring.TxQuickStart.Services.AccountManager.DoTransfer(SinglecreditAmount,SingledebitAmount)inL:\projects\Spring.Net\examples\Spring\Spring.TxQuickStart\src\Spring\Spring.TxQuickStart\TxQuickStart\Services\AccountManager.cs:line36

atSpring.DynamicReflection.Method_DoTransfer_ec48557f22b149958fd2243413136600.Invoke(Objecttarget,Object[]args)

atSpring.Reflection.Dynamic.SafeMethod.Invoke(Objecttarget,Object[]arguments)inl:\projects\Spring.Net\src\Spring\Spring.Core\Reflection\Dynamic\DynamicMethod.cs:line108

atSpring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint()inl:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\DynamicMethodInvocation.cs:line89

atSpring.Aop.Framework.AbstractMethodInvocation.Proceed()inl:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\AbstractMethodInvocation.cs:line257

atSpring.Transaction.Interceptor.TransactionInterceptor.Invoke(IMethodInvocationinvocation)inl:\projects\Spring.Net\src\Spring\Spring.Data\Transaction\Interceptor\TransactionInterceptor.cs:line80

atSpring.Aop.Framework.AbstractMethodInvocation.Proceed()inl:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\AbstractMethodInvocation.cs:line282

atSpring.Aspects.Logging.SimpleLoggingAdvice.InvokeUnderLog(IMethodInvocationinvocation,ILoglog)inl:\projects\Spring.Net\src\Spring\Spring.Aop\Aspects\Logging\SimpleLoggingAdvice.cs:line185

TRACE-LogginganexceptionthrownfrommethodDoTransfer

Page 831: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter40.NHibernateQuickStart

Page 832: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

40.1.IntroductionThis QuickStart application uses the all too familiar Northwind database andusesNHibernatebrowseandeditcustomers.ItItisaverysimpleapplicationthatdirectlyuses theDAOlayer insomecasesandalsohasa simple service layerthatsimulatedafullillmentprocess.Seetheintegrationtestsaswellforinsightinto how it works. The application uses Spring's declarative transactionmanagement features, HibernateTemplate helper class, and Open Session InViewmodule.

NoteTheexamplewillbeupdatedtonotuseHibernateTemplateandinsteadusethestandardNHibernateAPIinafuturerelease.AllfunctionalityisstillpresentwhenusingthestandardNHibernateAPI,asSpringtransactionmanagmentisintegratedintoNHibernateextensionpointsandexceptiontranslationisprovidedbyAOPadvice.SeethesectiontitledImplementingDAOsbasedonplainHibernate1.2/2.0API"inthehibernateormsectionofthereferencedocsformoreinformation.

Torun theapplicationmake theWebapplication theproject that startsandsetDefault.aspxasthestartpage.Youwillseealistofcustomers.Ifyouselect'edit'thenyoucanedit somecustomer infoandsave itbypressing the savebutton.NotethatyouwillneedtoexplicitlynavigatebacktotheDefault.aspxpageandreloaditinordertoseethechanges.

Page 833: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter41.QuartzQuickStart

Page 834: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

41.1.IntroductionInmanyapplicationstheneedarisestoperformacertainactionatagiventimewithout any user interaction, usually to perform some administrative tasks.Thesetasksneedtobescheduled,saytoperformajobintheearlyhoursofthemorningbeforethestartofbusiness.Thisfunctionalityisprovidedbyusingjobschedulingsoftware.Quartz.NETisanexcellentopensourcejobschedulerthatcan be used for these purposes. It provides a wealth of features, such aspersistentjobsandclustering.TofindoutmoreaboutQuartz.NETvisittheirwebsite. Spring integration allows you to use Spring to configure Quartz jobs,triggers,and schedulers andalsoprovides integrationwithSpring's transactionmanagementfeatures.The full details of Quartz are outside the scope of this quickstart but here is'quicktourfortheimpatient'ofthemainclassesandinterfacesusedinQuartzsoyou can get your sea legs. AQuartzIJob interface represents the task youwouldliketoexecute.YoueitherdirectlyimplementQuartz'sIJobinterfaceora convenience base class. The Quartz Trigger controls when a job isexecuted, for example in thewee hours of themorning everyweekday . ThiswouldbedoneusingQuartz'sCronTrigger implementation. Instancesofyour job are created every time the trigger fires. As such, in order to passinformationbetweendifferent jobinstancesyoustashdataaway inahashtablethat gets passed to the each Job instance upon its creation. Quartz'sJobDetailclasscombinestheIJobandthishashtableofdata.Insteadofthe standard System.Collections.Hashtable the classJobDataMapisused.TriggersareregisteredwithaQuartzISchedulerimplementationthatmanagestheoverallexecutionofthetriggersandjobs.TheStdSchedulerFactoryimplementationisgenerallyused.

Page 835: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

41.2.ApplicationOverviewThe sample applicationhas two typesof Jobs.One that inherits fromSpring'sconvenience base classQuartzJobObject and another which does notinherit fromanybase class.The latter class is adapted bySpring to be a Job.Two triggers, one for each of the jobs, are created. These triggers are in turnregistered with a scheduler. In each case the job implementation will writeinformationtotheconsolewhenitisexecuted.

Page 836: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

41.3.StandardjobschedulingTheSpringbaseclassQuartzJobObjectimplementsIJobandallowsfor your object's properties to be set via values that are stored insideQuartz'sJobDataMap that is passed along each time your job is instantiated due atriggerfiring.Thisclassisshownbelow

publicclassExampleJob:QuartzJobObject

{

privatestringuserName;

publicstringUserName

{

set{userName=value;}

}

protectedoverridevoidExecuteInternal(JobExecutionContextcontext)

{

Console.WriteLine("{0}:ExecuteInternalcalled,username:{1},nextfiretime{2}"

DateTime.Now,userName,context.NextFireTimeUtc.Value.ToLocalTime());

}

}

The methodExecuteInternal is called when the trigger fires and iswhereyouwouldputyourbusinesslogic.TheJobExecutionContextpassed in lets you access various pieces of information about the current jobexecution, such as the JobDataMap or information onwhen the next time thetrigger will fire. The ExampleJob is configured by creating aJobDetailobjectasshownbelowinthefollowingXMLsnippettakenfromspring-objects.xml

<objectname="exampleJob"type="Spring.Scheduling.Quartz.JobDetailObject,Spring.Scheduling.Quartz"

<propertyname="JobType"value="Spring.Scheduling.Quartz.Example.ExampleJob,Spring.Scheduling.Quartz.Example"

<!--WecaninjectvaluesthroughJobDataMap-->

<propertyname="JobDataAsMap">

<dictionary>

<entrykey="UserName"value="Alexandre"/>

Page 837: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</dictionary>

</property>

</object>

Thedictionary property of theJobDetailObject,JobDataAsMap,isused toset thevaluesof theExampleJob'sproperties.Thiswill result in theExampleJob being instantiated with it's UserName property value set to'Alexandre'thefirsttimethetriggerfires.Wethenwillschedulethisjobtobeexecutedon20secondincrementsofeveryminute as shown below using Spring's CronTriggerObject whichcreatesaQuartzCronTrigger.

<objectid="cronTrigger"type="Spring.Scheduling.Quartz.CronTriggerObject,Spring.Scheduling.Quartz"

<propertyname="jobDetail"ref="exampleJob"/>

<!--runevery20secondofminute-->

<propertyname="cronExpressionString"value="0/20****?"

</object>

Lastly,weschedulethistriggerwiththeschedulerasshownbelow

<objecttype="Spring.Scheduling.Quartz.SchedulerFactoryObject,Spring.Scheduling.Quartz"

<propertyname="triggers">

<list>

<refobject="cronTrigger"/>

</list>

</property>

</object>

Runningthisconfigurationwillproducethefollowingoutput

8/8/20081:29:40PM:ExecuteInternalcalled,username:Alexandre,nextfiretime8/8/20081:30:00PM

8/8/20081:30:00PM:ExecuteInternalcalled,username:Alexandre,nextfiretime8/8/20081:30:20PM

8/8/20081:30:20PM:ExecuteInternalcalled,username:Alexandre,nextfiretime8/8/20081:30:40PM

Page 838: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

41.4.SchedulingarbitrarymethodsasjobsIt is very convenient to schedule the execution of method as a job. TheAdminServiceclassintheexampledemonstratesthisfunctionalityandislistedbelow.

publicclassAdminService

{

privatestringuserName;

publicstringUserName

{

set{userName=value;}

}

publicvoidDoAdminWork()

{

Console.WriteLine("{0}:DoAdminWorkcalled,username:{1}"

}

}

Notethat itdoesnotinheritfromanybaseclass.ToinstructSpring tocreateaJobDetail object for this method we use Spring's factory object classMethodInvokingJobDetailFactoryObjectasshownbelow

<objectid="adminService"type="Spring.Scheduling.Quartz.Example.AdminService,Spring.Scheduling.Quartz.Example"

<!--weinjectstraighttotargetobject-->

<propertyname="UserName"value="admin-service"/>

</object>

<objectid="jobDetail"type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject,Spring.Scheduling.Quartz"

<!--Wedon'tactuallyneedtoimplementIJobaswecanusedelegation-->

<propertyname="TargetObject"ref="adminService"/>

<propertyname="TargetMethod"value="DoAdminWork"/>

</object>

Note thatAdminServiceobject is configuredusingSpring as youwoulddonormally,without consideration forQuartz.The trigger associatedwith thejobDetail object is listed below. Also note that when usingMethodInvokingJobDetailFactoryObject you can't use database persistence for

Page 839: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Jobs.Seetheclassdocumentationforadditionaldetails.

<objectid="simpleTrigger"type="Spring.Scheduling.Quartz.SimpleTriggerObject,Spring.Scheduling.Quartz"

<!--seetheexampleofmethodinvokingjobabove-->

<propertyname="jobDetail"ref="jobDetail"/>

<!--5seconds-->

<propertyname="startDelay"value="5s"/>

<!--repeatevery5seconds-->

<propertyname="repeatInterval"value="5s"/>

</object>

This creates an instances of Quartz's SimpleTrigger class (as compared to itsCronTrigger class used in the previous section). StartDelay andRepeatIntervalproperties areTimeSpanobjects than canbe set usingthe convenient strings such as 10s, 1h, etc, as supported by Spring's customTypeConverterforTimeSpans.This trigger can then be added to the scheduler's list of registered triggers asshownbelow.

<objecttype="Spring.Scheduling.Quartz.SchedulerFactoryObject,Spring.Scheduling.Quartz"

<propertyname="triggers">

<list>

<refobject="cronTrigger"/>

<refobject="simpleTrigger"/>

</list>

</property>

</object>

Theinterleavedoutputofboththesejobsbeingtriggeredisshownbelow.

8/8/20081:40:18PM:DoAdminWorkcalled,username:Gabriel

8/8/20081:40:20PM:ExecuteInternalcalled,username:Alexandre,nextfiretime8/8/20081:40:40PM

8/8/20081:40:23PM:DoAdminWorkcalled,username:Gabriel

8/8/20081:40:28PM:DoAdminWorkcalled,username:Gabriel

8/8/20081:40:33PM:DoAdminWorkcalled,username:Gabriel

8/8/20081:40:38PM:DoAdminWorkcalled,username:Gabriel

8/8/20081:40:40PM:ExecuteInternalcalled,username:Alexandre,nextfiretime8/8/20081:41:00PM

8/8/20081:40:43PM:DoAdminWorkcalled,username:Gabriel

8/8/20081:40:48PM:DoAdminWorkcalled,username:Gabriel

8/8/20081:40:53PM:DoAdminWorkcalled,username:Gabriel

Page 840: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

8/8/20081:40:58PM:DoAdminWorkcalled,username:Gabriel

8/8/20081:41:00PM:ExecuteInternalcalled,username:Alexandre,nextfiretime8/8/20081:41:20PM

8/8/20081:41:03PM:DoAdminWorkcalled,username:Gabriel

Page 841: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter42.NMSQuickStart

Page 842: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.1.IntroductionThe NMS quick start application demonstrates how to use asynchronousmessagingtoimplementasystemforpurchasingastock.Topurchaseastock,aclientapplicationwillsendastockrequestmessagecontainingthe informationaboutthestock,i.e.tickersymbol,quantity,etc.Theclientrequestmessagewillbe received by the server where it will perform business processing on therequest,forexampletodetermineiftheuserhassufficientcredittopurchasethestockoriftheuserisevenallowedtomakethepurchaseduetoexistingaccountrestrictions. These are typically external processes aswell. Usually the serverapplicationwill persist state about the request and forward it on to an executevenuewheretheactualexecutionofthestockrequestisperformed.Inaddition,marketdataforthestockwillbesentfromtheserverprocesstotheclient.Thehighlevelexchangeofinformationisshownbelow.

This example was developed with ActiveMQ 5.1 and the ActiveMQ NMSlibrarywithsubversionrepositorynumber685750.

Page 843: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.2.MessageDestinationsToimplementthisflowusingmessagingthefollowingqueuesandtopicswillbeused.AllrequestsfromtheclienttotheserverwillbesentonthequeuenamedAPP.STOCK.REQUEST.Responsestotherequestswillbesentfromtheservertotheclientonaqueueuniquetoeachclient.InthisexamplethequeuenameisoftheformAPP.STOCK.<UserName>,andmorespecificallyisconfiguredtobeAPP.STOCK.JOE.Market data does not need to be delivered to an individualclient asmanyclient applications are interested in this shared information.Assuch, the server will send market data information on a topic namedAPP.STOCK.MARKETDATA. The messaging communication between theserver and the execution venue is not included as part of the application. Anlocalimplementationoftheserviceinterfacethatrepresentstheexecutionvenueis used insteadof one based onmessaging or anothermiddleware technology.Themessagingflowshowingthequeuesandtopicsusedisshownbelow.

Queuesareshowninredandtopicsingreen.

Page 844: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.3.GatewaysGatewaysrepresenttheserviceoperationtosendamessage.Theclientwillsenda stock request to the server based on the contract defined by theIStockServiceinterface.

publicinterfaceIStockService

{

voidSend(TradeRequesttradeRequest);

}

TheserverwillsendmarketdatatotheclientsbasedonthecontractdefinedbytheIMarketDataServiceinterface.

publicinterfaceIMarketDataService

{

voidSendMarketData();

}

The market data gateway has no method parameters as it is assumed thatimplementations will manage the data to send internally. TheTradeRequestobject isoneofthedataobjects thatwillbeexchangedintheapplicationandisdiscussedinthenextsection.The use of interfaces allows for multiple implementations to be created.Implementations that use messaging to communicate will be based on theSpring's NmsGateway class and will be discussed later. stub or mockimplementationscanbeusedfortestingpurposes.

Page 845: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.4.MessageDataThe TradeRequest object shown above contains all the informationrequired to process a stock order. To promote the interoperability of this dataacross different platforms theTradeRequest class is generated from anXMLSchemausingMicrosoft'sSchemaDefinitionTool(xsd.exe).Theschemafortraderequestisshownbelow

<xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema"elementFormDefault

targetNamespace="http://www.springframework.net/nms/common/2008-08-05"

<xs:elementname="TradeRequest">

<xs:complexType>

<xs:sequence>

<xs:elementname="Ticker"type="xs:string"/>

<xs:elementname="Quantity"type="xs:long"/>

<xs:elementname="Price"type="xs:decimal"/>

<xs:elementname="OrderType"type="xs:string"/>

<xs:elementname="AccountName"type="xs:string"/>

<xs:elementname="BuyRequest"type="xs:boolean"/>

<xs:elementname="UserName"type="xs:string"/>

<xs:elementname="RequestID"type="xs:string"/>

</xs:sequence>

</xs:complexType>

</xs:element>

</xs:schema>

Runningxsd.exeonthisschemawillresultinaclassthatcontainspropertiesforeachof the elementnames.Apartial code listingof theTradeRequest class isshownbelow

//Thiscodewasgeneratedbyatool.

publicpartialclassTradeRequest{

publicstringTicker{

get{

returnthis.tickerField;

}

set{

Page 846: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

this.tickerField=value;

}

}

publiclongQuantity{

get{

returnthis.quantityField;

}

set{

this.quantityField=value;

}

}

//Additionalpropertiesnotshownforbrevity.

}

The schema and the TradeRequest class are located in the projectSpring.NmsQuickStart.Common. This common project will besharedbetweentheserverandclientforconvenience.WhensendingaresponsebacktotheclientthetypeTradeResponsewillbeused.TheschemafortheTradeResponseisshownbelow

<xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema"elementFormDefault

targetNamespace="http://www.springframework.net/nms/common/2008-08-05"

<xs:elementname="TradeResponse">

<xs:complexType>

<xs:sequence>

<xs:elementname="Ticker"type="xs:string"/>

<xs:elementname="Quantity"type="xs:integer"/>

<xs:elementname="Price"type="xs:decimal"/>

<xs:elementname="OrderType"type="xs:string"/>

<xs:elementname="Error"type="xs:boolean"/>

<xs:elementname="ErrorMessage"type="xs:string"/>

</xs:sequence>

</xs:complexType>

</xs:element>

</xs:schema>

Page 847: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

TheTradeResponsetypealsogeneratedfromaschemausingxsd.exe.Apartialcodelistingisshownbelow

//Thiscodewasgeneratedbyatool.

publicpartialclassTradeResponse{

publicstringTicker{

get{

returnthis.tickerField;

}

set{

this.tickerField=value;

}

}

publiclongQuantity{

get{

returnthis.quantityField;

}

set{

this.quantityField=value;

}

}

//Additionalpropertiesnotshownforbrevity.

}

ThemarketdatainformationwillbesentusingaHashtabledatastructure.

Page 848: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.5.MessageHandlersWhen the TradeRequest message is received by the server, it will behandled by the classSpring.NmsQuickStart.Server.Handlers.StockAppHandler

shownbelow

publicclassStockAppHandler

{

privateIExecutionVenueServiceexecutionVenueService;

privateICreditCheckServicecreditCheckService;

privateITradingServicetradingService;

publicTradeResponseHandle(TradeRequesttradeRequest)

{

TradeResponsetradeResponse;

IListerrors=newArrayList();

if(creditCheckService.CanExecute(tradeRequest,errors))

{

tradeResponse=executionVenueService.ExecuteTradeRequest(tradeRequest);

tradingService.ProcessTrade(tradeRequest,tradeResponse);

}

else

{

tradeResponse=newTradeResponse();

tradeResponse.Error=true;

tradeResponse.ErrorMessage=errors[0].ToString();

}

returntradeResponse;

}

}

The stub implementations of the services, located in the namespaceSpring.NmsQuickStart.Server.Services.Stubs, willresult in always sending back a error-free trade responsemessage. A realisticimplementationwould likely have the execution venue and trading service beremote services and the trading service could be implemented as a localtransactionalservicelayerthatusesspring'sdeclarativetransactionmanagement

Page 849: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

features.TheclientwillreceiveaTradeResponsemessageaswellasaHashtableofdatarepresenting the market data. The message handle for the client is the classSpring.NmsQuickStart.Client.Handlers.StockAppHandlerandisshownbelow.

publicclassStockAppHandler

{

//definitionofstockControlleromittedforbrevity.

publicvoidHandle(Hashtabledata)

{

//forwardtocontrollertoupdateview

stockController.UpdateMarketData(data);

}

publicvoidHandle(TradeResponsetradeResponse)

{

//forwardtocontrollertoupdateview

stockController.UpdateTrade(tradeResponse);

}

}

WhatisimportanttonoteaboutthesehandlersisthattheycontainnomessagingAPI artifacts. As such you can write unit and integration tests against theseclassesindependentofthemiddleware.Themissinglinkbetweenthemessagingworld and the objects processed by the message handlers are messageconverters. Spring's messaging helper classes, i.e.SimpleMessageListenerContainer andNmsTemplate usemessage converters topass data to the handlers and to send data via messaging for gatewayimplementations

Page 850: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.6.MessageConvertersThe implementation of IMessageConverter used isSpring.NmsQuickStart.Common.Converters.XmlMessageConverter

This converter adds the ability tomarshal and unmarshal objects to and fromXML strings. It also uses Spring's SimpleMessageConverter toconvertHashtables,strings,andbytearrays.Inordertopassinformationabouttheserialized type, type information isput in themessageproperties.The typeinformationcanbeeithertheclassnameoranintegervalueidentifyingthetype.In systems where the client and server are deployed together and are tightlycoupled, sharing the class name is a convenient shortcut. The alternative is toregister a type for a given integer value. The XML configuration used toconfiguretheseobjectsisshownbelow

<objectname="XmlMessageConverter"type="Spring.NmsQuickStart.Common.Converters.XmlMessageConverter,Spring.NmsQuickStart.Common"

<propertyname="TypeMapper"ref="TypeMapper"/>

</object>

<objectname="TypeMapper"type="Spring.NmsQuickStart.Common.Converters.TypeMapper,Spring.NmsQuickStart.Common"

<!--usesimpleconfiguationstyle-->

<propertyname="DefaultNamespace"value="Spring.NmsQuickStart.Common.Data"

<propertyname="DefaultAssemblyName"value="Spring.NmsQuickStart.Common"

</object>

Thisconfigurationiscommonbetweentheserverandtheclient.

Page 851: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.7.MessagingInfrastructureTheimplementationsofthegatewayinterfacesinheritfromSpring'shelperclassNmsGatewaySupport inorder togeteasyaccess toaNmsTemplate forsending. The implementation of theIStockService interface is shownbelow

publicclassNmsStockServiceGateway:NmsGatewaySupport,IStockService

{

privateIDestinationdefaultReplyToQueue;

publicIDestinationDefaultReplyToQueue

{

set{defaultReplyToQueue=value;}

}

publicvoidSend(TradeRequesttradeRequest)

{

NmsTemplate.ConvertAndSendWithDelegate(tradeRequest,

{

message.NMSReplyTo=defaultReplyToQueue;

message.NMSCorrelationID=

});

}

}

The Send method is using NmsTemplate'sConvertAndSendWithDelegate(object obj,

MessagePostProcessorDelegate

messagePostProcessorDelegate) method. The anonymousdelegateallowsyoutomodifythemessageproperties,suchasNMSReplyToandNMSCorrelationID after the message has been converted from an object butbeforeithasbeensent.Theuseofananonymousdelegateallowsmakesitveryeasytoapplyanypostprocessinglogictotheconvertedmessage.The object definition for the NmsStockServiceGateway is shownbelow along with its dependent object definitions of NmsTemplate and theConnectionFactory.

Page 852: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<objectname="StockServiceGateway"type="Spring.NmsQuickStart.Client.Gateways.NmsStockServiceGateway,Spring.NmsQuickStart.Client"

<propertyname="NmsTemplate"ref="NmsTemplate"/>

<propertyname="DefaultReplyToQueue">

<objecttype="Apache.NMS.ActiveMQ.Commands.ActiveMQQueue,Apache.NMS.ActiveMQ"

<constructor-argvalue="APP.STOCK.JOE"/>

</object>

</property>

</object>

<objectname="NmsTemplate"type="Spring.Messaging.Nms.Core.NmsTemplate,Spring.Messaging.Nms"

<propertyname="ConnectionFactory"ref="ConnectionFactory"

<propertyname="DefaultDestinationName"value="APP.STOCK.REQUEST"

<propertyname="MessageConverter"ref="XmlMessageConverter"

</object>

<objectid="ConnectionFactory"type="Apache.NMS.ActiveMQ.ConnectionFactory,Apache.NMS.ActiveMQ"

<constructor-argindex="0"value="tcp://localhost:61616"

</object>

In this example the 'raw'Apache.NMS.ActiveMQ.ConnectionFactory connectionfactory was used. It would be more efficient resource wise to use Spring'sCachingConnectionFactorywrapperclasssothatconnectionswillnot be open and closed for each message send as well as allowing for thecachingofother intermediateNMSAPIobjects such as sessions andmessageproducers.A similar configuration is used on the server to configure the classSpring.NmsQuickStart.Server.Gateways.MarketDataServiceGateway

thatimplementstheIMarketDataServiceinterface.Since the client is also a consumer of messages, on the topicAPP.STOCK.MARKETDATA and the queue APP.STOCK.JOE (for TraderJoe!),twomessagelistenercontainersaredefinedasshownbelow.

<nms:listener-containerconnection-factory="ConnectionFactory"

<nms:listenerref="MessageListenerAdapter"destination="APP.STOCK.JOE"

<nms:listenerref="MessageListenerAdapter"destination="APP.STOCK.MARKETDATA"

</nms:listener-container>

Refertothemessagesreferencedocsforalltheavailableattributestoconfigurethe

Page 853: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

containerandalsothesectiononregisteringtheNMSschemawithSpring..On the server we define a message listener container for the queueAPP.STOCK.REQUEST but set the concurrency property to 10 so that 10threadswillbeconsumingmessagesfromthequeue.

<nms:listener-containerconnection-factory="ConnectionFactory"

<nms:listenerref="MessageListenerAdapter"destination="APP.STOCK.REQUEST"

</nms:listener-container>

Page 854: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

42.8.RunningtheapplicationTo run both the client and servermake sure that you select 'Multiple StartupProjects' within VS.NET. The GUI has a button to make a hardcoded traderequestandshowconfirmation ina textbox.Atextarea isused todisplay themarket data. There is a 'Get Portfolio' button that is not implemented at themoment.ApictureoftheGUIafterithasbeenrunningforawhileandtradehasbeensentandrespondedtoisshownbelow

Page 855: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter43.MSMQQuickStart

Page 856: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.1.IntroductionThe MSMQ quick start application demonstrates how to use asynchronousmessaging to implement a system for purchasing a stock. Is follows the samebasic approach as in the NMS QuickStart but is adapted as need for use withMSMQ.Please read the introduction in that chapter toget anoverviewof thesystem.When there is direct overlap in functionality between the MSMQ and NMSquickstart a reference to the appropriate section in the NMS QuickStartdocumentationisgiven.

Page 857: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.2.MessageDestinationsTo communicate between th client and server a pair of queues will be used.Messages sent from the client to the server will use the transactional queuenamed .\Private$\request.txqueue. Messages sent from theserver to the client will use the transactional queue.\Private$\response.joe.txqueue. The queue for messagesthatcannotbeprocessed, socalled 'poisonmessages'willbesent to thequeue.\Private$\dead.queue. You can create these queues using thecomputer management administration console. Private queues are used tosimplifytheapplicationsetuprequirements.SinceMSMQdoesnotnativelysupportthepublish-subscribemessagingstyleasinothermessaging systems,ApacheMQ, IBMWebsphereMQ,TIBCOEMS,themarketdatainformationissentonthesamequeueastheresponsesfromtheservertotheclientfortraderequests..

Page 858: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.3.GatewaysThegatewayinterfacesarethesameasthosedescribedintheNMSQuickStarthere.

Page 859: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.4.MessageDataTradeRequestandTradeResponsemessagesaredefinedusingXMLSchemaandclassesaregeneratedfromthatschema.ThisisthesameapproachasdescribedinmoredetailsintheNMSQuickStarthere.Animportantdifferenceinthetypesofmessagedataformatssupported'out-of-the-box' with Apache, IBM, TIBCO as compared toMicrosoftMSMQ is thelattersupportsendingahashtabledatastructure.Asa result, thehashtable thatwas used to send market data information from the server to the client waschangedtobeoftypeSystem.StringintheMSMQexample.

Page 860: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.5.MessageHandlersThemessagehandlersare the sameasused in theNMSQuickStarthere,asidefromthechangeofthehashtabledatastructuretoastring.Thisisanimportantbenefitofenforcingaseparationbetweenthemessagingspecificclassesandthebusinessprocessinglayer.

Page 861: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.6.MessageConvertersThe message converter used isSpring.Messaging.Support.Converters.XmlMessageConverter. It is configuredby specifying the data types that will be send and received. Here is aconfiguration example for types generated from theXMLSchema and a plainstring.

<objectid="xmlMessageConverter"type="Spring.Messaging.Support.Converters.XmlMessageConverter,Spring.Messaging"

<propertyname="TargetTypes">

<list>

<value>Spring.MsmqQuickStart.Common.Data.TradeRequest,Spring.MsmqQuickStart.Common

<value>Spring.MsmqQuickStart.Common.Data.TradeResponse,Spring.MsmqQuickStart.Common

<value>System.String,mscorlib</value>

</list>

</property>

</object>

Page 862: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.7.MessagingInfrastructureTheimplementationsofthegatewayinterfacesinheritfromSpring'shelperclassMessageQueueGatewaySupport in order to get easy access to aMessageQueueTemplate for sending. The implementation of theIStockServiceinterfaceisshownbelow

publicclassMsmqStockServiceGateway:MessageQueueGatewaySupport

{

privateRandomrandom=newRandom();

privatestringdefaultResponseQueueObjectName;

publicstringDefaultResponseQueueObjectName

{

set{defaultResponseQueueObjectName=value;}

}

publicvoidSend(TradeRequesttradeRequest)

{

MessageQueueTemplate.ConvertAndSend(tradeRequest,delegate

{

message.ResponseQueue=GetResponseQueue();

message.AppSpecific=random.Next();

});

}

privateMessageQueueGetResponseQueue()

{

returnMessageQueueFactory.CreateMessageQueue(defaultResponseQueueObjectName);

}

}

The Send method is using MessageQueueTemplate'sConvertAndSend(object obj,

MessagePostProcessorDelegate

messagePostProcessorDelegate) method. The anonymous

Page 863: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

delegateallowsyoutomodify themessageproperties,suchasResponseQueueandAppSpecificafterthemessagehasbeenconvertedfromanobjectbutbeforeithasbeensent.Theuseofananonymousdelegateallowsmakesitveryeasytoapplyanypostprocessinglogictotheconvertedmessage.The configuration for MsmqStockServiceGateway and all itsdependenciesisshownbelow,highlightingimportantdependencylinks.

<objectname="stockServiceGateway"type="Spring.MsmqQuickStart.Client.Gateways.MsmqStockServiceGateway,Spring.MsmqQuickStart.Client"

<propertyname="MessageQueueTemplate"ref="messageQueueTemplate

<propertyname="DefaultResponseQueueObjectName"value="responseTxQueue"

</object>

<objectid="messageQueueTemplate"type="Spring.Messaging.Core.MessageQueueTemplate,Spring.Messaging">

<propertyname="DefaultMessageQueueObjectName"value="requestTxQueue"

<propertyname="MessageConverterObjectName"value="xmlMessageConverter

</object>

<objectid="xmlMessageConverter"type="Spring.Messaging.Support.Converters.XmlMessageConverter,Spring.Messaging">

<propertyname="TargetTypes">

<list>

<value>Spring.MsmqQuickStart.Common.Data.TradeRequest,Spring.MsmqQuickStart.Common

<value>Spring.MsmqQuickStart.Common.Data.TradeResponse,Spring.MsmqQuickStart.Common

<value>System.String,mscorlib</value>

</list>

</property>

</object>

<objectid="requestTxQueue"type="Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging"

<propertyname="Path"value=".\Private$\request.txqueue"/>

<propertyname="MessageReadPropertyFilterSetAll"value="true"

</object>

<objectid="responseTxQueue"type="Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging"

<propertyname="Path"value=".\Private$\response.joe.txqueue"

<propertyname="MessageReadPropertyFilterSetAll"value="true"

</object>

Since the client also needs to listen to incoming messages on theresponseTxQueue, aTransactionalMessageListenerContainer is configured.

Page 864: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Theconfigurationforthemessagelistenercontainerandallitsdependenciesisshownbelow,highlightingimportantdependencylinks.

<!--MSMQTransactionManager-->

<objectid="messageQueueTransactionManager"type="Spring.Messaging.Core.MessageQueueTransactionManager,Spring.Messaging"

<!--MessageListenerContainerthatusesMSMQtransactionalforreceives-->

<objectid="transactionalMessageListenerContainer"type="Spring.Messaging.Listener.TransactionalMessageListenerContainer,Spring.Messaging"

<propertyname="MessageQueueObjectName"value="responseTxQueue"

<propertyname="PlatformTransactionManager"ref="messageQueueTransactionManager"

<propertyname="MessageListener"ref="messageListenerAdapter

<propertyname="MessageTransactionExceptionHandler"ref="sendToQueueExceptionHandler

</object>

<!--Delegatetoplain.NETobjectformessagehandling-->

<objectid="messageListenerAdapter"type="Spring.Messaging.Listener.MessageListenerAdapter,Spring.Messaging">

<propertyname="HandlerObject"ref="stockAppHandler"/>

<propertyname="DefaultHandlerMethod"value="Handle"/>

<propertyname="MessageConverterObjectName"value="xmlMessageConverter"

</object>

<objectid="sendToQueueExceptionHandler"type="Spring.Messaging.Listener.SendToQueueExceptionHandler,Spring.Messaging">

<propertyname="MessageQueueObjectName"value="deadTxQueue

</object>

<objectid="deadTxQueue"type="Spring.Messaging.Support.MessageQueueFactoryObject,Spring.Messaging">

<propertyname="Path"value=".\Private$\dead.queue"/>

<propertyname="MessageReadPropertyFilterSetAll"value="true"

</object>

A similar configuration is used on the server to configure the classSpring.MsmqQuickStart.Server.Gateways.MarketDataServiceGateway

that implements the IMarketDataService interface and aTransactionalMessageListenerContainer to processmessages on the requestTxQueue.You can increase the number of processingthread in theTransactionalMessageListenerContainerbysettingthepropertyMaxConcurrentListeners,thedefaultvalueis1.

Page 865: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

43.8.RunningtheapplicationTo run both the client and servermake sure that you select 'Multiple StartupProjects' within VS.NET. The GUI has a button to make a hard coded traderequestandshowconfirmation ina textbox.Atextarea isused todisplay themarket data. There is a 'Get Portfolio' button that is not implemented at themoment.ApictureoftheGUIafterithasbeenrunningforawhileandtradehasbeensentandrespondedtoisshownbelow.

Page 866: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter44.WCFQuickStart

Page 867: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

44.1.IntroductionTheWCF quickstart application shows how to configure yourWCF servicesusingdependencyinjectionandhowtotoapplyAOPadvicetoyourservices.Itis based on the same interfaces used in the portable service abstractions quickstartexample that demonstrates similar features for .NET Remoting, EnterpriseServices,andASMXwebsevices.ThequickstartexampleisonlyavailableasaVS.NET2008solution.Therearetwoserverapplicationsinthesolution,oneisawebapplicationwherethe WCF service will be hosted, and the other is a self-hosting consoleapplication,Spring.WcfQuickStart.Server.2008.TheclientapplicationislocatedinSprng.WcfQuickStart.ClientApp.2008.Torunthesolutionmakesurethatallthreeprojectsaresettostartup.

Page 868: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

44.2.TheserversideTheservicecontractisshownbelow

[ServiceContract(Namespace="http://Spring.WcfQuickStart"

publicinterfaceICalculator

{

[OperationContract]

doubleAdd(doublen1,doublen2);

[OperationContract]

doubleSubtract(doublen1,doublen2);

[OperationContract]

doubleMultiply(doublen1,doublen2);

[OperationContract]

doubleDivide(doublen1,doublen2);

[OperationContract]

stringGetName();

}

andtheimplementationisstraightforward,onlyaddingapropertythatcontrolshow long each method should sleep. An abbreviated listing of theimplementationisshownbelow

publicclassCalculatorService:ICalculator

{

privateintsleepInSeconds;

publicintSleepInSeconds

{

get{returnsleepInSeconds;}

set{sleepInSeconds=value;}

}

publicdoubleAdd(doublen1,doublen2)

{

Thread.Sleep(sleepInSeconds*1000);

returnn1+n2;

}

//othermethodsomittedforbrevity.

Page 869: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

44.2.1.WCFDependency InjectionandAOPinself-hostedapplicationTheapproachusingdynamicproxiesisusedintheconsoleapplicationinsidetheSpring.WcfQuickStart.Server.2008 project. For more information on thisapproach refer to this section in the reference docs. The configuration of yourserviceisdoneasyouwouldtypicallydowithSpring,includingapplyingofanyAOPadvice.TheclassishostedinsidetheconsoleapplicationthroughtheuseofSpring's ServiceHostFactoryObject exporter. The configurationfortheserverconsoleapplicationisshownbelow.

<objectsxmlns="http://www.springframework.net"

xmlns:aop="http://www.springframework.net/aop">

<!--Servicedefinition-->

<objectid="calculator"singleton="false"

type="Spring.WcfQuickStart.CalculatorService,Spring.WcfQuickStart.ServerApp"

<propertyname="SleepInSeconds"value="1"/>

</object>

<objectid="serviceOperation"type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut,Spring.Aop"

<propertyname="pattern"value="Spring.WcfQuickStart.*"

</object>

<objectid="perfAdvice"type="Spring.WcfQuickStart.SimplePerformanceInterceptor,Spring.WcfQuickStart.ServerApp"

<propertyname="Prefix"value="ServiceLayerPerformance"

</object>

<aop:config>

<aop:advisorpointcut-ref="serviceOperation"advice-ref

</aop:config>

<!--hosttheserviceobject-->

<objectid="calculatorServiceHost"type="Spring.ServiceModel.Activation.ServiceHostFactoryObject,Spring.Services"

<propertyname="TargetName"value="calculator"/>

</object>

Page 870: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</objects>

Look at the standardWCF configuration section in App.config for additionalconfiguration details. In that section you will see that the name of theWCFservicecorrespondstothenameoftheserviceobjectinsidethespringcontainer.

44.2.2. WCF Dependency Injection and AOP in IIS webapplicationMuch of the configuration ob the objects is the same as before, the .svc filethoughrefers to thenameof theservice inside theSpringcontainer aswell asusingSpring'sSpring.ServiceModel.Activation.ServiceHostFactory.The.svcfileisshownbelow.

<%@ServiceHostLanguage="C#"Debug="true"Service="calculator"

Factory="Spring.ServiceModel.Activation.ServiceHostFactory"

Page 871: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

44.3.ClientaccessTheprojectSpring.WcfQuickStart.ClientApp.2008isaconsoleapplication thatcalls the two WCF services. It creates a client side proxy based on usingChannelFactory<T>.CreateChannel.Runningtheclientapplicationproducesthefollowingoutput.

---Press<return>tocontinue---

WebCalculator

Add(1,1):2

Divide(11,2):5.5

Multiply(2,5):10

Subtract(7,4):3

ServerAppCalculator

Add(1,1):2

Divide(11,2):5.5

Multiply(2,5):10

Subtract(7,4):3

---Press<return>tocontinue---

Page 872: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

PartVIII.Spring.NETforJavadevelopersThispartofthereferencedocumentationisforJavadeveloperswhowouldlikeaquickorientationtowhatisdifferentbetweentheJavaand.NETversionsoftheframework.

Chapter45,Spring.NETforJavaDevelopers

Page 873: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Chapter45.Spring.NETforJavaDevelopers

Page 874: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

45.1.IntroductionThischapteristohelpJavadevelopersgettheirsealegsusingSpring.NET.Itisnotintendedtobeacomprehensivecomparisonbetween.NETandJava.Rather,ithighlightstheday-to-daydifferencesyouwillexperiencewhenyoustarttouseSpring.NET.

Page 875: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

45.2.BeanstoObjectsThereare somesimplenamechanges,basicallyeverywhereyousaw theword'bean' you will now see the word 'object'. A comparison of a simple Springconfiguration file highlights these small name changes. Here is theapplication.xmlfileforthesampleMovieFinderapplicationinSpring.Java

<!DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<beanid="MyMovieLister"class="MovieFinder.MovieLister">

<propertyname="finder"ref="MyMovieFinder"/>

</bean>

<beanid="MyMovieFinder"class="MovieFinder.SimpleMovieFinder"

</beans>

HereisthecorrespondingfileinSpring.NET

<objectsxmlns="http://www.springframework.net"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.nethttp://www.springframework.net/xsd/spring-objects-1.1.xsd"

<objectname="MyMovieLister"

type="Spring.Examples.MovieFinder.MovieLister,Spring.Examples.MovieFinder"

<propertyname="movieFinder"ref="MyMovieFinder"/>

</object>

<objectname="MyMovieFinder"

type="Spring.Examples.MovieFinder.SimpleMovieFinder,Spring.Examples.MovieFinder"

</objects>

As you can easily see the <beans> and <bean> elements are replaced by<objects> and<object> elements. The class definition in Spring.Java containsthe fullyqualifiedclassname.TheSpring.NETversionalso contains the fullyqualified classname but in addition specifies the name of the assemblywherethat type is located. This is necessary since .NET does not have a 'classpath'concept.Assemblynamesin.NETcanhaveuptofourpartstodescribetheexactversion.TheotherXMLSchemaelementsinSpring.NETarethesameasinSpring.Java'sDTD except for specifying string based key value pairs. In Java this isrepresented by the java.util.Properties class and the xml element is name<props>asshownbelow

Page 876: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<propertyname="people">

<props>

<propkey="PennAndTeller">Themagicproperty</prop>

<propkey="GeorgeCarlin">Thefunnyproperty</prop>

</props>

</property>

In .NET the analogous class isSystem.Collections.Specialized.NameValueCollection and is representedby thexmlelement<name-values>.Thelistingoftheelementsalsofollowsthe.NETconventionofapplicationconfigurationfilesusingthe<add>elementwith'key'and'value'attributes.Thisisshowbelow

<propertyname="people">

<name-values>

<addkey="PennAndTeller"value="Themagicproperty"/>

<addkey="GeorgeCarlin"value="Thefunnyproperty"/>

</name-values>

</property>

Page 877: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

45.3.PropertyEditorstoTypeConvertersPropertyEditorsfromthejava.beanspackageprovidetheabilitytoconvertfromastringtoaninstanceofaJavaclassandvice-versa.Forexample,tosetastringarray property, a comma delimited string can be used. The Java class thatprovides this functionality is the appropriately namedStringArrayPropertyEditor. In .NET, TypeConverters from theSystem.ComponentModel namespace provide the same functionality. The typeconversionfunctionalityin.NETalsoallowsforTypeConverterstobeexplicitlyregisteredwithadatatype.Thisallowsfortransparentsettingofcomplexobjectproperties.However, some classes in the .NET framework do not support thestyleofconversionweareusedtofromSpring.Java,suchassettingofastring[]withacommadelimitedstring.Thetypeconverter,StringArrayConverterintheSpring.Objects.TypeConvertersnamespaceisthereforeexplicitlyregisteredwithSpring.NETinordertoprovidethisfunctionality.AsinthecaseofSpring.Java,Spring.NET allows user defined type converters to be registered. However, ifyouarecreatingacustomtypein.NET,usingthestandard.NETmechanismsfortypeconversionisthepreferredapproach.

Page 878: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

45.4.ResourceBundle-ResourceManager

Page 879: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

45.5.ExceptionsExceptions in Java can either be checked or unchecked. .NET supports onlyunchecked exceptions. Spring.Java prefers the use of unchecked exceptions,frequentlymaking conversions from checked to unchecked exceptions. In thisrespectSpring.Javaissimilartothedefaultbehaviorof.NET

Page 880: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

45.6.ApplicationConfigurationIn Spring.Java it is very common to create an ObjectFactory orApplicationContextfromanexternalXMLconfigurationfileThisfunctionalityis also provided in Spring.NET. However, in .NET the System.Configurationnamespaceprovidessupportformanagingapplicationconfigurationinformation.The functionality in this namespace depends on the availability of speciallynamedfiles:Web.configforASP.NETapplicationsand<MyExe>.exe.configforWinFormsandconsoleapplications.<MyExe>isthenameofyourexecutable.Aspart of the compilationprocess, if youhave a file nameApp.config in therootofyourproject, the compilerwill rename the file to<MyExe>.exe.configandplaceitintotheruntimeexecutablefolder.TheseapplicationconfigurationfilesareXMLbasedandcontainconfigurationsectionsthatcanbereferencedbynametoretrievecustomconfigurationobjects.In order to inform the .NET configuration system how to create a customconfiguration object from one of these sections, an implementation of theinterface, IConfigurationSectionHandler, needs to be registered. Spring.NETprovides two implementations, one to create an IApplicationContext from a<context> section and another to configure the context with objectdefinitionscontainedinan<objects>section.The<context> sectionis very powerful and expressive. It provides full support for locating allIResourceviaUrisyntaxandhierarchicalcontextswithoutcodingorusingmoreverboseXMLaswouldberequiredinthecurrentversionofSpring.Java

<?xmlversion="1.0"encoding="utf-8"?>

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="context"type="Spring.Context.Support.ContextHandler,Spring.Core"

<sectionname="objects"type="Spring.Context.Support.DefaultSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<context>

<resourceuri="config://spring/objects"/>

Page 881: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</context>

<objects>

<description>AnexamplethatdemonstratessimpleIoCfeatures.

<objectname="MyMovieLister"type="Spring.Examples.MovieFinder.MovieLister,MovieFinder"

<propertyname="movieFinder"ref="AnotherMovieFinder"

</object>

<objectname="MyMovieFinder"type="Spring.Examples.MovieFinder.SimpleMovieFinder,MovieFinder"

<!--

AnIMovieFinderimplementationthatusesatextfileasit'smoviesource...

-->

<objectname="AnotherMovieFinder"type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder,MovieFinder"

<constructor-argindex="0"value="movies.txt"

</object>

</objects>

</spring>

</configuration>

The<configSections>and<section>elementsarea standardpart of the .NETapplicationconfigurationfile.TheseelementsareusedtoregisteraninstanceofIConfigurationSectionHandlerandassociate itwithanotherxmlelement in thefile,inthiscasethe<context>and<objects>elements.ThefollowingcodesegmentisusedtoretrievetheIApplicationContextfromthe.NETapplicationconfigurationfile.

IApplicationContextctx

=ConfigurationUtils.GetSection("spring/context")

In order to enforce the usage of the named configuration sectionspring/context thepreferred instantiationmechanismisvia theuseoftheregistryclassContextRegistryasshownbelow

IApplicationContextctx=ContextRegistry.GetContext();

Page 882: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

45.7.AOPFramework

45.7.1. Cannot specify target name at the end ofinterceptorNamesforProxyFactoryObjectWhen configuring the list of interceptor names on aProxyFactoryObject instance (or object definition), one cannotspecifythenameofthetarget(i.e.theobjectbeingproxied)attheendofthelistof interceptor names. This shortcut is valid in Spring Java, where theProxyFactoryBeanwillautomaticallydetectthis,andusethelastnameintheinterceptornameslistasthetargetoftheProxyFactoryBean.Thefollowing configuration, which would be valid in Spring Java (barring theobviouselementnamechanges),isnotvalidinSpring.NET(sodon'tdoit).

<?xmlversion="1.0"encoding="utf-8"?>

<objectsxmlns="http://www.springframework.net">

<objectid="target"type="Spring.Objects.TestObject"

<propertyname="name"value="Bingo"/>

</object>

<objectid="nopInterceptor"type="Spring.Aop.Interceptor.NopInterceptor"

<objectid="prototypeTarget"type="Spring.Aop.Framework.ProxyFactoryObject"

<propertyname="interceptorNames"value="nopInterceptor,target"

</object>

</objects>

In Spring.NET, the InterceptorNames property of theProxyFactoryObject can only be used to specify the names ofinterceptors.UsetheTargetNamepropertytospecifythenameofthetargetobjectthatistobeproxied.Themain reason for not supporting exactly the same styleof configuration asSpringJavaisbecausethis 'feature' isregardedasa legacyholdoverfromRodJohnson'sinitialSpringAOPimplementation,andiscurrentlyonlykeptas-is(inSpringJava)forreasonsofbackwardcompatibility.

Page 883: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AppendixA.XMLSchema-basedconfiguration

Page 884: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

A.1.IntroductionThisappendixdetailstheuseofXMLSchema-basedconfigurationinSpring.The'classic'<object/>-basedschemaisgood,butitsgeneric-naturecomeswith a price in terms of configuration overhead. Creating a custom XMLSchema-based configuration makes Spring XML configuration filessubstantiallyclearertoread.Inaddition,itallowsyoutoexpresstheintentofanobjectdefinition.Thekey thing to remember is that creating custom schema tagsworkbest forinfrastructureorintegrationobjects:forexample,AOP,collections,transactions,integrationwith 3rd-party frameworks, etc., while the existing object tags arebestsuitedtoapplication-specificobjects,suchasDAOs,servicelayerobjects,etc.Please note the fact that the XML configuration mechanism is totallycustomisable and extensible. This means you can write your own domain-specificconfigurationtagsthatwouldbetterrepresentyourapplication'sdomain;theprocess involved indoingso iscovered in theappendixentitledAppendixB,ExtensibleXMLauthoring.

Page 885: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

A.2.XMLSchema-basedconfiguration

A.2.1.ReferencingtheschemasAsareminder,youreferencethestandardobjectsschemaasshownbelow

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.nethttp://www.springframework.net/schema/objects/spring-objects-1.1.xsd"

<!--<object/>definitionshere-->

</objects>

Note

The'xsi:schemaLocation'fragmentisnotactuallyrequired,butcanbeincludedtoreferencealocalcopyofaschema(whichcanbeusefulduringdevelopment)andassumestheXMLeditorwilllooktothatlocationandloadtheschema.

TheaboveSpringXMLconfigurationfragmentisboilerplatethatyoucancopyandpaste(!)andthenplug<object/>definitionsintolikeyouhavealwaysdone. However, the entire point of using custom schema tags is to makeconfigurationeasier.The rest of this chapter gives an overview of custom XML Schema basedconfigurationthatareincludedwiththerelease.

Note

AsofSpring.NET1.2.0itisnolongernecessarytoexplicitlyconfigurethenamespaceparsersthatcomewithSpringviaacustomsectioninApp.config.Youwillstillneedtoregistercustomnamespaceparsersifyouarewritingyourown.

A.2.2.Thetx(transaction)schemaThetxtagsdealwithconfiguringobjectsinSpring'scomprehensivesupportfortransactions.ThesetagsarecoveredinthechapterentitledChapter17,Transaction

Page 886: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

management.

Tip

Youarestronglyencouragedtolookatthe'spring-tx-1.1.xsd'filethatshipswiththeSpringdistribution.Thisfileis(ofcourse),theXMLSchemaforSpring'stransactionconfiguration,andcoversallofthevarioustagsinthetxnamespace,includingattributedefaultsandsuchlike.Thisfileisdocumentedinline,andthustheinformationisnotrepeatedhereintheinterestsofadheringtotheDRY(Don'tRepeatYourself)principle.

In the interestofcompleteness, touse the tags in thetx schema,youneed tohavethefollowingpreambleatthe topofyourSpringXMLconfigurationfile;the emboldened text in the following snippet references the correct schema sothatthetagsinthetxnamespaceareavailabletoyou.

<?xmlversion="1.0"encoding="UTF-8"?>

<objectxmlns="http://www.springframework.net"

xmlns:aop="http://www.springframework.net/aop"

xmlns:tx="http://www.springframework.net/tx">

<!--<object/>definitionshere-->

<!--<tx/>transactiondefinitionshere-->

<!--<aop/>AOPdefinitionshere-->

</object>

Note

Oftenwhenusingthetagsinthetxnamespaceyouwillalsobeusingthetagsfromtheaopnamespace(sincethedeclarativetransactionsupportinSpringisimplementedusingAOP).TheaboveXMLsnippetcontainstherelevantlinesneededtoreferencetheaopschemasothatthetagsintheaopnamespaceareavailabletoyou.

YouwillalsoneedtoconfiguretheAOPandTransactionnamespaceparsers inthemain.NETapplicationconfigurationfileasshownbelow

Page 887: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Note

AsofSpring.NET1.2.0itisnolongernecessarytoexplicitlyconfigurethenamespaceparsersthatcomewithSpringviaacustomsectioninApp.config.Youwillstillneedtoregistercustomnamespaceparsersifyouarewritingyourown.

<configuration>

<configSections>

<sectionGroupname="spring">

<!--otherSpringconfigsectionshandlerlikecontext,typeAliases,etcnotshownforbrevity-->

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Aop.Config.AopNamespaceParser,Spring.Aop"

<parsertype="Spring.Transaction.Config.TxNamespaceParser,Spring.Data"

</parsers>

</spring>

</configuration>

A.2.3.TheaopschemaTheaop tagsdealwith configuring all thingsAOP inSpring.These tags arecomprehensively covered in the chapter entitled Chapter 13, Aspect OrientedProgrammingwithSpring.NET.Intheinterestofcompleteness,tousethetagsintheaopschema,youneedtohavethefollowingpreambleat thetopofyourSpringXMLconfigurationfile;the emboldened text in the following snippet references the correct schema sothatthetagsintheaopnamespaceareavailabletoyou.

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:aop="http://www.springframework.net/aop">

Page 888: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<!--<object/>definitionshere-->

<!--<aop/>AOPdefinitionshere-->

</objects>

Youwill also need to configure theAOPnamespace parser in themain .NETapplicationconfigurationfileasshownbelow

Note

AsofSpring.NET1.2.0itisnolongernecessarytoexplicitlyconfigurethenamespaceparsersthatcomewithSpringviaacustomsectioninApp.config.Youwillstillneedtoregistercustomnamespaceparsersifyouarewritingyourown.

<configuration>

<configSections>

<sectionGroupname="spring">

<!--otherSpringconfigsectionshandlerlikecontext,typeAliases,etcnotshownforbrevity-->

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Aop.Config.AopNamespaceParser,Spring.Aop"

</parsers>

</spring>

</configuration>

A.2.4.ThedbschemaThedbtagsdealwithcreatingIDbProviderinstancesforagivendatabaseclient library. The following snippet references the correct schema so that thetags in thedb namespace are available to you.The tags are comprehensivelycoveredinthechapterentitledChapter19,DbProvider.

Page 889: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:db="http://www.springframework.net/db">

<!--<object/>definitionshere-->

<!--<db/>databasedefinitionshere-->

</objects>

YouwillalsoneedtoconfiguretheDatabasenamespaceparserinthemain.NETapplicationconfigurationfileasshownbelow

Note

AsofSpring.NET1.2.0itisnolongernecessarytoexplicitlyconfigurethenamespaceparsersthatcomewithSpringviaacustomsectioninApp.config.Youwillstillneedtoregistercustomnamespaceparsersifyouarewritingyourown.

<configuration>

<configSections>

<sectionGroupname="spring">

<!--otherSpringconfigsectionshandlerlikecontext,typeAliases,etcnotshownforbrevity-->

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Data.Config.DatabaseNamespaceParser,Spring.Data"

</parsers>

</spring>

</configuration>

A.2.5.TheremotingschemaTheremoting tagsareforusewhenyouwanttoexportanexistingPOCO

Page 890: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

objectasa.NETremotedobjectortocreateaclientside.NETremotingproxy.ThetagsarecomprehensivelycoveredinthechapterChapter25,.NETRemoting

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:r="http://www.springframework.net/remoting">

<!--<object/>definitionshere-->

<!--<r/>remotingdefinitionshere-->

</objects>

Youwillalsoneedtoconfiguretheremotingnamespaceparserinthemain.NETapplicationconfigurationfileasshownbelow

Note

AsofSpring.NET1.2.0itisnolongernecessarytoexplicitlyconfigurethenamespaceparsersthatcomewithSpringviaacustomsectioninApp.config.Youwillstillneedtoregistercustomnamespaceparsersifyouarewritingyourown.

<configuration>

<configSections>

<sectionGroupname="spring">

<!--otherSpringconfigsectionshandlerlikecontext,typeAliases,etcnotshownforbrevity-->

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Remoting.Config.RemotingNamespaceParser,Spring.Services"

</parsers>

</spring>

</configuration>

Page 891: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

A.2.6.ThenmsmessagingschemaThenms tags are for use when you want to configure Spring's messagingsupport.ThetagsarecomprehensivelycoveredinthechapterChapter29,MessageOrientedMiddleware-ApacheActiveMQ

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:r="http://www.springframework.net/nms">

<!--<object/>definitionshere-->

<!--<nms/>remotingdefinitionshere-->

</objects>

Youwillalsoneedtoconfiguretheremotingnamespaceparserinthemain.NETapplicationconfigurationfileasshownbelow

Note

AsofSpring.NET1.2.0itisnolongernecessarytoexplicitlyconfigurethenamespaceparsersthatcomewithSpringviaacustomsectioninApp.config.Youwillstillneedtoregistercustomnamespaceparsersifyouarewritingyourown.

<configuration>

<configSections>

<sectionGroupname="spring">

<!--otherSpringconfigsectionshandlerlikecontext,typeAliases,etcnotshownforbrevity-->

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Messaging.Nms.Config.NmsNamespaceParser,Spring.Messaging.Nms"

</parsers>

</spring>

Page 892: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</configuration>

A.2.7.ThevalidationschemaThevalidation tagsareforusewhenyouwantdefinteIValidatorobjectinstances.ThetagsarecomprehensivelycoveredinthechapterChapter12,ValidationFramework

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:v="http://www.springframework.net/validation">

<!--<object/>definitionshere-->

<!--<v/>valdiationdefinitionshere-->

</objects>

You will also need to configure the validation namespace parser in the main.NETapplicationconfigurationfileasshownbelow

Note

AsofSpring.NET1.2.0itisnolongernecessarytoexplicitlyconfigurethenamespaceparsersthatcomewithSpringviaacustomsectioninApp.config.Youwillstillneedtoregistercustomnamespaceparsersifyouarewritingyourown.

<configuration>

<configSections>

<sectionGroupname="spring">

<!--otherSpringconfigsectionshandlerlikecontext,typeAliases,etcnotshownforbrevity-->

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="Spring.Validation.Config.ValidationNamespaceParser,Spring.Core"

Page 893: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</parsers>

</spring>

</configuration>

A.2.8.TheobjectsschemaLastbutnotleastwehavethetagsintheobjectsschema.Examplesofthevarious tags in theobjects schema are not shown here because they arequite comprehensively covered in the section entitledSection 5.3.2, “Dependenciesandconfigurationindetail”(andindeedinthatentirechapter).

<?xmlversion="1.0"encoding="UTF-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.nethttp://www.springframework.net/schema/objects/spring-objects-1.1.xsd"

<objectid="foo"class="X.Y.Foo,X">

<propertyname="name"value="Rick"/>

</object>

</objects>

Page 894: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

A.3.SettingupyourIDETosetupVS.NETtoprovideintellisencewhileeditingXMLfileforyourcustomXMLschemasyouwillneedtocopyyourXSDfilestoanappropriateVS.NETdirectory.Refer to the following chapter for details,Chapter 32,Visual Studio.NETIntegration

For SharpDevelop, follow the directions on the "Editing XML" productdocumentation.

Page 895: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AppendixB.ExtensibleXMLauthoring

Page 896: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

B.1.IntroductionSpring supports adding custom schema-based extensions to the basic SpringXML format for defining and configuring objects. This section is devoted todetailing how you would go about writing your own custom XML objectdefinitionparsersandintegratingsuchparsersintotheSpringIoCcontainer.To facilitate the authoring of configuration files using a schema-aware XMLeditor, Spring's extensible XML configuration mechanism is based on XMLSchema. If you are not familiar with Spring's current XML configurationextensionsthatcomewiththestandardSpringdistribution,pleasefirstreadtheappendixentitledAppendixA,XMLSchema-basedconfiguration.Creating new XML configuration extensions can be done by following these(relatively)simplesteps:

1. AuthoringanXMLschematodescribeyourcustomelement(s).

2. CodingacustomINamespaceParserimplementation(thisisaneasystep,don'tworry).

3. CodingoneormoreIObjectDefinitionParserimplementations(thisiswheretherealworkisdone).

4. RegisteringtheaboveartifactswithSpring(thistooisaneasystep).What follows isadescriptionofeachof thesesteps.For theexample,wewillcreateanXMLextension(acustomXMLelement) thatallowsus toconfigureobjects of the type Regex (from theSystem.Text.RegularExpressions namespace) in an easymanner.Whenwearedone,wewillbeabletodefineobjectdefinitionsoftypeRegexlikethis:

<myns:regexid="regex"

pattern="(^\d{5}$)|(^\d{5}-\d{4}$)"

options="Compiled"/>

Page 897: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

B.2.AuthoringtheschemaCreating anXML configuration extension for usewith Spring's IoC containerstartswithauthoringanXMLSchematodescribetheextension.Whatfollowsistheschemawe'llusetoconfigureRegexobjects.

<?xmlversion="1.0"encoding="utf-8"?>

<xsd:schemaid="myns"

xmlns="http://www.mycompany.com/schema/myns"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:objects="http://www.springframework.net"

xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense"

targetNamespace="http://www.mycompany.com/schema/myns"

elementFormDefault="qualified"

attributeFormDefault="unqualified"

vs:friendlyname="SpringRegexConfiguration"vs:ishtmlschema

vs:iscasesensitive="true"vs:requireattributequotes

vs:defaultnamespacequalifier=""vs:defaultnsprefix

>

<xsd:importnamespace="http://www.springframework.net"/>

<xsd:elementname="regex">

<xsd:complexType>

<xsd:complexContent>

<xsd:extensionbase="objects:identifiedType">

<xsd:attributename="pattern"type="xsd:string"use

<xsd:attributename="options"type="xsd:string"use

</xsd:extension>

</xsd:complexContent>

</xsd:complexType>

</xsd:element>

</xsd:schema>

The emphasized line contains an extension base for all tags that will beidentifiable (meaning theyhaveanidattribute thatwillbeusedas theobjectidentifierinthecontainer).WeareabletousethisattributebecauseweimportedtheSpring-provided'objects'namespace.Thevs:prefixedelementsareforbetterintegrationwithintellisenseinVS.NET.

Page 898: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

The above schema will be used to configureRegex objects, directly in anXMLapplicationcontextfileusingthe<myns:regex/>element.

<myns:regexid="usZipCodeRegex"

pattern="(^\d{5}$)|(^\d{5}-\d{4}$)"

options="Compiled"/>

Note that after we've created the infrastructure classes, the above snippet ofXMLwillessentiallybeexactlythesameasthefollowingXMLsnippet.Inotherwords, we're just creating an object in the container, identified by the name'usZipCodeRegex' of type Regex, with a couple of constructorargumentsset.

<objectid="usZipCodeRegex"type="System.Text.RegularExpressions.Regex,System"

<constructor-argname="pattern"value="(^\d{5}$)|(^\d{5}-\d{4}$)"

<constructor-argname="options"value="Compiled"/>

</object>

Note

Theschema-basedapproachtocreatingconfigurationformatallowsfortightintegrationwithanIDEthathasaschema-awareXMLeditor.Usingaproperlyauthoredschema,youcanuseintellisensetohaveauserchoosebetweenseveralconfigurationoptionsdefinedintheenumeration.TheschemaforcreatingIDbProviderinstancesshowstheuseofXSDenumerations.

Page 899: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

B.3.CodingaINamespaceParserInadditiontotheschema,weneedanINamespaceParserthatwillparseall elements of this specific namespace Spring encounters while parsingconfigurationfiles.TheINamespaceParsershouldinourcasetakecareoftheparsingofthemyns:regexelement.

TheINamespaceParser interfaceisprettysimpleinthatitfeaturesjusttwomethods:

Init()-allowsforinitializationoftheINamespaceParserandwillbecalledbySpringbeforethehandlerisused

IObjectDefinition Parse(Element,

ParserContext) - called when Spring encounters a top-levelelement (not nested inside a object definition or a different namespace).This method can register object definitions itself and/or return a objectdefinition.

Although it is perfectly possible to codeyour ownINamespaceParserfor the entire namespace (and hence provide code that parses each and everyelementinthenamespace),itisoftenthecasethateachtop-levelXMLelementinaSpringXMLconfigurationfileresultsinasingleobjectdefinition(asinourcase,whereasingle<myns:regex/>element results inasingleRegexobjectdefinition).Springfeaturesanumberofconvenienceclassesthatsupportthis scenario. In this example, we'll make use theNamespaceParserSupportclass:

usingSpring.Objects.Factory.Xml;

namespaceCustomNamespace

{

[NamespaceParser(

Namespace="http://www.mycompany.com/schema/myns",

SchemaLocationAssemblyHint=typeof(MyNamespaceParser),

SchemaLocation="/CustomNamespace/myns.xsd"

)

]

publicclassMyNamespaceParser:NamespaceParserSupport

{

Page 900: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

publicoverridevoidInit()

{

RegisterObjectDefinitionParser("regex",newRegexObjectDefinitionParser());

}

}

}

Noticethatthereisn'tactuallyawholelotofparsinglogicinthisclass.Indeed...the NamespaceParserSupport class has a built in notion ofdelegation. It supports the registration of any number ofIObjectDefinitionParser instances, to which it will delegate towhen it needs to parse an element in it's namespace. This clean separation ofconcernsallowsanINamespaceParsertohandletheorchestrationoftheparsing of all of the custom elements in it's namespace, while delegating toIObjectDefinitionParsers to do the grunt work of the XMLparsing; this means that each IObjectDefinitionParser willcontainjustthelogicforparsingasinglecustomelement,aswecanseeinthenextstep.To help in the registration of the parser for this namespace, theNamespaceParser attribute is used tomap theXMLnamespace string,i.e. http://www.mycompany.com/schema/myns, to thelocationoftheXMLSchemafileasanembeddedassemblyresource.

Page 901: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

B.4.CodinganIObjectDefinitionParserA IObjectDefinitionParser will be used if theINamespaceParser encounters an XML element of the type that hasbeenmappedtothespecificobjectdefinitionparser(whichis'regex'inthiscase).Inotherwords,theIObjectDefinitionParser is responsiblefor parsingone distinct top-levelXML element defined in the schema. In theparser,we'llhaveaccesstotheXMLelement(andthusit'ssubelementstoo)sothat we can parse our customXML content, as can be seen in the followingexample:

usingSystem;

usingSystem.Text.RegularExpressions;

usingSystem.Xml;

usingSpring.Objects.Factory.Support;

usingSpring.Objects.Factory.Xml;

usingSpring.Util;

namespaceCustomNamespace

{

publicclassRegexObjectDefinitionParser:AbstractSimpleObjectDefinitionParser{

protectedoverrideTypeGetObjectType(XmlElementelement)

{

returntypeof(Regex);

}

protectedoverridevoidDoParse(XmlElementelement,ObjectDefinitionBuilderbuilder)

{

//thiswillneverbenullsincetheschemaexplicitlyrequiresthatavaluebesupplied

stringpattern=element.GetAttribute("pattern");

builder.AddConstructorArg(pattern);

//thishoweverisanoptionalproperty

stringoptions=element.GetAttribute("options");

if(StringUtils.HasText(options))

{

RegexOptionsregexOptions=(RegexOptions)Enum.Parse(

builder.AddConstructorArg(regexOptions);

}

Page 902: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

}

protectedoverrideboolShouldGenerateIdAsFallback

{

get{returntrue;}

}

}

WeusetheSpring-providedAbstractSingleObjectDefinitionParsertohandlealotofthebasicgruntworkofcreatingasingleIObjectDefinition.

WesupplytheAbstractSingleObjectDefinitionParsersuperclasswiththetypethatoursingleIObjectDefinitionwillrepresent.

In this simple case, this is all that we need to do. The creation of our singleIObjectDefinition is handled by theAbstractSingleObjectDefinitionParser superclass, as isthe extraction and setting of the object definition's unique identifier. Theproperty ShouldGenerateIdAsFallback will generate a throw-away object id incase one is not specified, this is useful when nesting objectdefinitions.

Page 903: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

B.5.RegisteringthehandlerandtheschemaThe coding is finished! All that remains to be done is to somehowmake theSpringXMLparsinginfrastructureawareofourcustomelement;wedothisbyregisteringourcustomINamespaceParserusingaspecialconfigurationsection handler. The location of the XML Schema in this example has beendirectly assoicated with the parser though the use of the Namespaceattribute.

B.5.1.NamespaceParsersSectionHandlerThe custom configuration section handler is of the typeSpring.Context.Support.NamespaceParsersSectionHandler

and is registered with .NET in the normal manner. The custom configurationsectionwillsimplypointtotheINamespaceParserimplementationthathas the Namespace attribute. For our example, we need to write thefollowing:

<configuration>

<configSections>

<sectionGroupname="spring">

<sectionname="parsers"type="Spring.Context.Support.NamespaceParsersSectionHandler,Spring.Core"

</sectionGroup>

</configSections>

<spring>

<parsers>

<parsertype="CustomNamespace.MyNamespaceParser,CustomNamespace"

</parsers>

</spring>

</configuration>

Page 904: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

B.6. Using a custom extension in your Spring XMLconfigurationUsing a custom extension that you yourself have implemented is no differentfromusingoneofthe'custom'extensionsthatSpringprovidesstraightoutofthebox. Find below an example of using the custom <regex/> elementdevelopedinthepreviousstepsinaSpringXMLconfigurationfile.

<?xmlversion="1.0"encoding="utf-8"?>

<objectsxmlns="http://www.springframework.net"

xmlns:myns="http://www.mycompany.com/schema/myns">

<!--asatoplevelobjectdefinition-->

<myns:regexid="usZipCodeRegex"

pattern="(^\d{5}$)|(^\d{5}-\d{4}$)"/>

<objectid="jobDetailTemplate"abstract="true">

<propertyname="regex">

<!--asaninnerobjectdefinition-->

<myns:regexpattern="(^\d{5}$)|(^\d{5}-\d{4}$)"

options="Compiled"/>

</property>

</object>

</objects>

Page 905: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

B.7.FurtherResourcesFind below links to further resources concerning XML Schema and theextensibleXMLsupportdescribedinthischapter.

TheXMLSchemaPart1:StructuresSecondEdition

TheXMLSchemaPart2:DatatypesSecondEdition

Page 906: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

AppendixC.Spring.NET'sspring-objects.xsd

<?xmlversion="1.0"encoding="UTF-8"?>

<xs:schemaxmlns="http://www.springframework.net"xmlns:xs="http://www.w3.org/2001/XMLSchema"

<xs:annotation>

<xs:documentation>

SpringObjectsXMLSchemaDefinition

BasedonSpringBeansDTD,authoredbyRodJohnson&amp;JuergenHoeller

Author:GriffinCaprio

Thisdefinesasimpleandconsistentwayofcreatinganamespace

ofmanagedobjectsconfiguredbyaSpringXmlObjectFactory.

ThisdocumenttypeisusedbymostSpringfunctionality,including

webapplicationcontexts,whicharebasedonobjectfactories.

Eachobjectelementinthisdocumentdefinesanobject.

Typicallytheobjecttype(System.Typeisspecified,alongwithplainvanilla

objectproperties.

Objectinstancescanbe"singletons"(sharedinstances)or"prototypes"

(independentinstances).

Referencesamongobjectsaresupported,i.e.settinganobjectproperty

torefertoanotherobjectinthesamefactoryoranancestorfactory.

Asalternativetoobjectreferences,"innerobjectdefinitions"canbeused.

Singletonflagsandnamesofsuch"innerobject"arealwaysignored:

Innerobjectareanonymousprototypes.

Thereisalsosupportforlists,dictionaries,andsets.

</xs:documentation>

</xs:annotation>

<xs:annotation>

<xs:documentation>Definesabasetypeforanyrequiredstring.Definesastringwithaminimumlengthof0

</xs:annotation>

<xs:simpleTypename="nonNullString">

Page 907: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<xs:restrictionbase="xs:string">

<xs:minLengthvalue="0"/>

</xs:restriction>

</xs:simpleType>

<xs:annotation>

<xs:documentation>

Elementcontaininginformativetextdescribingthepurposeoftheenclosing

element.Alwaysoptional.

UsedprimarilyforuserdocumentationofXMLobjectdefinitiondocuments.

</xs:documentation>

</xs:annotation>

<xs:simpleTypename="description">

<xs:restrictionbase="nonNullString"/>

</xs:simpleType>

<xs:complexTypename="valueObject">

<xs:simpleContent>

<xs:extensionbase="xs:string">

<xs:attributename="type"type="nonNullString"

</xs:extension>

</xs:simpleContent>

</xs:complexType>

<xs:complexTypename="expression">

<xs:sequence>

<xs:elementname="property"type="property"minOccurs

</xs:sequence>

<xs:attributename="value"type="nonNullString"use="required"

</xs:complexType>

<!--

Definesareferencetoanotherobjectinthisfactoryoranexternal

factory(parentorincludedfactory).

-->

<xs:complexTypename="objectReference">

<xs:attributename="object"type="nonNullString"use

<xs:attributename="local"type="xs:IDREF"use="optional"

<xs:attributename="parent"type="nonNullString"use

<!--

Referencesmustspecifyanameofthetargetobject.

The"object"attributecanreferenceanynamefromanyobjectinthecontext,

tobecheckedatruntime.

Localreferences,usingthe"local"attribute,havetouseobjectids;

theycanbecheckedbythisDTD,thusshouldbepreferredforreferences

withinthesameobjectfactoryXMLfile.

Page 908: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

-->

</xs:complexType>

<!--Definesareferencetoanotherobjectoratype.-->

<xs:complexTypename="objectOrClassReference">

<xs:attributename="object"type="nonNullString"use

<xs:attributename="local"type="xs:IDREF"use="optional"

<xs:attributename="type"type="nonNullString"use="optional"

</xs:complexType>

<xs:groupname="objectList">

<xs:sequence>

<xs:elementname="description"type="description"

<xs:choice>

<xs:elementname="object"type="vanillaObject"

<!--

Definesareferencetoanotherobjectinthisfactoryoranexternal

factory(parentorincludedfactory).

-->

<xs:elementname="ref"type="objectReference"

<!--

Definesastringpropertyvalue,whichmustalsobetheidofanother

objectinthisfactoryoranexternalfactory(parentorincludedfactory).

Whilearegular'value'elementcouldinsteadbeusedforthesameeffect,

usingidrefinthiscaseallowsvalidationoflocalobjectidsbythexml

parser,andnamecompletionbyhelpertools.

-->

<xs:elementname="idref"type="objectReference"

<!--

AobjectListcancontainmultipleinnerobject,ref,collection,orvalueelements.

Listsareuntyped,pendinggenericssupport,althoughreferenceswillbe

stronglytyped.

AobjectListcanalsomaptoanarraytype.Thenecessaryconversion

isautomaticallyperformedbyAbstractObjectFactory.

-->

<xs:elementname="list">

<xs:complexType>

<xs:groupref="objectList"minOccurs

<xs:attributename="element-type"type

</xs:complexType>

</xs:element>

<!--

Asetcancontainmultipleinnerobject,ref,collection,orvalueelements.

Setsareuntyped,pendinggenericssupport,althoughreferenceswillbe

Page 909: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

stronglytyped.

-->

<xs:elementname="set">

<xs:complexType>

<xs:groupref="objectList"minOccurs

</xs:complexType>

</xs:element>

<!--

ASpringmapisamappingfromastringkeytoobject(a.NETIDictionary).

Mapsmaybeempty.

-->

<xs:elementname="dictionary"type="objectMap"

<!--

Name-valueselementsdifferfrommapelementsinthatvaluesmustbestrings.

Name-valuesmaybeempty.

-->

<xs:elementname="name-values"type="objectNameValues"

<!--

Containsastringrepresentationofapropertyvalue.

Thepropertymaybeastring,ormaybeconvertedtothe

requiredtypeusingtheSystem.ComponentModel.TypeConverter

machinery.Thismakesitpossibleforapplicationdevelopers

towritecustomTypeConverterimplementationsthatcan

convertstringstoobjects.

Notethatthisisrecommendedforsimpleobjectsonly.

Configuremorecomplexobjectsbysettingpropertiestoreferences

tootherobjects.

-->

<xs:elementname="value"type="valueObject"/>

<!--

Containsastringrepresentationofanexpression.

-->

<xs:elementname="expression"type="expression"

<!--

Denotesa.NETnullvalue.Necessarybecauseanempty"value"tag

willresolvetoanemptyString,whichwillnotberesolvedtoa

nullvalueunlessaspecialTypeConverterdoesso.

-->

<xs:elementname="null"/>

</xs:choice>

</xs:sequence>

Page 910: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

</xs:group>

<xs:complexTypename="objectNameValues">

<xs:sequence>

<!--

The"value"attributeisthestringvalueoftheproperty.The"key"

attributeisthenameoftheproperty.

-->

<xs:elementname="add"minOccurs="0"maxOccurs="unbounded"

<xs:complexTypemixed="true">

<xs:attributename="key"type="nonNullString"

<xs:attributename="value"use="required"

<xs:attributename="delimiters"use="optional"

</xs:complexType>

</xs:element>

</xs:sequence>

</xs:complexType>

<xs:complexTypename="importElement">

<xs:attributename="resource"type="nonNullString"use

</xs:complexType>

<xs:complexTypename="aliasElement">

<xs:attributename="name"type="nonNullString"use="required"

<xs:attributename="alias"type="nonNullString"use=

</xs:complexType>

<xs:complexTypename="objectMap">

<xs:sequence>

<xs:elementtype="mapEntryElement"name="entry"

</xs:sequence>

<xs:attributename="key-type"type="nonNullString"use

<xs:attributename="value-type"type="nonNullString"

</xs:complexType>

<xs:complexTypename="mapEntryElement">

<xs:sequence>

<xs:elementtype="mapKeyElement"name="key"minOccurs

<xs:groupref="objectList"minOccurs="0"maxOccurs

</xs:sequence>

<xs:attributename="key"type="nonNullString"use="optional"

<xs:attributename="value"type="nonNullString"use=

<xs:attributename="expression"type="nonNullString"

<xs:attributename="key-ref"type="nonNullString"use

<xs:attributename="value-ref"type="nonNullString"

</xs:complexType>

<xs:complexTypename="mapKeyElement">

Page 911: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<xs:groupref="objectList"minOccurs="1"/>

</xs:complexType>

<xs:annotation>

<xs:documentation>Definesconstructorargument.</xs:documentation>

</xs:annotation>

<xs:complexTypename="lookupMethod">

<xs:attributename="name"type="nonNullString"use="required"

<xs:attributename="object"type="nonNullString"use

</xs:complexType>

<xs:complexTypename="constructorArgument">

<xs:groupref="objectList"minOccurs="0"/>

<!--

Theconstructor-argtagcanhaveanoptionalnamedparameterattribute,

tospecifyanamedparameterintheconstructorargumentlist.

-->

<xs:attributename="name"type="nonNullString"use="optional"

<!--

Theconstructor-argtagcanhaveanoptionalindexattribute,

tospecifytheexactindexintheconstructorargumentlist.Onlyneeded

toavoidambiguities,e.g.incaseof2argumentsofthesametype.

-->

<xs:attributename="index"type="nonNullString"use=

<!--

Theconstructor-argtagcanhaveanoptionaltypeattribute,

tospecifytheexacttypeoftheconstructorargument.Onlyneeded

toavoidambiguities,e.g.incaseof2singleargumentconstructors

thatcanbothbeconvertedfromaString.

-->

<xs:attributename="type"type="nonNullString"use="optional"

<xs:attributename="value"type="nonNullString"use=

<xs:attributename="expression"type="nonNullString"

<xs:attributename="ref"type="nonNullString"use="optional"

</xs:complexType>

<xs:annotation>

<xs:documentation>Definesproperty.</xs:documentation>

</xs:annotation>

<xs:complexTypename="property">

<xs:groupref="objectList"minOccurs="0"/>

<!--Thepropertynameattributeisthenameoftheobjectsproperty.-->

<xs:attributename="name"type="nonNullString"use="required"

<xs:attributename="value"type="nonNullString"use=

<xs:attributename="expression"type="nonNullString"

Page 912: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<xs:attributename="ref"type="nonNullString"use="optional"

</xs:complexType>

<xs:annotation>

<xs:documentation>Definesasinglenamedobject.</xs:documentation>

</xs:annotation>

<xs:complexTypename="vanillaObject">

<xs:sequence>

<xs:elementname="description"type="description"

<!--

Objectdefinitionscanspecifyzeroormoreconstructorarguments.

Theycorrespondtoeitheraspecificindexoftheconstructorargumentlist

oraresupposedtobematchedgenericallybytype.

Thisisanalternativeto"autowireconstructor".

-->

<xs:elementname="constructor-arg"type="constructorArgument"

<!--

Objectdefinitionscanhavezeroormoreproperties.

Springsupportsprimitives,referencestootherobjectsinthesameor

relatedfactories,lists,dictionariesandproperties.

-->

<xs:elementname="property"type="property"minOccurs

<!--

Objectdefinitionscanspecifyzeroormorelookup-methods.

-->

<xs:elementname="lookup-method"type="lookupMethod"

<!--Objectdefinitionscanhavezeroormorereplaced-methods.-->

<xs:elementname="replaced-method"minOccurs="0"

<xs:complexType>

<xs:sequence>

<xs:elementname="arg-type"minOccurs

<xs:complexType>

<xs:attributename="match"

</xs:complexType>

</xs:element>

</xs:sequence>

<xs:attributename="name"type="nonNullString"

<xs:attributename="replacer"type="nonNullString"

</xs:complexType>

</xs:element>

<!--Objectdefinitionscanhavezeroormoresubscriptions.-->

<xs:elementname="listener"minOccurs="0"maxOccurs

<xs:complexType>

Page 913: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<xs:sequence>

<xs:elementname="ref"type="objectOrClassReference"

</xs:sequence>

<!--Theevent(s)theobjectisinterestedin.-->

<xs:attributename="event"type="nonNullString"

<!--Thenameornamepatternofthemethodthatwillhandletheevent(s).-->

<xs:attributename="method"type="nonNullString"

</xs:complexType>

</xs:element>

</xs:sequence>

<!--

Objectscanbeidentifiedbyanid,toenablereferencechecking.

ThereareconstraintsonavalidXMLid:ifyouwanttoreferenceyourobject

in.NETcodeusinganamethat'sillegalasanXMLid,usetheoptional

"name"attribute.Ifneithergiven,theobjecttypenameisusedasid.

-->

<xs:attributename="id"type="xs:ID"use="optional"/>

<!--

Optional.Canbeusedtocreateoneormorealiasesillegalinanid.

Multiplealiasescanbeseparatedbyanynumberofspacesorcommas.

-->

<xs:attributename="name"type="nonNullString"use="optional"

<!--

Eachobjectdefinitionmustspecifythefull,assemblyqualifiedofthetype,

orthenameoftheparentobjectfromwhichthetypecanbeworkedout.

Notethatachildobjectdefinitionthatreferencesaparentwilljust

addrespectivelyoverridepropertyvaluesandbeabletochangethe

singletonstatus.Itwillinheritalloftheparent'sotherparameters

likelazyinitializationorautowiresettings.

-->

<xs:attributename="type"type="nonNullString"use="optional"

<xs:attributename="parent"type="nonNullString"use

<!--

Isthisobject"abstract",i.e.notmeanttobeinstantiateditselfbut

ratherjustservingasparentforconcretechildobjectdefinitions?

Defaultisfalse.Specifytruetotelltheobjectfactorytonottryto

instantiatethatparticularobjectinanycase.

-->

<xs:attributename="abstract"type="xs:boolean"use=

<!--

Isthisobjecta"singleton"(onesharedinstance,whichwill

Page 914: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

bereturnedbyallcallstoGetObject()withtheid),

ora"prototype"(independentinstanceresultingfromeachcallto

getObject().Defaultissingleton.

Singletonsaremostcommonlyused,andareidealformulti-threaded

serviceobjects.

-->

<xs:attributename="singleton"type="xs:boolean"use

<!--

Optionalattributecontrollingthescopeofsingletoninstances.Itis

onlyapplicabletoASP.Netwebapplicationsandithasnoeffectonprototype

objects.ApplicationsotherthanASP.Netwebapplicationssimplyignorethisattribute.

Ithas3possiblevalues:

1."application"

Defaultobjectscope.Objectsdefinedwithapplicationscopewillbehavelike

traditionalsingletonobjects.Sameinstancewillbereturnedfromeverycall

toIApplicationContext.GetObject()

2."session"

Objectswiththisscopewillbestoredwithinuser'sHTTPsession.Sessionscope

istypicallyusedforobjectssuchasshoppingcart,userprofile,etc.

3."request"

ObjectwiththisscopewillbeinitializedforeachHTTPrequest,butunlikewithprototype

objects,sameinstancewillbereturnedfromallcallstoIApplicationContext.GetObject()

withinthesameHTTPrequest.Forexample,ifoneASPpageforwardsrequesttoanotherusing

Server.Transfermethod,theycaneasilysharethestatebyconfiguringdependencytothesame

request-scopedobject.

-->

<xs:attributename="scope"use="optional"default="application"

<xs:simpleType>

<xs:restrictionbase="xs:string">

<xs:enumerationvalue="application"/>

<xs:enumerationvalue="session"/>

<xs:enumerationvalue="request"/>

</xs:restriction>

</xs:simpleType>

</xs:attribute>

<!--

Isthisobjecttobelazilyinitialized?

Iffalse,itwillgetinstantiatedonstartupbyobjectfactories

thatperformeagerinitializationofsingletons.

Page 915: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

-->

<xs:attributename="lazy-init"use="optional"default

<xs:simpleType>

<xs:restrictionbase="xs:string">

<xs:enumerationvalue="true"/>

<xs:enumerationvalue="false"/>

<xs:enumerationvalue="default"/>

</xs:restriction>

</xs:simpleType>

</xs:attribute>

<!--

Optionalattributecontrollingwhetherto"autowire"objectproperties.

Thisisanautomagicalprocessinwhichobjectreferencesdon'tneedtobecoded

explicitlyintheXMLobjectdefinitionfile,butSpringworksoutdependencies.

Thereare5modes:

1."no"

ThetraditionalSpringdefault.Noautomagicalwiring.Objectreferences

mustbedefinedintheXMLfileviathe<ref>element.Werecommendthis

inmostcasesasitmakesdocumentationmoreexplicit.

2."byName"

Autowiringbypropertyname.IfaobjectofclassCatexposesadogproperty,

Springwilltrytosetthistothevalueoftheobject"dog"inthecurrentfactory.

3."byType"

Autowiringifthereisexactlyoneobjectofthepropertytypeintheobjectfactory.

Ifthereismorethanone,afatalerrorisraised,andyoucan'tusebyType

autowiringforthatobject.Ifthereisnone,nothingspecialhappens-use

dependency-check="objects"toraiseanerrorinthatcase.

4."constructor"

Analogousto"byType"forconstructorarguments.Ifthereisn'texactlyoneobject

oftheconstructorargumenttypeintheobjectfactory,afatalerrorisraised.

5."autodetect"

Chooses"constructor"or"byType"throughintrospectionoftheobjectclass.

Ifadefaultconstructorisfound,"byType"getsapplied.

ThelattertwoaresimilartoPicoContainerandmakeobjectfactoriessimpleto

configureforsmallnamespaces,butdoesn'tworkaswellasstandardSpring

Page 916: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

behaviourforbiggerapplications.

Notethatexplicitdependencies,i.e."property"and"constructor-arg"elements,

alwaysoverrideautowiring.Autowirebehaviourcanbecombinedwithdependency

checking,whichwillbeperformedafterallautowiringhasbeencompleted.

-->

<xs:attributename="autowire"use="optional"default

<xs:simpleType>

<xs:restrictionbase="xs:string">

<xs:enumerationvalue="no"/>

<xs:enumerationvalue="byName"/>

<xs:enumerationvalue="byType"/>

<xs:enumerationvalue="constructor"/>

<xs:enumerationvalue="autodetect"/>

<xs:enumerationvalue="default"/>

</xs:restriction>

</xs:simpleType>

</xs:attribute>

<!--

Optionalattributecontrollingwhethertocheckwhetherallthis

objectsdependencies,expressedinitsproperties,aresatisfied.

Defaultisnodependencychecking.

"simple"typedependencycheckingincludesprimitivesandString

"object"includescollaborators(otherobjectsinthefactory)

"all"includesbothtypesofdependencychecking

-->

<xs:attributename="dependency-check"use="optional"

<xs:simpleType>

<xs:restrictionbase="xs:string">

<xs:enumerationvalue="none"/>

<xs:enumerationvalue="objects"/>

<xs:enumerationvalue="simple"/>

<xs:enumerationvalue="all"/>

<xs:enumerationvalue="default"/>

</xs:restriction>

</xs:simpleType>

</xs:attribute>

<!--

Thenamesoftheobjectsthatthisobjectdependsonbeinginitialized.

Theobjectfactorywillguaranteethattheseobjectsgetinitializedbefore.

Page 917: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

Notethatdependenciesarenormallyexpressedthroughobjectpropertiesor

constructorarguments.Thispropertyshouldjustbenecessaryforotherkinds

ofdependencieslikestatics(*ugh*)ordatabasepreparationonstartup.

-->

<xs:attributename="depends-on"type="nonNullString"

<!--

Optionalattributeforthenameofthecustominitializationmethod

toinvokeaftersettingobjectproperties.Themethodmusthavenoarguments,

butmaythrowanyexception.

-->

<xs:attributename="init-method"type="nonNullString"

<!--

Optionalattributeforthenameofthecustomdestroymethodtoinvoke

onobjectfactoryshutdown.Themethodmusthavenoarguments,

butmaythrowanyexception.Note:Onlyinvokedonsingletonobjects!

-->

<xs:attributename="destroy-method"type="nonNullString"

<xs:attributename="factory-method"type="nonNullString"

<xs:attributename="factory-object"type="nonNullString"

</xs:complexType>

<xs:annotation>

<xs:documentation>Thedocumentroot.Atleastoneobjectdefinitionisrequired.

</xs:annotation>

<xs:elementname="objects">

<xs:complexType>

<xs:sequence>

<xs:elementname="description"type="description"

<xs:choiceminOccurs="0"maxOccurs="unbounded"

<xs:elementname="import"type="importElement"

<xs:elementname="alias"type="aliasElement"

<xs:elementname="object"type="vanillaObject"

<xs:anynamespace="##other"processContents

</xs:choice>

</xs:sequence>

<!--

Defaultvaluesforallobjectdefinitions.Canbeoverriddenat

the"object"level.Seethoseattributedefinitionsfordetails.

-->

<xs:attributename="default-lazy-init"type="xs:boolean"

<xs:attributename="default-dependency-check"use

<xs:simpleType>

Page 918: The Spring.NET Framework - Documentation & Help · Introduction to AdoTemplate Spring.NET is an application framework that provides comprehensive The Spring Framework takes best practices

<xs:restrictionbase="xs:string">

<xs:enumerationvalue="none"/>

<xs:enumerationvalue="objects"/>

<xs:enumerationvalue="simple"/>

<xs:enumerationvalue="all"/>

</xs:restriction>

</xs:simpleType>

</xs:attribute>

<xs:attributename="default-autowire"use="optional"

<xs:simpleType>

<xs:restrictionbase="xs:string">

<xs:enumerationvalue="no"/>

<xs:enumerationvalue="byName"/>

<xs:enumerationvalue="byType"/>

<xs:enumerationvalue="constructor"/>

<xs:enumerationvalue="autodetect"/>

</xs:restriction>

</xs:simpleType>

</xs:attribute>

</xs:complexType>

</xs:element>

</xs:schema>