You are on page 1of 223

April2010

COMMUNITYPREVIEWLICENSE
Thisdocumentisapreliminaryreleasethatmaybechangedsubstantiallypriortofinalcommercial release.ThisdocumentisprovidedforinformationalpurposesonlyandMicrosoftmakesno warranties,eitherexpressorimplied,inthisdocument.Informationinthisdocument,includingURL andotherInternetWebsitereferences,issubjecttochangewithoutnotice.Theentireriskofthe useortheresultsfromtheuseofthisdocumentremainswiththeuser.Unlessotherwisenoted,the companies,organizations,products,domainnames,emailaddresses,logos,people,places,and eventsdepictedinexampleshereinarefictitious.Noassociationwithanyrealcompany, organization,product,domainname,emailaddress,logo,person,place,oreventisintendedor shouldbeinferred.Complyingwithallapplicablecopyrightlawsistheresponsibilityoftheuser. Withoutlimitingtherightsundercopyright,nopartofthisdocumentmaybereproduced,storedin orintroducedintoaretrievalsystem,ortransmittedinanyformorbyanymeans(electronic, mechanical,photocopying,recording,orotherwise),orforanypurpose,withouttheexpresswritten permissionofMicrosoftCorporation. Microsoftmayhavepatents,patentapplications,trademarks,copyrights,orotherintellectual propertyrightscoveringsubjectmatterinthisdocument.Exceptasexpresslyprovidedinany writtenlicenseagreementfromMicrosoft,thefurnishingofthisdocumentdoesnotgiveyouany licensetothesepatents,trademarks,copyrights,orotherintellectualproperty.

2010MicrosoftCorporation.Allrightsreserved.
MicrosoftaretrademarksoftheMicrosoftgroupofcompanies. Allothertrademarksarepropertyoftheirrespectiveowners.

UnityDependencyInjectionandInterception..............................................................................11 WhatIsUnity?...............................................................................................................................11 WhatDoesUnityDo?....................................................................................................................12 TheTypesofObjectsUnityCanCreate.....................................................................................13 RegisteringExistingTypesandObjectInstances ......................................................................13 . ManagingtheLifetimeofObjects.............................................................................................13 ConfiguringTypesforInjectionintoConstructors,Methods,andProperties..........................14 ExampleApplicationCodeforConstructorInjection............................................................14 ExampleApplicationCodeforProperty(Setter)Injection....................................................15 PopulatingandInjectingArrays,IncludingGenericArrays.......................................................15 InterceptingCallstoObjects.....................................................................................................16 ExampleApplicationCode.....................................................................................................16 WhenShouldIUseUnity?.............................................................................................................17 ScenariosforUnity....................................................................................................................18 BenefitsofUnity........................................................................................................................18 LimitationsofUnity...................................................................................................................19 AboutThisReleaseofUnity..........................................................................................................19 HowtoUseThisGuidance ........................................................................................................20 . MoreInformation......................................................................................................................20 ChangesinThisRelease ................................................................................................................21 . BreakingChangestoUnity........................................................................................................21 ChangesinUnity........................................................................................................................22 TargetAudienceandSystemRequirements.................................................................................23 SystemRequirementsandPrerequisites..................................................................................24 MigrationandSidebySideExecution..........................................................................................25 PartialMigration........................................................................................................................25 ReusingConfigurationFilesBasedonaPreviousSchema............................................................25 MigratingCustomExtensions....................................................................................................26 Relatedpatterns&practicesLinks................................................................................................27 CopyrightandTermsofUse..........................................................................................................28 ConfiguringUnity ..........................................................................................................................28 . DesignTimeConfiguration............................................................................................................29 UsingtheConfigurationTool ........................................................................................................30 .
3

UsingtheUnityXSDtoEnableVisualStudioIntelliSense.............................................................31 UsingDesignTimeConfiguration..................................................................................................31 FormatoftheUnityConfigurationFile.....................................................................................32 LoadingConfigurationFileInformationintoaContainer.........................................................33 LoadingtheConfigurationfromAlternativeFiles.................................................................34 SpecifyingTypesintheConfigurationFile....................................................................................36 CLRTypeNames....................................................................................................................36 TypeAliases...........................................................................................................................37 AutomaticTypeLookup ........................................................................................................37 . DefaultAliasesandAssemblies.............................................................................................39 GenericTypes........................................................................................................................40 TheUnityConfigurationSchema...................................................................................................41 The<unity>ConfigurationSection............................................................................................41 The<container>Element......................................................................................................42 The<register>Element.............................................................................................................43 The<lifetime>Element.............................................................................................................44 The<constructor>Element.......................................................................................................45 The<property>Element............................................................................................................46 The<method>Element.............................................................................................................47 The<param>Element...............................................................................................................48 The<dependency>Element......................................................................................................49 The<value>Element.................................................................................................................49 The<optional>Element............................................................................................................50 The<array>Element.................................................................................................................51 The<extension>Element..........................................................................................................51 The<instance>Element............................................................................................................52 The<namespace>Element.......................................................................................................53 The<assembly>Element...........................................................................................................54 The<alias>Element..................................................................................................................54 The<sectionExtension>Element..............................................................................................55 SpecifyingValuesforInjection......................................................................................................55 ResolvingValuesfromtheContainer........................................................................................56 GivingValuesinConfiguration..................................................................................................57 ConfiguringArrayValues...........................................................................................................57
4

ExtendingtheUnityConfigurationSchema..................................................................................58 ConfigurationFilesforInterception..............................................................................................59 UsingtheConfigurationFiletoEnableInterception.................................................................60 StandardInterceptionAliases...............................................................................................61 EnablingInterceptiononaType ...........................................................................................62 . ConfiguringPolicyInjectionPolicies......................................................................................62 LegacyInterceptionConfiguration........................................................................................65 InterceptionConfigurationSchemaElements..............................................................................66 The<interceptor>Element.......................................................................................................66 The<interceptionBehavior>Element.......................................................................................67 The<addInterface>Element.....................................................................................................67 The<interception>Element......................................................................................................68 The<policy>Element................................................................................................................68 The<matchingRule>Element...................................................................................................68 The<callHandler>Element.......................................................................................................69 The<interceptors>Element......................................................................................................69 Theinterceptors<interceptor>Element...................................................................................70 The<default>Element..............................................................................................................70 The<key>Element....................................................................................................................71 RunTimeConfiguration................................................................................................................71 UsingRunTimeConfiguration.......................................................................................................72 UsingtheUnityContainerFluentInterface...............................................................................72 RegisteringTypesandTypeMappings..........................................................................................73 RegisteringanInterfaceorClassMappingtoaConcreteType................................................74 RegisteringaNamedType.........................................................................................................75 RegisteringTypeMappingswiththeContainer........................................................................75 UsingaLifetimeManagerwiththeRegisterTypeMethod.......................................................77 SummaryoftheRegisterTypeMethodOverloads....................................................................80 MoreInformation......................................................................................................................81 CreatingInstanceRegistrations.....................................................................................................82 RegisteringanExistingObjectInstanceofanInterfaceorTypetoaContainer.......................82 UsingaLifetimeManagerwiththeRegisterInstanceMethod.................................................85 SummaryoftheRegisterInstanceOverloads............................................................................88 MoreInformation..................................................................................................................89
5

RegisteringInjectedParameterandPropertyValues...................................................................89 RegisteringInjectionforParameters,Properties,andMethodsusingInjectionMembers..90 RegisterConstructorsandParameters.....................................................................................90 SpecifyaPropertyforInjection.................................................................................................92 SpecifyaMethodforInjection..................................................................................................94 InjectingArraysatRunTime.................................................................................................94 InjectingSpecificArrayInstances..............................................................................................96 InjectingAllArrayNamedInstances.........................................................................................97 SummaryoftheInjectionMemberMethodsandOverloads................................................98 MoreInformation..................................................................................................................99 RegisteringGenericParametersandTypes..................................................................................99 RegisteringGenericInterfacesandClasses.............................................................................100 RegisteringTypeMappingsforGenerics.................................................................................102 RegisteringGenericArrays......................................................................................................103 SupportforGenericDecoratorChains................................................................................106 MethodsforRegisteringGenericParametersandTypes.......................................................108 MoreInformation....................................................................................................................108 RegisteringContainerExtensions................................................................................................108 AddingandRemovingExtensions...........................................................................................109 AccessingConfigurationInformationforExtensions..............................................................110 MethodsforRegisteringandConfiguringContainerExtensions............................................111 MoreInformation....................................................................................................................111 RegisteringInterception..............................................................................................................111 RegisteringInterceptorsandInterceptorBehaviorsExplicitlyUsingRegisterType............112 DefaultInterceptorforaType ................................................................................................113 . RegisteringAdditionalInterfaces........................................................................................114 RegisteringPolicyInjectionComponents....................................................................................115 PolicyInjectionRunTimeConfiguration.............................................................................115 DefiningingPoliciesbyUsingtheAPI......................................................................................116 UsingUnityinApplications .........................................................................................................121 . ApplicationDesignConceptswithUnity.....................................................................................121 PluggableArchitectures ..........................................................................................................122 . ManagingCrosscuttingConcerns............................................................................................123 ServiceandComponentLocation ...........................................................................................125 .
6

PolicyInjectionthroughInterception .....................................................................................127 . AddingUnitytoYourApplication................................................................................................128 DependencyInjectionwithUnity................................................................................................130 ResolvingObjects........................................................................................................................130 ResolvinganObjectbyType.......................................................................................................131 TheResolveMethodOverloadsforDefaultRegistrations......................................................132 UsingtheResolveMethodwithDefaultRegistrations...........................................................132 ResolvingTypesRegisteredasInterfaces............................................................................132 ResolvingTypesRegisteredasBaseClasses........................................................................133 ResolvinganObjectbyTypeandRegistrationName.................................................................134 TheResolveMethodOverloadsforNamedRegistrations......................................................134 UsingtheResolveMethodwithNamedRegistrations ...........................................................135 . ResolvingTypesRegisteredasInterfaces............................................................................135 ResolvingTypesRegisteredasBaseClasses........................................................................136 ResolvingGenericTypesbyName..........................................................................................137 MoreInformation....................................................................................................................137 ResolvingGenericTypes..........................................................................................................138 MoreInformation....................................................................................................................140 ResolvingAllObjectsofaParticularType...................................................................................140 TheResolveAllMethodOverloads..........................................................................................140 UsingtheResolveAllMethod..................................................................................................141 ResolvingAllGenericTypesbyName.....................................................................................142 ResolvingObjectsbyUsingOverrides.........................................................................................142 UsingParameterOverrides.....................................................................................................144 UsingPropertyOverrides........................................................................................................147 UsingDependencyOverrides..................................................................................................148 Moreinformation....................................................................................................................152 DeferringtheResolutionofObjects............................................................................................152 RetrievingContainerRegistrationInformation...........................................................................155 ViewingtheContainerRegistrationsandMappings...............................................................155 CheckingfortheExistenceofaSpecificRegistration .............................................................157 . UnderstandingLifetimeManagers..............................................................................................157 UnityBuiltInLifetimeManagers............................................................................................158 MoreInformation....................................................................................................................163
7

UsingBuildUptoWireUpObjectsNotCreatedbytheContainer..............................................163 TheBuildUpMethodOverloads..............................................................................................163 UsingtheBuildUpMethod......................................................................................................164 MoreInformation....................................................................................................................165 UsingInjectionAttributes ...........................................................................................................165 . AnnotatingObjectsforConstructorInjection.............................................................................166 SingleConstructorAutomaticInjection..............................................................................166 SpecifyingNamedTypeMappings......................................................................................169 MultipleConstructorInjectionUsinganAttribute..............................................................170 NotesonUsingConstructorInjection.....................................................................................172 HowUnityResolvesTargetConstructorsandParameters.................................................173 ConstructorInjectionwithExistingObjects........................................................................173 AvoidingCircularReferences ..............................................................................................173 . WhentoUseConstructorInjection.....................................................................................173 AnnotatingObjectsforProperty(Setter)Injection.....................................................................174 UsingOptionalDependencies.................................................................................................179 NotesonUsingProperty(Setter)Injection.............................................................................179 UsingtheDependencyAttributewithConstructorandMethodParameters....................180 PropertyInjectionwithExistingObjects.............................................................................180 AvoidingtheUseofPublicProperties.................................................................................180 AvoidingCircularReferences ..............................................................................................180 . . WhentoUseProperty(Setter)Injection ............................................................................180 AnnotatingObjectsforMethodCallInjection............................................................................181 SpecifyingNamedTypeMappings......................................................................................184 NotesonUsingMethodCallInjection.....................................................................................185 MethodCallInjectionwithExistingObjects .......................................................................185 . AvoidingCircularReferences ..............................................................................................185 . WhentoUseMethodCallInjection....................................................................................185 UsingContainerHierarchies........................................................................................................186 ConstructingandDisposingUnityContainers.........................................................................186 ControllingObjectScopeandLifetime....................................................................................187 RegisteringDifferentMappingsforSpecificTypes.................................................................188 CircularReferenceswithDependencyInjection.........................................................................190 DesignofUnity............................................................................................................................192
8

DesignGoals............................................................................................................................192 Operation............................................................................................................................192 ExtendingandModifyingUnity...................................................................................................192 CreatingLifetimeManagers........................................................................................................193 CreatingandUsingContainerExtensions...................................................................................193 CreatingPolicyInjectionMatchingRules....................................................................................194 Example:TheTagAttributeMatchingRule...............................................................................194 CreatingInterceptionPolicyInjectionCallHandlers...................................................................196 TheICallHandlerInterfaceandPipelineExecution.................................................................197 OutlineImplementationofaCallHandler0............................................................................198 ExceptionsandAbortedPipelineExecution............................................................................200 CreatingInterceptionHandlerAttributes...................................................................................202 ExampleCallHandlerAttribute...........................................................................................203 CreatingInterceptionBehaviors .................................................................................................204 . DeploymentandOperations.......................................................................................................204 UsingXCopy.............................................................................................................................205 UsingtheGlobalAssemblyCache...........................................................................................205 InstallinganAssemblyintheGlobalAssemblyCache ........................................................205 . Versioning................................................................................................................................206 UsingUnityinPartialTrustEnvironments..................................................................................206 UpdatingtheUnityAssemblies...................................................................................................206 UpdatingPrivateAssemblies...................................................................................................207 UpdatingSharedAssemblies...................................................................................................207 StrongNamingtheUnityAssemblies..........................................................................................207 UsingVisualStudiotoStrongNametheUnityAssemblies.....................................................208 UnityQuickStarts.........................................................................................................................209 BuildingtheQuickStarts..........................................................................................................209 Walkthrough:TheUnityStopLightQuickStart............................................................................210 RegisteringMappingsforTypeswiththeContainer...............................................................211 ImplementingtheModelViewPresenterPattern.................................................................212 InjectingaBusinessComponentusingProperty(Setter)Injection ........................................213 . ImplementingaConfigurablePluggableArchitecture............................................................215 Walkthrough:TheUnityEventBrokerExtensionQuickStart......................................................216 CreatingaCustomUnityContainerExtension........................................................................218
9

AddinganExtensiontotheUnityContaineratRunTime ......................................................220 . UsingtheExampleEventBrokerExtension............................................................................220

10

UnityDependencyInjection
WelcometoUnity.ThefollowingsectionsofthisguidancedescribethewaysthatyoucanuseUnity dependencyinjectionandUnityinterceptioninyourapplications.Thesectionsare: WhatIsUnity? WhatDoesUnityDo? WhenShouldIUseUnity? AboutThisReleaseofUnity ConfiguringUnity UsingUnityinApplications DesignofUnity ExtendingandModifyingUnity DeploymentandOperations UnityQuickStarts.ThistopicwalksthroughtheQuickStartapplicationsthatdemonstratehow toexecutecommonoperationsinyourapplications.

WhatIsUnity?
Unityisalightweight,extensibledependencyinjectioncontainerthatsupportsinterception, constructorinjection,propertyinjection,andmethodcallinjection.YoucanuseUnityinavarietyof differentwaystohelpdecouplethecomponentsofyourapplications,tomaximizecoherencein components,andtosimplifydesign,implementation,testing,andadministrationofthese applications. UnityisageneralpurposecontainerforuseinanytypeofMicrosoft.NETFrameworkbased application.Itprovidesallofthefeaturescommonlyfoundindependencyinjectionmechanisms, includingmethodstoregistertypemappingsandobjectinstances,resolveobjects,manageobject lifetimes,andinjectdependentobjectsintotheparametersofconstructorsandmethodsandasthe valueofpropertiesofobjectsitresolves. Inaddition,Unityisextensible.Youcanwritecontainerextensionsthatchangethebehaviorofthe container,oraddnewcapabilities.Forexample,theinterceptionfeatureprovidedbyUnity,which youcanusetoaddpoliciestoobjects,isimplementedasacontainerextension.
11

ThefollowingsectionsofthisguidancedescribewhatUnitycando,whenyoushouldchooseUnity, andthewaysthatyoucanuseitinyourapplications: WhatDoesUnityDo?Thistopicprovidesabriefoverviewthatwillhelpyoutounderstand whatUnitycando,andexplainssomeoftheconceptsandfeaturesitincorporates.Italso providesasimpleexampleofthewaythatyoucanwritecodetouseUnity. WhenShouldIUseUnity?ThistopicwillhelpyoutodecideifUnityissuitableforyour requirements.ItexplainsthebenefitsofusingUnity,andanyalternativetechniquesyoumay consider.ItalsoprovidesdetailsofanylimitationsofUnitythatmayaffectyourdecisionto useit. AboutThisReleaseofUnity.Thistopiccontainsinformationaboutthechangesinthisrelease, thetargetaudienceandsystemrequirements,migrationandsidebysideexecution,and linkstootherMicrosoftpatterns&practicesresources. ConfiguringUnity.ThistopicdescribeshowyoucanpopulateaUnitycontainerwiththetype registrations,mappings,extensions,andotherinformationrequiredbyyourapplication. UsingUnityinApplications.ThistopicexplainshowtouseUnityinyourownapplications.It explainshowtoaddUnitytoyourapplication,howtoresolveobjects,andhowtotake advantageofthemanyothercapabilitiesofUnity. DesignofUnity.ThistopicexplainsthedecisionsthatwentintodesigningUnityandthe rationalebehindthosedecisions. ExtendingandModifyingUnity.ThistopicexplainshowtoextendUnityandhowtomodify thesourcecode. DeploymentandOperations.ThistopicexplainshowtodeployandupdatetheUnity assembliesandusetheinstrumentationexposedbyUnity.

WhatDoesUnityDo?
Byusingdependencyinjectionframeworksandinversionofcontrolmechanisms,youcangenerate andassembleinstancesofcustomclassesandobjectsthatcancontaindependentobjectinstances andsettings.ThefollowingsectionsexplainthewaysthatyoucanuseUnity,andthefeaturesit provides: TheTypesofObjectsUnityCanCreate RegisteringExistingTypesandObjectInstances ManagingtheLifetimeofObjects SpecifyingValuesforInjection PopulatingandInjectingArrays,IncludingGenericArrays
12

InterceptingCallstoObjects

TheTypesofObjectsUnityCanCreate
YoucanusetheUnitycontainertogenerateinstancesofanyobjectthathasapublicconstructor(in otherwords,objectsthatyoucancreateusingthenewoperator),withoutregisteringamappingfor thattypewiththecontainer.WhenyoucalltheResolvemethodandspecifythedefaultinstanceof atypethatisnotregistered,thecontainersimplycallstheconstructorforthattypeandreturnsthe result. UnityexposesamethodnamedRegisterTypethatyoucanusetoregistertypesandmappingswith thecontainer.ItalsoprovidesaResolvemethodthatcausesthecontainertobuildaninstanceof thetypeyouspecify.Thelifetimeoftheobjectitbuildscorrespondstothelifetimeyouspecifyin theparametersofthemethod.Ifyoudonotspecifyavalueforthelifetime,thecontainercreatesa newinstanceoneachcalltoResolve.FormoreinformationseeRegisteringTypesandType Mappings.

RegisteringExistingTypesandObjectInstances
UnityexposesamethodnamedRegisterInstancethatyoucanusetoregisterexistinginstanceswith thecontainer.WhenyoucalltheResolvemethod,thecontainerreturnstheexistinginstanceduring thatlifetime.Ifyoudonotspecifyavalueforthelifetime,theinstancehasacontainercontrolled lifetime,whichmeansthatiteffectivelybecomesasingletoninstance.Formoreinformationsee CreatingInstanceRegistrations.

ManagingtheLifetimeofObjects
Unityallowsyoutochoosethelifetimeofobjectsthatitcreates.Bydefault,Unitycreatesanew instanceofatypeeachtimeyouresolvethattype.However,youcanusealifetimemanagerto specifyadifferentlifetimeforresolvedinstances.Forexample,youcanspecifythatUnityshould maintainonlyasingleinstance(effectively,asingleton).Itwillcreateanewinstanceonlyifthereis noexistinginstance.Ifthereisanexistinginstance,itwillreturnareferencetothisinstead.There arealsootherlifetimemanagersyoucanuse.Forexample,youcanusealifetimemanagerthat holdsonlyaweakreferencetoobjectssothatthecreatingprocesscandisposethem,oralifetime managerthatmaintainsaseparatesingleinstanceofanobjectoneachseparatethreadthat resolvesit. Youcanspecifythelifetimemanagertousewhenyouregisteratype,atypemapping,oranexisting objectusingdesigntimeconfiguration,asshowninSpecifyingTypesintheConfigurationFileor, alternatively,youcanuseruntimecodetoaddaregistrationtothecontainerthatspecifiesthe lifetimemanageryouwanttouse,asshowninRegisteringTypesandTypeMappingsandCreating InstanceRegistrations.

13

ConfiguringTypesforInjectionintoConstructors,Methods,and Properties
Unityenablesyoutousetechniquessuchasconstructorinjection,propertyinjection,andmethod callinjectiontogenerateandassembleinstancesofobjectscompletewithalldependentobjects andsettings.FormoreinformationseeSpecifyingValuesforInjectionandRegisteringInjected ParameterandPropertyValues.

ExampleApplicationCodeforConstructorInjection
Asanexampleofconstructorinjection,ifaclassthatyouinstantiateusingtheResolvemethodof theUnitycontainerhasaconstructorthatdefinesoneormoredependenciesonotherclasses,the Unitycontainerautomaticallycreatesthedependentobjectinstancespecifiedintheparametersof theconstructor.Forexample,thefollowingcodeshowsaclassnamedCustomerServicethathasa dependencyonaclassnamedLoggingService. C#
publicclassCustomerService { publicCustomerService(LoggingServicemyServiceInstance) { //workwiththedependentinstance myServiceInstance.WriteToLog("SomeValue"); } }

VisualBasic
PublicClassCustomerService PublicSubNew(myServiceInstanceAsLoggingService) 'workwiththedependentinstance myServiceInstance.WriteToLog("SomeValue") EndSub EndClass

Atruntime,developerscreateaninstanceoftheCustomerServiceclassusingtheResolvemethod ofthecontainer,whichcausesittoinjectaninstanceoftheconcreteclassLoggingServicewithinthe scopeoftheCustomerServiceclass. C#


IUnityContaineruContainer=newUnityContainer(); CustomerServicemyInstance=uContainer.Resolve<CustomerService>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsCustomerService=uContainer.Resolve(OfCustomerService)()

14

ExampleApplicationCodeforProperty(Setter)Injection
Inadditiontoconstructorinjection,describedearlier,Unitysupportspropertyandmethodcall injection.Thefollowingcodedemonstratespropertyinjection.AclassnamedProductService exposesasapropertyareferencetoaninstanceofanotherclassnamedSupplierData(notdefined inthefollowingcode).Unitydoesnotautomaticallysetpropertiesaspartofcreatinganinstance; youmustexplicitlyconfigurethecontainertodoso.OnewaytodothisistoapplytheDependency attributetothepropertydeclaration,asshowninthefollowingcode. C#
publicclassProductService { privateSupplierDatasupplier; [Dependency] publicSupplierDataSupplierDetails { get{returnsupplier;} set{supplier=value;} } }

VisualBasic
PublicClassProductService PrivatesupplierAsSupplierData <Dependency()>_ PublicPropertySupplierDetails()AsSupplierData Get Returnsupplier EndGet Set(ByValvalueAsSupplierData) supplier=value EndSet EndProperty EndClass

Now,creatinganinstanceoftheProductServiceclassusingUnityautomaticallygeneratesan instanceoftheSupplierDataclassandsetsitasthevalueoftheSupplierDetailspropertyofthe ProductServiceclass.

PopulatingandInjectingArrays,IncludingGenericArrays
Youcandefinearrays,includingarraysofgenerictypes,andUnitywillinjectthearrayintoyour classesatruntime.Youcanspecifythemembersofanarray,orhaveUnitypopulatethearray automaticallybyresolvingallofthematchingtypesdefinedinyourconfiguration.Youcanthenuse thepopulatedarraysastypestoresolvedirectly,ortosetthevaluesofconstructorandmethod parametersandproperties.Arrayscanbedefinedinconfigurationfilesorbyaddingthedefinitions tothecontaineratruntimeusingcode.
15

Fordetailsandexamples,seethesectionsonarraysinthefollowingtopics: ConfiguringInjectedParameterandPropertyValues RegisteringInjectedParameterandPropertyValues RegisteringGenericParametersandTypes

InterceptingCallstoObjects
Thebesttypesinobjectorientedsystemsareonesthathaveasingleresponsibility.Butassystems grow,otherconcernstendtocreepin.Systemmonitoring,suchaslogging,eventcounters, parametervalidation,andexceptionhandlingarejustsomeexamplesofareaswherethisis common.Thesecrosscuttingconcernsoftenrequirelargeamountsofrepetivecodethroughoutthe applicationandifyourdesignchoicechanges,forexampleyouchangeyourloggingframework,then theloggingcallsmustbechangedinmanyplacesthroughoutthecodeset. Interceptionisatechniquethatenablesyoutoaddcodethatwillrunbeforeandafteramethodcall onatargetobject.Thecallisinterceptedandadditionalprocessingcanhappen.Whenyouperform thiscodingprocessmanually,youarefollowingwhatiscommonlyknownasthedecoratorpattern. Writingdecoratorsrequiresthatthetypesinquestionbedesignedforitinthebeginning,and requiresadifferentdecoratortypeforeachtypeyouaredecorating. TheUnityinterceptionsystemcreatesthedecoratorsautomatically.Thisallowsyoutoeasilyreuse codethatimplementsthesecrosscuttingconcernswithminimal,ifany,attentiontowhattypesthe crosscuttingconcernswillbeappliedto.

ExampleApplicationCode
Thefollowingexampleconfiguresthecontaineratruntimeforinterceptionofthetype TypeToInterceptbyusingaVirtualMethodInterceptorinterceptorwithaninterceptionbehavior, ABehavior,andanadditionalinterfacetobeimplemented. C#
IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<Interception>(); container.RegisterType<TypeToIntercept>( newInterceptor<VirtualMethodInterceptor>(), newInterceptionBehavior<ABehavior>(), newAdditionalInterface<IOtherInterface>());

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfInterception)() container.RegisterType(OfTypeToIntercept)(NewInterceptor(Of VirtualMethodInterceptor)(),NewInterceptionBehavior(OfABehavior)(),New AdditionalInterface(OfIOtherInterface)())

Youcouldthenresolveaninstancebyusingthefollowingcall:
16

C#
TypeToInterceptinstance=container.Resolve<TypeToIntercept>();

VisualBasic
DiminstanceAsTypeToIntercept=container.Resolve(OfTypeToIntercept)()

Nowwhencallingmethodsonaninstance,thecodeintheABehaviorclasswillbeexecutedbefore andafteranycalltotheinstance.

WhenShouldIUseUnity?
Dependencyinjectionprovidesopportunitiestosimplifycode,abstractdependenciesbetween objects,andautomaticallygeneratedependentobjectinstances.Ingeneral,youshoulduseUnity when: Youwishtobuildyourapplicationaccordingtosoundobjectorientedprinciples(followingthe fiveprinciplesofclassdesign,orSOLID),butdoingsowouldresultinlargeamountsof difficulttomaintaincodetoconnectobjectstogether. Yourobjectsandclassesmayhavedependenciesonotherobjectsorclasses. Yourdependenciesarecomplexorrequireabstraction. Youwanttotakeadvantageofconstructor,method,orpropertycallinjectionfeatures. Youwanttomanagethelifetimeofobjectinstances. Youwanttobeabletoconfigureandchangedependenciesatruntime. Youwanttointerceptcallstomethodsorpropertiestogenerateapolicychainorpipeline containinghandlersthatimplementcrosscuttingtasks. YouwanttobeabletocacheorpersistthedependenciesacrosspostbacksinaWeb application.

ThefollowingsectionsprovidemoreinformationtohelpyoudecidewhetherUnityissuitablefor yourrequirements: ScenariosforUnity BenefitsofUnity LimitationsofUnity

EnterpriseLibrary,alsofromtheMicrosoftpatterns&practicesgroup,usesUnityasitsprimary mechanismforgeneratinginstancesofEnterpriseLibraryobjects.Forinformationaboutthisand

17

otherfeaturesofEnterpriseLibrary,seetheEnterpriseLibraryCommunitysiteonCodePlex,orthe MicrosoftEnterpriseLibrarypagesonMSDN.

ScenariosforUnity
Unityaddressestheissuesfacedbydevelopersengagedincomponentbasedsoftwareengineering. Modernbusinessapplicationsconsistofcustombusinessobjectsandcomponentsthatperform specifictasksorgenerictaskswithintheapplication,inadditiontocomponentsthatindividually addresscrosscuttingconcernssuchaslogging,authentication,authorization,caching,andexception handling. Thekeytosuccessfullybuildingthesetypesofapplicationsistoachieveadecoupledorveryloosely coupleddesign.Looselycoupledapplicationsaremoreflexibleandeasiertomaintain.Theyarealso easiertotestduringdevelopment.Youcanmockupshims(lightweightmockimplementations)of objectsthathavestrongconcretedependencies,suchasdatabaseconnections,network connections,enterpriseresourceplanning(ERP)connections,andrichuserinterfacecomponents. Dependencyinjectionisaprimetechniqueforbuildinglooselycoupledapplications.Itprovides waystohandlethedependenciesbetweenobjects.Forexample,anobjectthatprocessescustomer informationmaydependonotherobjectsthataccessthedatastore,validatetheinformation,and checkthattheuserisauthorizedtoperformupdates.Dependencyinjectiontechniquescanensure thatthecustomerclasscorrectlyinstantiatesandpopulatesalltheseobjects,especiallywherethe dependenciesmaybeabstract. Thefollowingdesignpatternsdefinearchitecturalanddevelopmentapproachesthatsimplifythe process: InversionofControl(IoC)pattern.Thisgenericpatterndescribestechniquesforsupportinga pluginarchitecturewhereobjectscanlookupinstancesofotherobjectstheyrequire. DependencyInjection(DI)pattern.ThisisaspecialcaseoftheIoCpatternandisaninterface programmingtechniquebasedonalteringclassbehaviorwithoutthechangingtheclass internals.Developerscodeagainstaninterfacefortheclassanduseacontainerthatinjects dependentobjectinstancesintotheclassbasedontheinterfaceorobjecttype.The techniquesforinjectingobjectinstancesareinterfaceinjection,constructorinjection, property(setter)injection,andmethodcallinjection. Interceptionpattern.Thispatternintroducesanotherlevelofindirection.Thistechnique placesaproxyobjectbetweentheclientandtherealobject.Theclientbehavioristhesame aswheninteractingdirectlytotherealobject,buttheproxyinterceptsthecallsandmanages theirexecutionbycollaboratingwiththerealobjectandotherobjectsasrequired.

BenefitsofUnity
Unityprovidesdeveloperswiththefollowingadvantages:
18

Itprovidessimplifiedobjectcreation,especiallyforhierarchicalobjectstructuresand dependencies,whichsimplifiesapplicationcode.Itcontainsamechanismforbuilding(or assembling)instancesofobjects,whichmaycontainotherdependentobjectinstances. Itsupportsabstractionofrequirements;thisallowsdeveloperstospecifydependenciesatrun timeorinconfigurationandsimplifythemanagementofcrosscuttingconcerns. Itincreasesflexibilitybydeferringcomponentconfigurationtothecontainer.Italsosupports ahierarchyforcontainers. Ithasaservicelocationcapability,whichisusefulinmanyscenarioswhereanapplication makesrepeateduseofcomponentsthatdecoupleandcentralizefunctionality. Itallowsclientstostoreorcachethecontainer.ThisisespeciallyusefulinASP.NETWeb applicationswheredeveloperscanpersistthecontainerintheASP.NETsessionor application. Ithasaninterceptioncapability,whichallowsdeveloperstoaddfunctionalitytoexisting componentsbycreatingandusinghandlersthatareexecutedbeforeamethodorproperty callreachesthetargetcomponent,andagainasthecallsreturns. Itcanreadconfigurationinformationfromstandardconfigurationsystems,suchasXMLfiles, anduseittoconfigurethecontainer. Itmakesnodemandsontheobjectclassdefinition.Thereisnorequirementtoapply attributestoclasses(exceptwhenusingpropertyormethodcallinjection),andthereareno limitationsontheclassdeclaration. Itsupportscustomcontainerextensionsthatyoucanimplement;forexample,youcan implementmethodstoallowadditionalobjectconstructionandcontainerfeatures,suchas caching. Itallowsarchitectsanddeveloperstomoreeasilyimplementcommondesignpatternsoften foundinmodernapplications.

LimitationsofUnity
DependencyinjectionthroughUnitycanhaveaminorimpactonperformance,anditcanincrease complexitywhereonlysimpledependenciesexist.YoushouldnotuseUnityinthefollowing situations: Whenyourobjectsandclasseshavenodependenciesonotherobjectsorclasses. Whenyourdependenciesareverysimpleanddonotrequireabstraction.

AboutThisReleaseofUnity
19

ThissectioncontainsthefollowingtopicsthatwillhelpyoutounderstandthisreleaseofUnityand helpyouunderstandhowtouseitalongsideearlierversionsormigrateyourapplicationstothis version.Thissectionincludesthefollowingtopics: ChangesinThisRelease TargetAudienceandSystemRequirements MigrationandSidebySideExecution Relatedpatterns&practicesLinks CopyrightandTermsofUse

HowtoUseThisGuidance
Thefollowingtableshowswhereyoucanlooktofindmoreinformationaboutspecifictopics coveredbythisguidance.
If you want to find out about... What's new in this release of Unity What you can do with Unity When you should choose to use Unity How to configure Unity How to use Unity in your applications How to resolve objects in Unity How to use injection for methods and properties How to use interception How to use interception and create policies How to use container hierarchies Issues with circular references when using Unity How to deploy Unity The design of Unity How to extend and modify Unity Additional guidance and information Read this section... Changes in This Release What Does Unity Do? When Should I Use Unity? Configuring Unity Using Unity in Applications Resolving Objects Using Injection Attributes Using Interception in Applications Using Interception and Policy Injection Using Container Hierarchies Circular References with Dependency Injection Deployment and Operations Design of Unity Extending and Modifying Unity The Community Web Site on CodePlex

MoreInformation
Forrelatedinformation,seethefollowingguidance: TheUnityCommunityWebSiteonCodePlex
20

LoosenUpTameYourSoftwareDependenciesforMoreFlexibleAppsbyJamesKovacsin MSDNMagazine DesignPatterns:DependencyInjectionbyGriffinCaprioinMSDNMagazine AspectOrientedProgrammingEnablesBetterCodeEncapsulationandReusebyDharma Shukla,SimonFell,andChrisSellsinMSDNMagazine AspectOrientedProgrammingbyMatthewDeitersonMSDN CreateaCustomMarshalingImplementationUsing.NETRemotingandCOMInteropbyJim SievertinMSDNMagazine TheEFxArchitecturalGuidanceSoftwareFactorybyJezzSantosonMSDN

ChangesinThisRelease
Unity2.0April2010isanewreleaseoftheMicrosoftpatterns&practicesUnitydependency injectionandinterceptionsystem.Thisreleasealsoincludesadditionsinfunctionality,andhasbeen adaptedtoworkwithMicrosoftVisualStudio2010;andwiththeMicrosoft.NETFramework versions3.5SP1and4.0. GotoCodePlexforinformationonKnownIssues. ThefollowingsectionsdiscussthechangestoUnity: BreakingChangestoUnity ChangesinUnity

BreakingChangestoUnity
ThissectionliststhebreakingchangesinUnity2.0. Unity2.0usesanewstreamlinedconfigurationschemaforConfiguringUnity.Partial backwardcompatibilityisprovidedforpreviousconfigurationschemas.Thenewschema breakspreviouscontainerextensionconfigurationsthatuse<extensionConfig>. Unity2.0configurationAPIchange: ThepreviousAPIusedtoloadcontainerconfigurationhasbeendeprecated.Previous versionsusedthefollowingapproach: C#
IUnityContainermyContainer=newUnityContainer(); UnityConfigurationSectionsection =(UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers["containerName"].Configure(myContainer);
21

InUnity2.0,youhavethetwochoices.YoucanuseConfigurationManagerandConfigureto loadagivencontainerfromaspecificnamedconfigurationsection,asshowninthe followingexample. C#


IUnityContainermyContainer=newUnityContainer(); UnityConfigurationSectionsection =(UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Configure(myContainer,"containerName");

Otherwise,youcanuseLoadConfigurationtoloadagivennamedcontainerfromthe defaultconfigurationsection,asshowninthefollowingexample. C#
IUnityContainermyContainer=newUnityContainer(); myContainer.LoadConfiguration("containerName");

ThereareseveraloverloadsofthenewLoadConfigurationextensionmethod.SeeUsing DesignTimeConfigurationformoreinformation. Thearrangementofcallhandlersandmatchingruleshasbeenchanged.Formoreinformation seeConfiguringPolicyInjectionPoliciesandEnterpriseLibraryCallHandlers. TheUnityforSilverlightassemblyhaschangedfromMicrosoft.Practices.Unity.DLLto Microsoft.Practices.Unity.Silverlight.dll.

ChangesinUnity
Thefollowingchangesareimplementedinthisrelease: TheObjectBuildergenericdependencyinjectionmechanism,whichwaspreviouslydistributed asaseparateassembly,isnowintegratedwithUnity.Younolongerneedtoreferencethe ObjectBuilderassemblyinyourprojects. TheStaticFactory.StaticFactoryExtensiontoUnity,whichallowsyoutospecifyafactory functionthatthecontainerwillusetocreateanobject,wasshippedasaseparateprojectin Unity1.2.Inthisrelease,itiscontainedwithinthemainUnityassemblybutisdeprecated. UsethenewInjectionFactoryclass. AnewInjectionFactoryclasshasbeenadded.Itenablesyouspecifyafactorymethodthatthe containerwillusetocreatetheobject.Itisaneasierwaytoaccomplishthesametaskasthe oldStaticFactory.StaticFactoryExtension. Unityprovidesanewinterceptionprocessandprovidesinterceptorsthatenableyouto interceptcallstoobjectsandattachbehaviorstotheinterceptedmethods.Abehaviors pipelineisusedinsteadofthepreviouscallhandlerspipeline.Interceptionissupportedwith orwithoutadependencyinjectioncontainer.SeeInterceptionwithUnity.
22

AHierarchicalLifetimeManagerisprovidedtoregisteranobjectintheparentcontainersuch thateachchildcontainerresolvesitsowninstanceoftheobjectinsteadofsharingonewith theparent.UnderstandingLifetimeManagers Dependenciescanbemadeoptionalbyusingthe<optional>elementinconfigurationfiles, the[OptionalDependency]attribute,orOptionalParameterinyourcode.SeeAnnotating ObjectsforProperty(Setter)Injection. Unitynowprovidestheabilitytospecifyparametervaluesforconstructors,orspecificvalues forproperties,atResolvetime.Thesevaluesoverridewhatthecontainerwouldhave otherwisesupplied.ParameterOverride,PropertyOverride,andDependencyOverrideare ResolverOverrideimplementationsthatprovidesupportforoverridingtheregistration informationforresolvinginstancesoftypes.ResolvingObjectsbyUsingOverrides APerResolveLifetimeManagerregistersanobjectsuchthatthebehaviorislikea TransientLifetimeManager,butalsoprovidesasignaltothedefaultbuildplan,markingthe typesothatinstancesarereusedacrossthebuildupobjectgraph.UnderstandingLifetime Managers TheRegistrationspropertyandIsRegisteredmethodhavebeenadded.Theseletyouquery thecontainerandretrieveinformationaboutwhatiscurrentlyregistered.SeeRetrieving ContainerRegistrationInformation. Youcanusethe.NETstandardtypeFunc<T>(C#)orFunc(OfT)(VisualBasic)withthe Resolvemethodifyouwishtodefertheresolutionofanobject.Formoreinformationsee DeferringtheResolutionofObjects. Specifyingaresolvedarraywithoutprovidinganymemberswillresultinanempty(zero length)array. Inaconfigurationfile,the<array/>elementwithnochildelementswillgeneratea zerolengtharrayforbothgenericandnongenerictypes.Ifyouwanttoresolveall configuredtypestopopulatethearray(effectivelyinvokingtheResolveAll behavior),youmustusea<dependency/>elementinstead. Whenperformingruntimeconfiguration,theResolvedArrayParameterand GenericResolvedArrayParameterclasseswillgenerateazerolengtharrayifyoudo notspecifythemembersforthearray.Ifyouwanttoresolveallconfiguredtypes, usetheGenericParameterclassandspecifythearraytypefollowedbythe appropriatebracketstoindicateanarraytypeinthelanguageyouareusing.For example,GenericParameter("T[]")inC#orGenericParameter("T()")inVisualBasic.

TargetAudienceandSystem Requirements
23

Thisguidanceisintendedforsoftwarearchitectsandsoftwaredevelopers.Togetthegreatest benefitfromthisguidance,youshouldhaveanunderstandingofthefollowingtechnologies: MicrosoftVisualC#orMicrosoftVisualBasic.NET Microsoft.NETFramework

SystemRequirementsandPrerequisites
ThefollowingarethesystemrequirementsforusingUnity: Operatingsystem:MicrosoftWindows7Professional,Enterprise,orUltimate;Windows Server2003R2;WindowsServer2008withServicePack2;WindowsServer2008R2; WindowsVistawithServicePack2;WindowsXPwithServicePack3. Microsoft.NETFramework3.5withServicePack1orMicrosoft.NETFramework4.0.

Forarichdevelopmentenvironmentanduseoftheintegratedconfigurationtool,thefollowingare recommended: MicrosoftVisualStudio2008DevelopmentSystemwithServicePack1(anyedition)or MicrosoftVisualStudio2010DevelopmentSystem(anyedition) Toruntheunittests,thefollowingarealsorequired: MicrosoftVisualStudio2008Professional,VisualStudio2008TeamEdition,VisualStudio2010 Premium,VisualStudio2010Professional,orVisualStudio2010Ultimateedition Moqv3.1assemblies.

SystemRequirementsforUnityforSilverlight
ThefollowingarethesystemrequirementsforusingUnityforSIlverlight: Operatingsystem:MicrosoftWindows7Professional,EnterpriseorUltimate;Windows Server2003R2;WindowsServer2008withServicePack2;WindowsServer2008R2;or WindowsVistawithServicePack2. MicrosoftSilverlight3orMicrosoftSilverlight4.

Forarichdevelopmentenvironment,thefollowingarerecommended: MicrosoftVisualStudio2008DevelopmentSystemwithServicePack1(anyedition)or MicrosoftVisualStudio2010DevelopmentSystem(anyedition). MicrosoftSilverlight3ToolsforVisualStudio2008SP1orVisualStudio2010,orMicrosoft Silverlight4ToolsforVisualStudio2010

Toruntheunittests,thefollowingarealsorequired:

24

MicrosoftVisualStudio2008Professional,VisualStudio2008TeamEdition,VisualStudio 2010Premium,VisualStudio2010Professional,orVisualStudio2010Ultimateedition.

MigrationandSidebySideExecution
Ingeneral,applicationsthatusepreviousversionsofUnitywillfunctionwiththisreleasewithoutthe needforanycodechanges.Itwillbenecessary,however,toupdatethereferencestorefertothe newassembliesandtoupdatetheconfigurationfilestoreferencethecorrectversionofthe assemblies. ThisversionofUnitycanalsobeinstalledsidebysidewithearlierversions.Youcandeploynew applicationswrittenforthisversionofUnityalongwithapplicationswrittenforearlierversions.In addition,youcanalsochoosetomigrateexistingapplicationstothenewversion. Ifyoudecidetousesidebysideexecution,youmustdeploythedifferentUnityversionsindifferent directories.Inanyspecificdirectory,youcannotmixandmatchassembliesfromdifferentversions. TheshippedprojectfilesusedataintheAssemblyInfo.csfiletobuildassembliesthathavedifferent versioninformation.Thisallowsyoutousestrongnamesandtoadddifferentversionstotheglobal assemblycache(GAC)forsidebysideexecution.

PartialMigration
EachassemblyinanapplicationcanrefertoonlyoneversionofUnity,butanapplicationthathas multipleassembliescanrefertomorethanoneversion.Forexample,youmayhaveanapplication withtwoassemblies,bothusingtheUnity1.1.OneassemblycanbemigratedtouseUnity2.0,and theotherassemblycanremainunchanged.Thismeansyoucangraduallymigrateyourapplication, oneassemblyatatime.However,althoughpartialmigrationissupported,itissomewhat complicatedtoimplement;therefore,itisnotrecommended. Fordetailsonmigratingapplicationsandconfigurationfilesseethe"EnterpriseLibrary5.0andUnity 2.0MigrationGuide"athttp://www.codeplex.com/entlib/. FordetailsonmigratingextensionsseeReusingConfigurationFilesBasedonaPreviousSchema.

ReusingConfigurationFilesBasedona PreviousSchema
AlthoughthisdocumentationisbasedontheUnity2.0configurationschemaandallexamplesuse Unity2.0,partialbackwardcompatibilityisprovidedfortheUnity1.2configurationschema.
25

However,youcannotsimplyuseaUnity1.2configurationfile.Inordertousethecontentsofa Unity1.2configurationfileyoumust: 1. Createanewconfigurationfile. 2. Editthe<configSections>topointtothecorrectassembly. 3. Adda<sectionExtension>sectionifyouareusingcontainerextensionsforUnity. 4. CutandpastetheportionsoftheUnity1.2configurationfileyouwishtoreuse. Checktheresultsasyoustillmaygeterrorsdependinguponthespecificportionsyoucut andpaste.

ForinformationonusingtheUnity1.2configurationschemaseeUnityConfigurationSchematicon MSDN.

MigratingCustomExtensions
Unity1.2extensionconfigurationscannotjustbecopiedintoaUnity2.0configurationfile.Thereis no<extensionConfig>sectioninUnity2.0.Howeveryoucanoftencopythecontentsofanold <extensionConfig>sectiontoUnity2.0<register>elements. Forexample,thefollowingisanexcerptfromaUnity1.2configurationfile. XML
<extensionConfig> <addname="interception" type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionC onfigurationElement,Microsoft.Practices.Unity.Interception.Configuration"> <interceptors> <interceptortype="transparentProxy"> <defaulttype="wrappable"/> <keytype="wrappableWithProperty"/> </interceptor> <interceptortype="virtualMethod"> <keytype="wrappableVirtual"name="name"/> </interceptor> </interceptors> </add> </extensionConfig>

InUnity2.0youwoulddothefollowing: 1. Use<sectionExtension>toaddtheextensionelementstotheschemaandaliasestothe configurationsection. XML


<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.Interce

26

ptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>

2. Youwouldthenusethe<extension>elementtoaddtheinterceptionextensiontothe configuration. XML


<extensiontype="Interception"/>

3. ThenyoucouldcopytheinterceptorelementcontentandchangeTransparentProxyto TransparentProxyInterceptor. XML


<containername="configuringDefaultInterceptor"> <extensiontype="Interception"/> <interceptors> <interceptortype="TransparentProxyInterceptor"> <defaulttype="wrappable"/> <keytype="wrappableWithProperty"/> </interceptor> </interceptors> </container>

Youcanusethecontainerelementextensionorinjectionmemberstoaddextensions.Formore informationonUnity2.0extensionsseeConfigurationFilesforInterception.

Relatedpatterns&practicesLinks
ForinformationrelatedtoUnityandothertools,andguidancefordesigningandbuilding applications,seethepatterns&practiceswebsiteandguides:
27

Microsoftpatterns&practicesDeveloperCenter MicrosoftApplicationArchitectureGuide,2ndEdition SolutionDevelopmentFundamentals SecurityGuidanceforApplicationsIndex .NETDataAccessArchitectureGuide Improving.NETApplicationPerformanceandScalability Monitoringin.NETDistributedApplicationDesign Deploying.NETFrameworkbasedApplications

CopyrightandTermsofUse
Thisdocumentisprovided"asis".Informationandviewsexpressedinthisdocument,includingURL andotherInternetwebsitereferences,maychangewithoutnotice.Youbeartheriskofusingit. Someexamplesdepictedhereinareprovidedforillustrationonlyandarefictitious.Noreal associationorconnectionisintendedorshouldbeinferred. Thisdocumentdoesnotprovideyouwithanylegalrightstoanyintellectualpropertyinany Microsoftproduct.Youmaycopyandusethisdocumentforyourinternal,referencepurposes. 2010Microsoft.Allrightsreserved. Microsoft,Windows,WindowsServer,WindowsVista,VisualC#,VisualBasic,andVisualStudioare trademarksoftheMicrosoftgroupofcompanies.Allothertrademarksarepropertyoftheir respectiveowners.

ConfiguringUnity
OneofthekeytasksyouneedtoperformwhenusingUnityistoconfigurethecontainerwiththe requiredaliases,typeregistrations,mappings,andotherinformationthatitrequiresinorderto resolveobjectsatruntimeandinjecttheappropriateobjectsandvaluesintodependentobjects. ThissectioncoversalloftheconfigurationoptionsforUnity,anddescribeshowyoucanconfigure thecontainerusingaconfigurationfile,oratruntimeusingcode. UnitycanreadconfigurationinformationfromanXMLconfigurationfile.Bydefault,thisisthe App.configorWeb.configfileforyourapplication.However,youcanloadconfigurationinformation fromanyotherXMLformatfileorfromothersourcesifrequired. Inaddition,Unityexposesaseriesofmethodsthatyouuseinyourapplicationcodetoconfigurethe container.Thisapproachisusefulwhentheregistrationsandmappingsdependontheenvironment orruntimeinformation,andyoucanchangetheconfigurationatruntimeusingthesemethods. Runtimeconfigurationisalsoagoodchoiceifyouwanttobeabletomanipulatecontainer hierarchiesatruntimetochangetheoverallbehavioroftyperesolution,injection,andinterception. Youcan,ofcourse,useacombinationofdesigntime(configurationfiles)andruntimeconfiguration toachieveexactlytheconfigurationyourequireatanypointduringapplicationexecution. TohelpyouunderstandhowtoconfigureUnity,thissectiondividestheinformationintotwo separatesubsectionsonefordesigntimeconfigurationandoneforruntimeconfiguration.Each sectioncontainsbasicallythesamesetoftopicsthatdescribespecificconfigurationscenarios. Theconfigurationfilesarenotencryptedbydefault.Aconfigurationfilemaycontainsensitive informationaboutconnectionstrings,userIDs,passwords,databaseservers,andcatalogs.You shouldprotectthisinformationagainstunauthorizedread/writeoperationsbyusingencryption techniques.
28

Ifyouwishtorestrictaccesstotheconfigurationfile,itmustbeencryptedorprotectedusing AccessControlLists.Itisrecommendedthattheconfigurationstoreisinthesametrustboundary andthatdecryptingtheconfigurationisdoneinthesametrustboundaryaftertheconfigurationis read. Thecompletesetoftopicsinthissectionisasfollows: DesignTimeConfiguration UsingtheConfigurationTool UsingDesignTimeConfiguration SpecifyingTypesintheConfigurationFile SpecifyingValuesforInjection ExtendingtheUnityConfigurationSchema ConfigurationFilesforInterception DefaultAliasesandAssemblies

RunTimeConfiguration UsingRunTimeConfiguration RegisteringTypesandTypeMappings CreatingInstanceRegistrations RegisteringInjectedParameterandPropertyValues RegisteringGenericParametersandTypes RegisteringContainerExtensions RegisteringInterception

Forinformationaboutusingcontainerhierarchies,seeUsingContainerHierarchies.Forinformation aboutusingUnity,seeUsingUnityinApplications.

DesignTimeConfiguration
ThistopicdescribesthetechniquesyoucanusetoconfigureUnitycontainersusingaconfiguration fileoraconfigurationyouloadintothecontaineratruntime. ThisdocumentationisbasedontheUnity2.0configurationschemaandallexamplesuseUnity2.0. PartialbackwardcompatibilityisprovidedfortheUnity1.2configurationschema.
29

ThefollowingtopicsdescribeUnityconfiguration: UsingtheConfigurationTool.NotavailableforUnityconfiguration. UsingtheUnityXSDtoEnableVisualStudioIntelliSense.Thistopicexplainshowtousethe UnityXSDtoenableIntelliSenseinVisualStudiotoassistinmanuallyeditingtheUnity configuration. ReusingConfigurationFilesBasedonaPreviousSchema.Thistopicexplainshowtocreatea currentconfigurationfilebyreusingaconfigurationfilebasedonapreviousUnityschema. UsingDesignTimeConfiguration.ThistopicexplainstheoverallstructureoftheUnity configurationfile,howyouloadconfigurationinformationatruntime,andhowyoucanuse alternativeconfigurationsourceswithUnity. SpecifyingTypesintheConfigurationFile.Thistopicexplainshowtoconfiguremappingsin thecontainerbetweentypes.Ingeneral,youwillcreatemappingsbetweenaninterfaceand atypethatimplementstheinterface,orbetweenabaseclassandatypethatinheritsthat baseclass.YoucanalsousethissectiontospecifyconcretetypesforwhichyouwantUnityto managethelifetime. TheUnityConfigurationSchema.Thistopicdescribestheconfigurationschemaelementsfor Unity. SpecifyingValuesforInjection.Thistopicexplainshowtoconfigureregistrationsforinstance typessuchasstring,dateandtime,orintegervaluesthatyoucanresolveinyourapplication. ExtendingtheUnityConfigurationSchema.ThistopicexplainshowtoconfigureUnitytoload andusecontainerextensionsthataddadditionalfunctionalitytothecontainer,andhowyou canspecifyconfigurationinformationfortheseextensions. ConfigurationFilesforInterception.Thistopicexplainshowtoconfigureinterceptors, behaviors,policies,handlers,andmatchingrulesthatUnitywillusewhencreatinginstances oftypestowhichyouwanttoaddinterceptioncapabilitiesinordertochangethebehaviorof thatobjectortype.

ForinformationabouthowtoconfigureUnityusingcodethatexecutesatruntimeandcallsthe registrationmethodsoftheUnitycontainer,seeRunTimeConfiguration.Forinformationabout resolvingtypesatruntime,seeResolvingObjects.

UsingtheConfigurationTool
NotavailableforUnityconfiguration.

30

UsingtheUnityXSDtoEnableVisual StudioIntelliSense
YoucanenableIntelliSenseinVisualStudiotoassistthemanualeditingofUnityconfigurationfiles. TheXSDisnotrequired.Configurationwillworkatruntimewithoutit.Itisonlyrequiredfor IntelliSenseinVisualStudio. InorderfortheXSDtobeusedbytheVisualStudioeditorthe<unity>elementmusthaveanXMLNS attributewiththecorrectnamespace.Thefollowingarethetwowaystogetthecorrectnamespace insteadofmanuallyenteringit: YoucanforcetheeditortousetheschemabyclickingSchemasontheXMLmenuand selectingtheentryfortheunityconfigurationschema.Afterthat,the<unity>elementwill appearasanalternativeintheIntelliSensedropdownandbychoosingitfromIntelliSensethe xmlnsattributewillbepopulated.Thisisaperuserandperprojectsetting,soeveryuser workingontheprojectwouldberequiredtoselectthissetting. Youcanenter<unityxmlns="andthenIntelliSensewillshowalistofnamespaceswhichare targetedbyaknownschema.Youcanthenchoosetherightnamespace, http://schemas.microsoft.com/practices/2010/unity,whichwillshowupintheIntelliSense listwhenyouclickonthexmlnsattributeandcompletetheentry.VisualStudiowillthen associatetheURLwiththeactualphysicalfile.Thisistherecommendedoption,sincethe settingpersistswhenyoupasstheconfigurationfiletoanotheruser. Collectionelements,suchasaliases,containers,extensions,namespaces,andassembliesarenot supportedbythexsd,buttheydoworkintheconfigurationfile. Therearesomepredefinedtypenamesforsometypeattributes,suchasforlifetimemanagers,but thesearejustsuggestionsandanytypenameisaccepted. Theschemafortheregisterelementimposesaspecificorderforitschildren,anorderthatisnot requiredbytheconfigurationruntimebutmakestheschemamorerobust.Theorderofchildrenis asfollows:oneoptionallifetime,oneoptionalconstructor,andthenasmanyofmethod,property, interceptor,interceptionBehavior,addInterfaceandanycustomelementasdesired,inanyorder.

UsingDesignTimeConfiguration
UsingUnitytypicallyrequirestheconfigurationofaDependencyInjection(DI)container.Youcan configureacontainerbyusingtheUnityAPI,a.NETconfigurationfile,ortoalimiteddegreebyusing
31

attributes.ThistopicdescribeshowtouseanXMLconfigurationfiletosupplytherequired configurationinformation.. Dependencyinjectionisaveryflexiblepattern,andtobeusedsuccessfullyrequiresthedeveloper toprovideinformationtothecontainerabouthisapplications.Thetwomostcommonconfiguration tasksaresettinguptypemappingsandconfiguringinjectionofatype.Typemappingsenableyouto requestatypefromthecontainerthatresultsinthecontainerreturninganinstanceofadifferent type(typicallyaderivedclassorinterfaceimplementation).Configuringinjectionforatypeentails specifyinginformationsuchaswhichconstructorgetscalled,whichpropertiesgetinjected,and whattheirvaluesare.TheUnityconfigurationschemaencompassesthesetypesofconfiguration andisalsoextensibletoallowforadditionalkindsofconfigurationsuchasUnityinterception configuration,seeTheUnityConfigurationSchema.Thefollowingsectionsprovidemoredetails: FormatoftheUnityConfigurationFile LoadingConfigurationFileInformationintoaContainer LoadingtheConfigurationfromAlternativeFiles

FormatoftheUnityConfigurationFile
UnityusestheSystem.Configurationnamespacesuppliedwiththe.NETframework.Thismeansthat configurationinformationcanbestoredinany.NETconfigurationfile,whichistypicallyyour App.configorWeb.configfile,butitcouldbestoredelsewhere.Thefollowingexampleisasimple XMLconfigurationfile. XML
<configuration> <configSections> <sectionname="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unityxmlns="http://schemas.microsoft.com/practices/2010/unity"> <aliasalias="ILogger"type="MyApp.ILogger,MyApp"/> <namespacename="MyApp.Implementations"/> <assemblyname="MyApp"/> <container> <registertype="ILogger"name="special"mapTo="SpecialLogger"/> </container> </unity> </configuration>

AUnityconfigurationsectionconsistsofasetoftypelookupmodifiers(aliases,namespaces,and assemblies),andoneormore<container>elements.A<container>elementhasasetof
32

<registration>elementsthatprovidetheconfigurationforthecontainer'stypes.Otherelements canalsobeusedinthecontainer,seeTheUnityConfigurationSchemaforafulldescriptionofthe schema. TheXMLnamespacespecifiedwiththexmlnsattributeintheexampleisnotrequiredatruntime. However,itisusefulbecauseVisualStudiousesittomatchthesectionwiththeUnityXMLschema andtoprovideIntelliSenseintheXMLeditor.

LoadingConfigurationFileInformationintoaContainer
AddingaUnityconfigurationsectiontoaconfigurationfileneithercreateanactualcontainernor configuresit.YoumustcreateaUnitycontainerinstance,readtheconfigurationfile,andloadthe configurationfileinformationintothecontainer. Alternatively,afteryoucreatethecontainer,youcanconfigureitprogrammaticallyatruntime withregistrations,typemappings,andanyextensions.Formoreinformationaboutruntime configuration,seeRunTimeConfiguration. Toloadtheconfigurationfileinformationintoacontainer,usetheLoadConfigurationextension methodonIUnityContainer.Thisinterpretsthedefaultconfigurationfileforyourapplication,seeks theUnityconfigurationsection,andconfiguresthecontainer.TheLoadConfigurationextension methodhasseveraloverloads. Unityoffersaconventionbasedapproachtoconfiguringyourcontainerthatcanbeappliedinmost cases.TotakeadvantageofthisyoumustusethedefaultUnityconfigurationsectionnameofunity andspecifyanunnamedcontainerinyourApp.configorWeb.configfile.Thefollowingexample usesthisapproach. C#
IUnityContainercontainer=newUnityContainer() .LoadConfiguration();

VisualBasic
DimcontainerasIUnityContainer=NewUnityContainer() container.LoadConfiguration()

Theconfigurationforanamedcontainercanbeloadedfromthedefaultconfigurationsectionby providingthenameofthecontainertotheLoadConfigurationmethodasshowninthefollowing example: C#


IUnityContainercontainer=newUnityContainer() .LoadConfiguration("otherContainerElement");

VisualBasic
DimcontainerasIUnityContainer=NewUnityContainer() container.LoadConfiguration("otherContainerElement")

33

Ifyourconfigurationisinadifferentsection(eitherwithadifferentnameorfromadifferentfile entirely),youmustfirstloadthesectionobjectthroughConfigurationManagerandthenpassthe sectiontotheLoadConfigurationmethod,asshowninthefollowingexample: C#


IUnityContainercontainer=newUnityContainer() .LoadConfiguration(section)//Loadsunnamed<container>element .LoadConfiguration(section,"otherContainerElement");//named<container> element

VisualBasic
DimcontainerasIUnityContainer=NewUnityContainer() container.LoadConfiguration(section)_ .LoadConfiguration(section,"otherContainerElement")

Youcanalsoloadmultipleconfigurationsintothesamecontainer.Nonconflictingconfigurations willsimplybeadded,andifthereisaconflict,suchastwomappingsforthesametype,thenthelast configurationaddedwillbetheonethatisused.Thepreviousexampleillustratestheadditive featureforconfiguration. ThereisalsoanAPIontheUnityConfigurationSectionobjectthatcanbeusedtoconfigurea container.OnceyouhaveobtainedthesectionobjectoftheConfigurationManager,youcancallits Configuremethodtoapplyconfigurationtoacontainer: C#


varsection= (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); IUnityContainercontainer=newUnityContainer(); section.Configure(container);//Unnamed<container>element section.Configure(container,"otherContainerElement");//namedcontainerelement

VisualBasic
Dimsection=DirectCast(Configurationmanager.GetSection("unity"), UnityConfigurationSection) DimcontainerasIUnityContainer=newUnityContainer() section.Configure(container) section.Configure(container,"otherContainerElement")

Ingeneral,theLoadConfigurationextensionmethodispreferredasitiseasiertoreadanduse.

LoadingtheConfigurationfromAlternativeFiles
Youarenotrequiredtostoreyourcontainerconfigurationinthestandardapplicationconfiguration file:App.configorWeb.config.However,ifyoudostoreyourconfigurationinadifferentfileyou mustusetheConfigurationManagermethodstoexplicitlyloadthatspecificnamedfile.
34

Ifyouuseacustomconfigurationfile,insteadofApp.configinanexecutableapplication,youmust ensurethatitisavailableintheruntimefolderofyourapplication.Ifyoucreateacustom configurationfileinaVisualStudioproject,openthePropertieswindowforthefileandsetthe CopytoOutputDirectorypropertytoCopyalways. Forexample,inordertoloadconfigurationinformationfromthenamedconfigurationfile, unity.config,youmustfirstloadthesection,inthiscaseUnityConfigurationSection,asshownin followingcode. SeeConfigurationManager.OpenMappedExeConfigurationonMSDNformoredetails. C#


usingSystem.Configuration; varfileMap=newExeConfigurationFileMap{ExeConfigFilename="unity.config"}; System.Configuration.Configurationconfiguration= ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); varunitySection=(UnityConfigurationSection)configuration.GetSection("unity"); varcontainer=newUnityContainer() .LoadConfiguration(unitySection);

VisualBasic
ImportsSystem.Configuration DimfileMapasnewExeConfigurationFileMap()With{.ExeConfigFilename= unity.config} DimconfigurationasSystem.Configuration.Configuration=_ ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None) DimunitySection=DirectCast(configuration.GetSection("unity"), UnityConfigurationSection) DimcontainerasIUnityContainer=newUnityContainer() container.LoadConfiguration(unitySection)

A<container>elementintheconfigurationfileisnotaninstanceofaUnityContainerobject.Itisa namedsetofconfigurationsthatcanbeappliedtoacontainerinstancelaterandasingle <container>elementcanbeappliedtomultipleUnityContainerinstances. Youcannotnestcontainersintheconfigurationfile.All<container>elementsresideatthesame levelwithinthe<containers>element.Youconfigurenestedcontainersbycreatingthecontainers intherequiredhierarchyinyourcodeandthenpopulatingthemfromtheappropriate<container> elements.Ifrequired,youcanloadmorethanonecontainerfromthesame<container>element, andyoucanusemorethanonecontainerelementinaconfigurationfile.Forinformation,see UsingContainerHierarchies.


35

SpecifyingTypesintheConfiguration File
ThistopicexplainshowtousetypesinUnityconfigurationfiles.AtthecoreofUnity'sfunctionality aretypesandhowyouspecifyandhandlethem.Youwillneedtospecifytypesmanytimesinthe typicalconfigurationfile.Theconfigurationfileshavetheirownsetofrulesforwritingtypenames rulesthatdifferfromthosefortypeswritteninC#orVisualBasic.Theserulesapplyeverywhereyou canspecifyatypeintheUnityconfigurationsection. Thistopiccontainsthefollowingsectionthatdescribehowyoucanspecifytypes: CLRTypeNames TypeAliases AutomaticTypeLookup DefaultAliasesandAssemblies GenericTypes

CLRTypeNames
YoucanspecifyatypenamebyusingtheCLRstandardtypenamesyntax,asshowninthefollowing example: <namespace>.<typename>,<assembly> Youcanuseeitherpartialassemblynamesorfullyqualifiedassemblynameswhichincludethe culture,version,andpublickeytoken.Thesenamesarestraightforwardforsimpletypes. Inordertospecifyanameforatypethatisintheglobalassemblycache,youmustusethefully qualifiedassemblynameforthetypetobecorrectlyloaded.Forexample,forSystem.String,atype inmscorlib,youcannotuseSystem.String,mscorlib.Youmustusethefullyqualifiedassembly name,System.String,mscorlib,Version=2.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089. CLRtypenamescanbeveryverbose,especiallywhenworkingwithgenerictypes.Forexample, comparethefollowingsimpledictionaryinC#orVisualBasicwiththeCLRexample: C#
Dictionary<string,int>

VisualBasic
Dictionary(OfString,Integer)

CLR

36

System.Collections.Generic.Dictionary`2[[System.String,mscorlib,2.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089],[System.Int32,mscorlib, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089]],mscorlib, Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089

Inordertoexpeditetheprocessandmaketypenameslesserrorprone,Unityconfiguration providestwooptionsyoucanuseintheconfigurationfile:aliasesandautomatictypelookup.

TypeAliases
Analiasissimplyashorthandnamethatwillbereplacedwiththefulltypenamewhenconfiguration isappliedtothecontainer.Youspecifyanaliasintheconfigurationfileinsidethesection,but outsideany<container>elements,asshowninthefollowingexample: XML
<unityxmlns="http://schemas.microsoft.com/practices/2010/unity"> <aliasalias="MyAlias"type="fulltypename"/> ... </unity>

Therearethefollowingrulesforusingaliases: Youcanhaveanarbitrarynumberof<alias>elementsintheconfigurationfile. Anywhereyoucangiveatypenameyoucanuseanaliasinstead. Therearenorecursivealiases,whichmeansthatyoucannotuseanaliastodefinethetypefor analias. Aliasnamesarecasesensitive:<aliasalias="int"/>and<aliasalias="Int"/>aretwodifferent aliasesandarenotinterchangeable. Aliasesonlyexistatconfigurationtime.Theyarenotavailableatruntime.

AutomaticTypeLookup
Inmanycases,likeforILoggerintheFormatoftheUnityConfigurationFileexample,thenameofa typeisallthatisrequired.ButgivenUnity'sdependenceontypesandthelargenumberoftypes typicallyinvolvedinaconfiguration,theabilitytoperformautomatictypelookupsfurtherexpedites theprocess.Byincorporatingautomatictypelookups,Unityalsoeliminatestheneedtodefinean aliasforeverytypeinanassembly,whichsaveseffortandservestoreducethechanceforerror fromrepeatedlytypingthenamespaceandassemblyname. TheUnityconfigurationsystemcansearchfortypes.However,itwillonlylookfortypesifthetype namespecifiedisnotafulltypenameanditisnotanalias.Youcanprovidetheconfiguration sectionwiththenamespacesandassembliestolookthroughbyusingthe<namespace>and <assembly>elements,asshowninthefollowingexample.
37

XML
<unityxmlns="http://schemas.microsoft.com/practices/2010/unity"> <namespacename="MyApp.Interfaces"/> <namespacename="System"/> <assemblyname="MyApp/> <assemblyname="mscorlib,2.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/> ... </unity>

Withtheconfigurationshowninthepreviousexample,whentheconfigurationsystemhitsaname itdoesnotrecognizeasatypenameoralias,itwillthensearchthroughtheassembliesand namespacesforamatch.So,tofindILogger,itwilltrytomatchthefollowingnamesinorder: 1. MyApp.Interfaces.ILogger,MyApp 2. System.ILogger,MyApp 3. MyApp.Interfaces.ILogger,mscorlib,2.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089 4. System.ILogger,mscorlib,2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089

Thesearchwillstopatthefirstmatchingtype. Thesystemusessimplestringconcatenationtocreatethetypenameitattemptstoload.However, youcannotspecifyanamespacequalifiednameplusthetype,MyApp.Interfaces.ILogger,MyApp,if youhaveanynamespaceelementsinyourconfigurationsection,<namespacename="System" />.Thenamespacefromtheconfigurationsectionwillbeappendedtothenamespace,resultingina searchonthewrongname,System.MyApp.Interfaces.ILogger.Youshouldputnamespacesinthe <namespace>elementsinsteadofonthetypenamesintheconfigurationfiletoavoidthis possibility. Ifyouhavealargenumberofassembliesandnamespaces,thenthesystemtypesearchcouldtakea significantamountoftimetocomplete.Normally,containersareonlyconfiguredatapplication startup,sothistimehitwillnotbesignificantduringtheoperationofyourapplication.Ifyoufindit becomesasignificantissue,thenyoushouldconsiderusinganexplicitaliasforthetypesthattake thegreatestsearchtimes,sincealiasesarematchedfirst. Whenmatchinganamewithatype,theconfigurationsystemperformsthefollowingstepsinorder. Thefirstonetosucceedstopstheprocess: 1. Attempttoloadatypeusingthenamedirectly(treatedasafulltypename) 2. Attempttomatchanametoanalias 3. Doautomatictypesearch

38

DefaultAliasesandAssemblies
SometypesandassembliesareusedfrequentlyinUnityconfigurationfiles.TheUnityconfiguration systemprovidesasetofpredefineddefaultaliasessoyoudonothavetoexplicitlyaddaliasesfor thesecommontypes.Anyuserdefinedentrieswilloverwritethedefaultones. Aliasesarecasesensitive. Inadditiontothedefaultaliases,theUnityconfigurationsystemalsoautomaticallyaddsSystemand mscorlibassembliestothelistofassembliesthataresearchedfortypes. ThefollowingtablehasthecompletelistofpredefinedtypealiasesprovidedbyUnity:
Default Alias sbyte short int integer long byte ushort uint ulong float single double decimal char bool object string datetime DateTime date singleton ContainerControlledLifetimeManager Type System.SByte System.Int16 System.Int32 System.Int32 System.Int64 System.Byte System.UInt16 System.UInt32 System.UInt64 System.Single System.Single System.Double System.Decimal System.Char System.Boolean System.Object System.String System.DateTime System.DateTime System.DateTime Microsoft.Practices.Unity.ContainerControlledLifetimeManager Microsoft.Practices.Unity.ContainerControlledLifetimeManager 39

transient TransientLifetimeManager perthread PerThreadLifetimeManager external ExternallyControlledLifetimeManager hierarchical HierarchicalLifetimeManager resolve perresolve PerResolveLifetimeManager

Microsoft.Practices.Unity.TransientLifetimeManager Microsoft.Practices.Unity.TransientLifetimeManager Microsoft.Practices.Unity.PerThreadLifetimeManager Microsoft.Practices.Unity.PerThreadLifetimeManager Microsoft.Practices.Unity.ExternallyControlledLifetimeManager Microsoft.Practices.Unity.ExternallyControlledLifetimeManager Microsoft.Practices.Unity.HierarchicalLifetimeManager Microsoft.Practices.Unity.HierarchicalLifetimeManager Microsoft.Practices.Unity.PerResolveLifetimeManager Microsoft.Practices.Unity.PerResolveLifetimeManager Microsoft.Practices.Unity.PerResolveLifetimeManager

GenericTypes
TheCLRtypenamesyntaxforgenerictypesisextremelyverbose,anditalsodoesnotallowfor thingslikealiases.TheUnityconfigurationsystemallowsforashorthandsyntaxforgenerictypes thatalsoallowsforaliasesandtypesearching. Tospecifyaclosedgenerictype,youprovidethetypenamefollowedbythetypeparametersina commaseparatedlistinsquarebrackets. TheUnityshorthandwouldlooklikethefollowingexample. XML
<container> <registertype="IDictionary[string,int]"</register> </container>

Ifyouwishtouseanassemblynamequalifiedtypeasatypeparameter,ratherthananaliasoran automaticallyfoundtype,youmustplacethatentirenameinsquarebrackets,asshowninthe followingexample: XML


<registertype="IDictionary[string,[MyApp.Interfaces.ILogger,MyApp]]"/>

Tospecifyanopengenerictypeyousimplyleaveoutthetypeparameters.Youhavetwooptions: UsetheCLRnotationof`NwhereNisthenumberofgenericparameters. Usethesquarebrackets,withcommas,toindicatethenumberofgenericparameters.


Generic Type Configuration file XML using CLR notation IList`1 IDictionary`2 Configuration file XML using comma notation IList[] IDictionary[,]

IList<T> IDictionary<K,V>

40

TheUnityConfigurationSchema
Unity2.0usesanewstreamlinedconfigurationschemaforconfiguringUnity. Thefollowingsectionsdescribetheschemaconfigurationelements,theirchildelements,andtheir attributesinmoredetail: The<unity>ConfigurationSection The<container>Element The<register>Element The<lifetime>Element The<constructor>Element The<property>Element The<method>Element The<param>Element The<dependency>Element The<value>Element The<optional>Element The<array>Element The<extension>Element The<instance>Element The<namespace>Element The<alias>Element The<sectionExtension>Element

The<unity>ConfigurationSection
Thetoplevelelementfortheconfigurationsectionisdefinedbythenamethatyouspecifyinthe <configSections>tagwhenaddingittotheconfigurationfile.Typically,theelementis<unity>,as showninthefollowingXMLexample.However,youcanchooseanothernameforthissection. XML
<configSections> <sectionname="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unityxmlns="http://schemas.microsoft.com/practices/2010/unity">
41

<aliasalias="ILogger"type="MyApp.ILogger,MyApp"/> <namespacename="MyApp.Implementations"/> <assemblyname="MyApp"/> <container> </container> </unity>

ThefollowingattributeistheonlyattributeavailablefortheUnitysection:
Attribute
Xmlns

Description
XML namespace for this section. Not required for the configuration file to work, but if you want XML IntelliSense support in Visual Studio, set this to http://schemas.microsoft.com/practices/2010/unity. This element is optional.

Thefollowingchildelementsareavailableforthe<unity>section:
Element
<alias> <namespace> <assembly> <sectionExtension>

Number
Many Many Many Many

Description
Creates a type alias. This element is optional. Adds a namespace to the namespace search list. This element is optional. Adds an assembly to the assembly search list. This element is optional. Adds a section extension, which adds new supported elements to the configuration schema. This element is optional. A set of container configurations. This element is optional.

<container>

Many

The<container>Element
The<container>elementcontainsasetofconfigurationsforaUnitycontainerinstance.Withinthat element,therecanbechildelementsdescribingtypemapping,injectionconfiguration,instance creation,containerextensions,orotheroptionsmadeavailablethroughanyaddedsection extensions.Thefollowingtableliststheattributeforthe<container>element.
Attribute
name

Description
Name of this container configuration. One container element in the section may omit the name attribute; all others must have unique names. The unnamed <container> element is considered the default, and is the one that will be loaded if a container name is omitted when calling container.LoadConfiguration. This attribute is optional. For more information see Loading Configuration File Information.

Thefollowingexampleshowstheusageofthe<container>element. XML
<unityxmlns="http://schemas.microsoft.com/practices/2010/unity"> <container><!defaultcontainer> contenthere...
42

</container> <containername="otherContainer"> ...contenthere... </container> </unity>

Thefollowingtableliststhechildelementsforthe<container>element.
Element
<register> <instance> <extension>

Number
Many Many Many

Description
Registration information for a type. This element is optional. Creates an instance directly in the container. This element is optional. Adds a container extension to the Unity container. This element is optional.

Formoreinformationseethefollowing: The<register>Element The<instance>Element The<extension>Element

The<register>Element
The<register>elementisthebasicbuildingblockforanyconfigurationfile.Itenablesyoutospecify typemappingsandinjectionconfigurationforatype.Ifyouspecifyaname,thatnameisusedfor thetypemapping.Ifyoudonotspecifyaname,itcreatesadefaultmappingforthespecifiedtypes. Youcanspecifyalifetimemanagerforeachmapping.Ifnoexplicitlifetimemanagerisconfigured foratype,itusesthetransientlifetimemanager. Thefollowingtableliststheattributesforthe<register>element.
Attribute type Description The type that is being registered. This is the type that will be requested when calling the Resolve method. This attribute is required. The name of the registration; if omitted the default registration for the type will be created. This attribute is optional. Type which will actually be created and returned when Resolve is called. This sets up a type mapping. It can be a user-defined alias or one of the default aliases. This attribute is optional.

name

mapTo

Thefollowingexampleshowsthecommonusageforthe<register>element. XML
<container> <registertype="MyService">...</register><!Defaultregistrationfortype MyService> <registertype="ILogger"mapTo="EventLogLogger"/><!typemapping> <registertype="ILogger"mapTo="PageAdminLogger"name="emergency"/><!named registration> </container>

43

Toregisteratypemappingatruntime,usetheRegisterTypemethod.Thefollowingexample registersEventLogLoggeratruntime. C#
//Registeradefault(unnamed)typemappingwithatransientlifetime //Specifytheregisteredtypeasaninterfaceorobjecttype //andthetargettypeyouwantreturnedforthattype myContainer.RegisterType<ILogger,EventLogLogger>();

VisualBasic
'Registeradefault(unnamed)typemappingwithatransientlifetime 'Specifytheregisteredtypeasaninterfaceorobjecttype 'andthetargettypeyouwantreturnedforthattype myContainer.RegisterType(OfILogger,EventLogLogger)()

FormoreinformationonregisteringatypeatruntimeseeRegisteringTypesandTypeMappings. Thefollowingtableliststhechildelementsforthe<register>element.Whenusinginterception configurationextension, Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtensio n,additionalelementsarevalidchildrenofa<register>element.Formoreinformationsee InterceptionConfigurationSchemaElements.


Element
<lifetime>

Number
One

Description
The type that manages instances created by the container. This element is optional. Configures the constructor to be called when creating instances. This element is optional. Configures properties that will be set when creating instances. This element is optional. Configures methods that will be called when creating instances. This element is optional.

<constructor>

One

<property>

Many

<method>

Many

Formoreinformationseethefollowing: The<lifetime>Element The<constructor>Element The<property>Element The<method>Element

The<lifetime>Element
The<lifetime>elementspecifieswhichlifetimemanagerwillbeusedtomanageinstancescreated foratype.Ifomitted,lifetimedefaultstotheTransientLifetimeManager.SeeUnderstanding LifetimeManagersfordetailsaboutlifetimemanagers.Thefollowingexampleshowsthecommon usageforthe<lifetime>element
44

XML
<registertype="ILogger"mapTo="SerialPortLogger"> <!Simpleuseoflifetimesingletoninstance> <lifetimetype="singleton"/> </register> <registertype="TypeWithCustomLifetime"> <!UseaLifetimemanagerinstancecreatedbyatypeconverter. Typeconvertergetspassedextrainformationprovidedin invalueattribute> <lifetimetype="SessionLifetimeManager" value="Session#1"typeConverter="SessionLifetimeConverter"/> </register>

Thefollowingtableliststheattributesforthe<lifetime>element.
Attribute type Description The type of the lifetime manager to create. Type must derive from LifetimeManager. Can be a user-defined alias or one of the default aliases. This attribute is required. The type of type converter to use when creating the lifetime manager. If given, the type converters ConvertFrom method will be called to create the lifetime manager, and pass the contents of the value attribute. If not specified, the default converter for the specified type is used. Aliases are allowed. This attribute is optional. Any value required to initialize the lifetime manager. This attribute is optional.

typeConverter

value

The<lifetime>elementhasnovalidchildelements.

The<constructor>Element
The<constructor>elementconfigurationfortheconstructorforthistypeandcontainsdetailsofthe constructorinjectionrequirementsforthisobjecttype.Theconstructorelementhasnoattributes. Youcanincludeonlyone<constructor>elementineachregistersection.Theexampleshowsthe commonusageforthe<constructor>element. XML
<registertype="ILogger"mapTo="SerialPortLogger"> <!Calltheconstructorwithoneparameternamed"port"> <constructor> <paramname="port"value="COM1:"/> </constructor> </register>

Thefollowingtableliststhechildelementforthe<constructor>element.
Element
<param>

Number
Many

Description
Specifies the parameters of the constructor to call. If no <param> child elements are present, it indicates that the zero-argument constructor should be called. This element is optional.

FormoreinformationseeThe<param>Element.

45

Youcanspecifyaconstructorfortheinjectionofaspecificnamedinstance.Inthefollowing example,InjectionConstructorindicateswhichconstructortousebasedonitsarguments,thestring "UI,"andcausestheTraceSourceLoggerconstructorwithasinglestringparametertobeinvoked. C#


container.RegisterType<ILogger,TraceSourceLogger>( "UI", newInjectionConstructor("UI")); container.RegisterType<DriveController>( newInjectionProperty("MyProperty")); container.RegisterType<DriveController>( newInjectionMethod("InitializeMe",42.0, newResolvedParameter(typeof(ILogger),"SpecialLogger")));

VisualBasic
container.RegisterType(OfILogger,TraceSourceLogger)_ ("UI",NewInjectionConstructor("UI")) container.RegisterType(OfDriveController)_ (NewInjectionProperty("MyProperty")) container.RegisterType(OfDriveController)_ (NewInjectionMethod(_ "InitializeMe",_ 42,_ NewResolvedParameter(GetType(ILogger),"SpecialLogger")))

FormoreinformationonusinginjectionatruntimeseeRegisteringInjectedParameterandProperty Values.

The<property>Element
The<property>elementconfiguresapropertyforinjection.Itcontainsdetailsoftheproperty injectionrequirementsforthisobjecttype.Youcanincludeoneormore<property>elementsin each<register>element.SeeSpecifyingValuesforInjectionfordetailsonhowtospecifywhatvalue toinjectfortheproperty.Noexplicitvaluemeanstoinjectthedefaultvalueforthetypeofthe property. XML
<registertype="ILogger"mapTo="SerialPortLogger"> <!Injecttheproperty"Settings"> <propertyname="Settings"/> </register>

Thefollowingtableliststheattributesforthe<property>element.
Attribute name dependencyName Description The name of the property. This attribute is required. If present, resolve the value of the property using this name rather than the default. This attribute is optional. 46

dependencyType

If present, indicates the type to resolve for the value of the property. If not given, the type of the property is the one resolved. This attribute is optional. Value to store in the property. This string is converted to the type of the property using the default TypeConverter for that type. This attribute is optional.

value

The<property>elementcantakeasinglechildelement,whichcanbeoneofthefollowing:
Element
<dependency>

Number
One

Description
Specifies how to resolve the value to store in the property. This element is optional. Specifies a literal value to be stored in the property. This element is optional. Specifies that an optional value should be resolved for the property. This element is optional. Configures injection of an array value for properties of array types. This element is optional.

<value> <optional>

One One

<array>

One

Forinformationaboutthechildelementsofthe<property>element,seethefollowing: The<dependency>Element The<value>Element The<optional>Element The<array>Element

The<method>Element
The<method>elementconfiguresamethodthatwillbecalledaspartofcreatinganinstance.It containsdetailsofthemethodinjectionrequirementsforthisobjecttype.Youcanincludeoneor more<method>elementsforeach<register>element. XML
<registertype="MyLogger"> <methodname="Initialize"> <paramname="loggerSettings"/> </method> </register>

Thefollowingtableliststheattributesforthe<method>element.
Attribute name Description The name of the method to call. This attribute is required.

47

The<method>elementcantakethefollowingchildelements.Thesecorrespondtotheparameters ofthemethodyouwanttospecify.
Element
<param>

Number
Many

Description
Specifies the parameters of the method to call. If no <param> child elements are present, it means that the method has no arguments This element is optional.

Formoreinformationseethe<param>element.

The<param>Element
The<param>elementspecifiesaparameterforconstructorormethodinjection.Itisusedto determinewhichconstructorormethodoverloadiscalled,basedonthenames(andoptionally types)oftheparametersfortheconstructorormethod. XML
<constructor> <paramname="param1"/> <paramname="param2"value="HelloWorld!"/> </constructor>

SeeSpecifyingValuesforInjectionformoreinformationabouthowthevaluesfortheparameters areprovided. Thefollowingtableliststheattributesforthe<param>element.


Attribute name type Description The name of the parameter. This attribute is required. The type of parameter. This attribute is only required if there are two different overloads with the same parameter name and you need to differentiate between them based on type. Normally, the parameter name alone is sufficient. This attribute is optional. Name to use to resolve dependencies. This attribute is optional. The type of dependency to resolve. This attribute is optional. Value to inject for this parameter. This attribute is optional.

dependencyName dependencyType value

The<param>elementcantakeoneofthefollowingchildelements.Onlyonechildelementis allowed.
Element
<dependency> <optional> <value> <array>

Number
One One One One

Description
Resolve value for parameter through the container. This element is optional. Resolve optional value through the container. This element is optional. Gives explicit value to use for parameter value. This element is optional. If parameter is of an array type, specifies what values to put into the resolved array. This element is optional.

Forinformationaboutthechildelementsofthe<param>element,seethefollowing:
48

The<value>Element The<dependency>Element The<optional>Element The<array>Element

Valueelementsareaschemaextensionpoint,sootherchildelementsmaybealloweddepending onwhichschemaextensionsareavailable.SeeExtendingtheUnityConfigurationSchema.

The<dependency>Element
The<dependency>elementisusedwhenavalueistoberesolvedthroughthecontainer.By default,withnootherconfiguration,thiselementresultsinacallbackintothecontainerforthe defaultvalueofthetypeofthecontainingparameterorproperty.Attributesmaybeusedto customizewhatisresolved.Ifthevaluecannotberesolved,thenanexceptionisthrownatresolve time.Thefollowingexampleshowsthecommonusageforthe<dependency>element. XML
<constructor> <paramname="param1"> <dependencyname="otherRegistration"/> </param> </constructor>

Thefollowingtableliststheattributesforthe<dependency>element.
Attribute name Description The name of the named type or mapping registered in the container to use to resolve this dependency. If omitted, the default registration will be resolved. This attribute is optional. Type to resolve from the container. It must be a type compatible with the type of the parameter or property. If omitted, Unity resolves the type based on the type of the parent parameter or property. This attribute is optional.

type

The<dependency>elementhasnovalidchildelements.

The<value>Element
The<value>elementisusedtospecifyaspecificvalueforaparameterorproperty.Thiselement letsyouspecifyastringthatisthenpassedthroughaTypeConvertertocreatetheactualobjectto beinjected.Ifnospecifictypeconvertertypeisgiven,thenthedefaulttypeconverterforthetype ofparameterorpropertyisused. Thestringisconvertedtoanobjectusingtheinvariantculture;ifyouwishtousealocalespecific cultureyoumustprovideacustomTypeConvertertodoso. Thefollowingtableliststheattributesforthe<value>element.
Attribute Description 49

value typeConverter

The string value to be converted to an object. This attribute is required. Type of the TypeConverter to use to convert the value to an object. If omitted, the default type converter for the containing parameter or property type will be used. This attribute is optional.

Thefollowingexampleshowsthecommonusageofthe<value>element. XML
<constructor> <paramname="param1"> <valuevalue="42"/> </param> <paramname="param2"> <valuevalue="aieou"typeConverter="VowelTypeConverter"/> </param> </constructor>

The<value>elementhasnovalidchildelements.

The<optional>Element
The<optional>elementisusedwhenavalueshouldberesolvedthroughthecontainerbutits presenceisoptional.Thecontainerwilltrytoresolvethisparameterorpropertyusingthetypesand mappingsregisteredinthecontainer,butiftheresolutionfails,thecontainerreturnsnullinsteadof throwinganexception. Thefollowingtableliststheattributesforthe<optional>element.
Attribute name Description The name of the named type or mapping registered in the container to use to resolve this optional dependency. If omitted the default registration will be resolved. This attribute is optional. The type to use to resolve an optional dependency mapping or registration. Must be a type compatible with the type of the parameter or property. If you do not specify a type, Unity will resolve the type of the parameter or property. This attribute is optional.

type

XML
<constructor> <paramname="param1"> <optionalname="otherRegistration"/> </param> </constructor>

The<optional>elementhasnovalidchildelements.

50

The<array>Element
The<array>elementcanbeusedtocustomizewhichelementsarereturnedinthearrayifa parameterorpropertyisofanarraytype.SeeSpecifyingValuesforInjectionformoredetails. The<array>elementtakesnoattributes. The<array>elementhasacollectionofzeroormorechildelements.Iftherearenochildelements, anempty,zerolengtharrayforbothgenericandnongenerictypesisinjected.Ifthereismorethan onechild,anyvalueelementsuchas<dependency>,<optional>,or<value>maybeused,andeach onecorrespondstoanelementinthereturnedarray. Ifyouwanttohavethedefaultcontainerbehaviorforarrays,donotspecifythe<array>element; usethe<dependency>elementinstead. Thefollowingexampleshowsthecommonusageofthe<array>element. XML
<registertype="ILogger"mapTo="NetworkLogger"> <!Emptyarray> <propertyname="noSettings"> <array/> </property> <!TypeNetworkSettings[],getdefaultarrayinjection> <propertyname="allSettings"/> <!TypeNetworkSettings[],getonlythespecifiedthreevalues> <propertyname="someSettings"> <array> <dependencyname="fastSettings"/> <optionalname="turboSettings"/> <valuevalue="port=1234;protocol=tcp;timeout=60 typeConverter="ConnectionSettingsTypeConverter"/> </array> </property> </register>

The<extension>Element
The<extension>elementisusedtoaddaUnitycontainerextensiontoacontainerandcontainsthe listofextensionstoregisterwiththeUnitycontainer. Thefollowingexampleshowsthecommonusageforthe<extension>element. XML
<container> <extension type="Microsoft.Practices.Unity.Interception.InterceptionExtension, Microsoft.Practices.Unity.Interception"/> </container>
51

Thefollowingexampleaddsanextensionatruntime.Thiscodecreatesanewinstanceofan extensionclassnamedMyCustomExtensionthatyouhavepreviouslycreated,andwhichresidesin thisorareferencedproject,andaddsittothecontainer. C#


IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<MyCustomExtension>();

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfMyCustomExtension)()

FormoreinformationonaddingextensionsatruntimeseeRegisteringContainerExtensions. Thefollowingtabledescribesthesingleattributeforthe<extension>element.
Attribute type Description The type of extension to add to the container. Can be a user-defined alias or one of the default aliases. This attribute is required.

Therearenochildelementsforthe<extension>element.

The<instance>Element
The<instance>elementisusedtospecifyavaluetobeplacedinthecontainerandtoindicatethat youdonotwantthatvaluetobecreatedbythecontainerbutthatitwillbecreatedbyusinga TypeConverterandthenplacedinthecontainerbyusingtheRegisterInstancemethod. Instancesaddedthroughconfigurationtendtobesimplebecauseitishardtorepresentthemwitha stringvalue,buttheycouldbearbitrarilycomplexifthereisatypeconverterthatcanhandlethe conversionfromastring. Youcannotuseanexistinginstancewiththe<instance>element.The<instance>sectionresultsin thecreationofanewinstance,muchlikesomethingregisteredwithRegisterTypewould.Thisisin contrasttotheuseofRegisterInstance,whichrequirestheusertocreatetheinstancemanually andthenregisterit. Thefollowingtableliststheattributesforthe<instance>element.
Attribute name type Description The name to use when registering this instance. This attribute is optional. The type of the value. Can be a user-defined alias or one of the default aliases. If omitted, the assumed type is System.String. This attribute is optional. The value to pass to the type converter to create the object. If omitted, null is passed to the type converter. This attribute is optional. 52

value

typeConverter

The type converter to use to construct the value. If not specified, the default converter for the type of the value is used. This attribute is optional.

Thefollowingexampleshowshowthe<instance>elementisusedinaconfigurationfile. XML
<container> <!Anamedstringvalue> <instancename="NorthwindDb"value="SqlConnectionStringHere"/> <!Atypedvalue> <instancetype="ConnectionSettings"value="port=1234" typeConverter="ConnectionSettingsTypeConverter"/> </container>

Thefollowingexampleshowshowyoucanregisterinstancesatruntime.Thefollowingexample createsadefault(unnamed)registrationforanobjectoftypeEmailServicethatimplementsthe IMyServiceinterface. C#


EmailServicemyEmailService=newEmailService(); myContainer.RegisterInstance<IMyService>(myEmailService);

VisualBasic
DimmyEmailServiceAsNewEmailService() myContainer.RegisterInstance(OfIMyService)(myEmailService)

The<instance>elementhasnochildelements.

The<namespace>Element
The<namespace>elementisusedtodeclarenamespacesthatwillbeautomaticallysearchedfor types,asexplainedinthesectionSpecifyingTypesintheConfigurationFile. Thefollowingtableliststheattributeforthe<namespace>element.
Attribute name Description The name of the namespace that is to be searched for the types. This attribute is required.

Thefollowingexampleshowshowthe<namespace>elementisused. XML
<namespacename="ObjectsInstancesExamples.MyTypes"/>

SeeSpecifyingTypesintheConfigurationFileformoreexamples. The<namespace>elementhasnoallowedchildelements.

53

The<assembly>Element
The<assembly>elementisusedtodeclareassembliesthatUnitywillautomaticallysearchfortypes, asdescribedinthesectionSpecifyingTypesintheConfigurationFile. Thefollowingtableliststheattributeforthe<assembly>element.
Attribute name Description The name of the assembly to search. The assembly name must be sufficiently qualified for the common language runtime (CLR) to load it. Assemblies in the GAC, for instance, must have a fully-qualified assembly name. This attribute is required.

Thefollowingexampleshowshowthe<assembly>elementisused.SeeSpecifyingTypesinthe ConfigurationFileformoreexamples. XML


<assemblyname="ObjectsInstancesExamples"/>

SeetheAutomaticTypeLookupsectionforthesearchrulesformatches. The<assembly>elementhasnoallowedchildelements.

The<alias>Element
The<alias>elementisusedtodefineatypealias,asexplainedinthesectionSpecifyingTypesinthe ConfigurationFile. Thefollowingtableliststheattributesforthe<alias>element.
Attribute alias type Description The alias used to refer to the specified type. This attribute is required. The type that the alias refers to. This name must be a CLR type name. Aliases or automatic type lookups do not apply with this attribute. This attribute is required.

Thefollowingexampleshowshowthe<alias>elementisused. XML
<unity> <aliasalias="MyLogger"type="MyNamespace.MyLogger,MyProject"/> <aliasalias="AGenericType"type="MyNamespace.MyGenericType`1,MyProject"/> </unity>

The<alias>elementhasnovalidchildelements.

54

The<sectionExtension>Element
The<sectionExtension>elementisusedtoloadaschemaextension.Unlikethe<extension> element,whichisusedtoloadacontainerextensionobjecttomodifytheruntimebehaviorofa Unitycontainerinstance,thiselementloadsaschemaextension,whichmodifiestheallowed elementsintheconfigurationfileitself.Thisisasectionlevelelement;itmustoccuroutsideany <container>elements. SeeExtendingtheUnityConfigurationSchemaformoredetails. Thefollowingtabledescribestheattributesforthe<sectionExtension>element.
Attribute type prefix Description The type that implements the section extension. This attribute is required. Specifies a prefix that will be appended to all the extension elements. This allows you to avoid collisions if two different extensions add an element with the same name. If left out, no prefix will be added. This attribute is optional.

XML
<unity> <sectionExtensiontype="MyProject.MySectionExtension,MyProject"/> <sectionExtensionprefix="ext"type="MyOtherSectionExtension"/> ... </unity>

The<sectionExtension>elementhasnoallowedchildelements.

SpecifyingValuesforInjection
ThistopicexplainshowtoconfiguretheinformationrequiredsothatUnitywillautomatically populateconstructorandmethodparametersandpropertyvalueswhenitresolvesinstancesof types.The<param>and<property>elementsbothletyouspecifyavaluetobesuppliedforthe parameterorproperty,respectively.Therearemanydifferentkindsofvaluesthatcanbespecified, eachwithaseparateelement.Inaddition,theUnityconfigurationschemasupportsashorthand notationforthemostcommoncases. FormoreinformationabouttheformatoftheUnityconfigurationfile,seeUsingDesignTime Configuration. Thistopiccontainsthefollowingsectionsdescribingvaluesforinjection: ResolvingValuesfromtheContainer GivingValuesinConfiguration ConfiguringArrayValues
55

ResolvingValuesfromtheContainer
Probablythemostcommonuseisthecasewhenyouwantthevalueforaparameterorpropertyto beresolvedfromthecontainer.Youcanusethe<dependency>elementtoaccomplishthis.The typeofthedependencytoresolveis,bydefault,thetypeoftheparameterorpropertybeing injected.Ifyouwanttouseadifferenttype,thenyoumustspecifythetypeattributeonthe <dependency>element.Also,thecontainerwillresolvethedefaultvalueforthattypeunlessyou usethenameattributetospecifyanamedregistrationtoresolve. Thereareseveralshorthandattributestoexpeditetheconfigurationprocess.Ifyouwanttoresolve thedefaultregistrationforthetypeoftheparameterorproperty,youcansimplyleaveoutthe <dependency>element,asshowninthefollowingexample. XML
<registertype="ILogger"mapTo="SerialPortLogger"> <propertyname="Settings"/> </register>

Similarly,sincespecifyingadependencyissocommon,insteadofusingthechild<dependency> element,youcanusethedependencyTypeanddependencyNameattributesonthecontaining elements.Thefollowingexampleusesthe<dependency>element. XML


<!Explicitdependencyelement> <registertype="ILogger"mapTo="SerialPortLogger"> <propertyname="Settings"> <dependencytype="SpecialPortSettings"name="highSpeedSettings"/> </property> </register>

Thefollowingexampleusesattributesinsteadofthe<dependency>elementtoaccomplishthe sameconfiguration. XML


<!Useattributesinsteadofthedependencyelement> <registertype="ILogger"mapTo="SerialPortLogger"> <propertyname="Settings"dependencyType="SpecialPortSettings dependencyName="highSpeedSettings"/> </register>

Thepreviousexamplesusethe<property>element,buttheattributescanalsobeusedonthe <param>elementinexactlythesameway. Optionalvalues,specifiedbyusingthe<optional>element,areresolvedfromthecontainer.Ifthe containercannotresolveanoptionalvalue,forexamplewhenattemptingtoresolveaninterface thatisnotregistered,theninsteadofgettinganexception,asyouwouldforanormaldependency, yougetnullinjected.Therearenoshorthandattributesforoptionaldependencies;youmustuse theexplicitchildelement.


56

GivingValuesinConfiguration
Theothermostcommonscenarioistospecifyaparticularvaluetobeinjected,suchasastringor integer.Theexplicitwaytodoisbyusingthe<value>element.Thisletsyouspecifyastring,which willbepassedtoaTypeConvertertocreatetheunderlyingobject.Thetypeofthevalueisthetype oftheenclosingpropertyorparameter. Likethe<dependency>element,the<value>elementhasshorthandattributes.Ifyouonlyneedthe defaulttypeconvertertoturnthestringintoavalue,whichiscommonlythecaseformostvalue typeslikestringsandnumbers,youcansimplyusethevalueattributeonyourenclosingparameter orproperty,asshowninthefollowingexample. XML
<registertype="ILogger"mapTo="NetworkLogger"> <constructor> <!Explicitvaluechildelement> <paramname="logHost"> <valuevalue="loghost.example.org"/> </param> <!usingshorthandattribute> <paramname="header"value="LogEntry:"/> <!customtypeconverter,noshorthandavailable> <paramname="connectionSettings"> <valuevalue="port=123;protocol=tcp;timeout=30" typeConverter="ConnectionSettingsTypeConverter"/> </param> </constructor> </register>

ConfiguringArrayValues
Thecontainerhandlesparameterorpropertiesofarraytypesuniquely.Thereareseveraloptionsfor howtoconfigurearrayvalues;thechoicedependsonwhatyouwanttoaccomplish.SeeRegistering InjectedParameterandPropertyValues. Thesimplestapproachforarraysisthedefaultbehaviorofthecontainerforarrays.Inthatcase simplyusethe<dependency>childelementor,fortheequivalentshorthandattribute,justleave theattributeout. Ifyouwishtohaveonlyexplicitvaluesinjectedintothearray,thenyoucanusethe<array>element withchildelements.Thiselementletsyouspecifyexplicitlywhatvaluesyouwanttohaveinjected. Ifyouwantanemptyarray,use<array>withnochildelements.Ifyouwantanarraywithvalues, includeaschildrenasetofothervalueelements,suchas<dependency>,<optional>,or<value>to givethevaluesforthevariousarrayelements.Forexample: XML
<registertype="ILogger"mapTo="NetworkLogger">
57

<!Emptyarray> <propertyname="noSettings"> <array/> </property> <!TypeNetworkSettings[],getdefaultarrayinjection> <propertyname="allSettings"/> <!TypeNetworkSettings[],getonlythespecifiedthreevalues> <propertyname="someSettings"> <array> <dependencyname="fastSettings"/> <optionalname="turboSettings"/> <valuevalue="port=1234;protocol=tcp;timeout=60" typeConverter="ConnectionSettingsTypeConverter"/> </array> </property> </register>

ExtendingtheUnityConfiguration Schema
TheUnitycontainerishighlycustomizable.Noonefixedconfigurationformatcancovereverything thatyoumightwanttodowiththecontainer.Asaresult,theUnityconfigurationsystemitselfis extensible,allowingyoutoaddnewvalidelementstoyourconfigurationfile.The <sectionExtension>elementallowsyoutoloadthecodethataddsthesenewoptionstothe configurationfile.ThisletsyouspecifyanimplementationoftheSectionExtensiontype. Sectionextensionscandothefollowingtotheconfiguration: Addnewpredefinedaliases Addnewcontainerlevelelements Addnewregistrationlevelelements Addnewvaluelevelelements Youcancreateyourowncustomextensions,oruseextensionscreatedbythirdparties,withUnity. Unityalsousesdefaultextensionstoimplementitsownfunctionality.Forinformationaboutusing extensions,seeCreatingandUsingContainerExtensions. OneexampleofasectionextensionistheInterceptionConfigurationExtensionsectionextension, whichshipswiththeUnitypackage.Thissectionextensionaddsthefollowingelementsandaliases totheschema:

58

Aliasesaredefinedforeachofthetypes(likeVirtualMethodInterceptor, TransparentProxyInterceptor,andvariousmatchingrules)thatareusedbytheinterception configuration. The<interception>elementisaddedasavalidelementchildelementforthe<container> element. The<interceptor>,<interceptionBehavior>,<addInterface>,and<policyInjection>elements areaddedasvalidchildelementsforthe<register>element. Thisextensionmechanismallowsforalmostunlimitedextensibilityoftheconfigurationfileonan optinbasis.Thoughtheschemaextensionwillmodifytheschemaallowedatruntime,itdoesnot modifytheXSDfileusedbyVisualStudioIntelliSense.Asaresult,youwillstillgetwarningsinthe VisualStudioXMLeditoreventhoughthefilewillworkfineatruntime.Inordertoresolvethis problem,thesectionextensionauthormustprovideanupdatedXSDdocumentforusewiththeir extension. TheInterceptionConfigurationExtensionissupportedbytheschemashippedwithUnity. The<sectionExtension>elementalsoacceptsauserprovidedprefixattribute.Thisisusefulinthe casewheretwosectionextensionsbothprovideextensionelementswiththesamename.Inthe caseofacollision,youcanspecifyaprefixforoneorbothsectionextensions,andthenusethat prefixtodisambiguatethem. Considertwoschemaextensions,bothofwhichadda<containerCustomization>element.Using theprefixattribute,aconfigurationfilethatusesbothwouldlooklikethefollowingexample. XML
<unity> <sectionExtensionprefix="ext1"type="MyFirstExtension,MyStuff"/> <sectionExtensionprefix="ext2"type="MySecondExtension,MyOtherStuff"/> <container> <ext1.containerCustomization/> <ext2.containerCustomization/> </container> </unity>

ConfigurationFilesforInterception
Unity2.0treatsinterceptionlikeanyextensionyouaddtoUnity.AswithanyextensioninUnity2.0, theUnityinterceptionmechanismcanbeconfiguredthrougheithertheAPIorthroughaUnity configurationsection. Unityprovidespartialbackwardcompatibilityforimplementinginterceptionthroughacontainer. EarlierversionsusedacontainerextensionnamedInterceptionExtension,whichresidesinthe assemblynamedMicrosoft.Practices.Unity.Interception.dll.Toconfigureinterception,youspecify
59

thisextensioninthe<extensions>elementofyourapplicationconfiguration,andthendefinethe behaviorofinterceptioninthe<extensionConfig>section. UsingtheextensionandregisterelementsinUnity2.0iscomparabletoInterceptorelementuse intheextensionConfigsectioninearlierversions. Formoreinformationonbackwardcompatibility,seeReusingConfigurationFilesBasedona PreviousSchema. FormoreinformationaboutUnity1.2interception,seeUsingInterceptionwithUnityonMSDN. Thistopiccontainsthefollowingsectionstodescribetheinterceptionconfigurationfile: UsingtheConfigurationFiletoEnableInterception StandardInterceptionAliases EnablingInterceptionofaType ConfiguringPolicyInjectionPolicies LegacyInterceptionConfiguration InterceptionConfigurationSchemaElements RegisteringInterceptionatRunTime

UsingtheConfigurationFiletoEnableInterception
InterceptionisnotpartofthedefaultUnityconfigurationschema.Beforeyoucanconfigure interceptionyoumustaddthecorrect<sectionExtension>elementtoyourconfigurationsectionin theconfigurationfile.Theinterceptionconfigurationextensionisthetype Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtensio n,intheMicrosoft.Practices.Unity.Interception.Configurationassembly. Thefollowingextractfromaconfigurationfileaddstheinterceptionextension, InterceptionConfigurationExtension,byusingthe<sectionExtension>element. XML
<unityxmlns="http://schemas.microsoft.com/practices/2010/unity"> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionC onfigurationExtension,Microsoft.Practices.Unity.Interception.Configuration"/> </unity>

LoadingtheinterceptionsectionextensionsuppliesasetofStandardInterceptionAliasesand additionalconfigurationelements. Loadingthesectionextensiononlyenablestheinterceptionconfigurationtobegiveninthe configurationfile.Interceptionitselfwillnotworkunlessyoualsoloadtheinterceptioncontainer

60

extensioninyourUnitycontainerinstance.Thiscanalsobedoneintheconfigurationfile,asshown inthefollowingexample. XML


<unityxmlns="http://schemas.microsoft.com/practices/2010/unity"> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionC onfigurationExtension,Microsoft.Practices.Unity.Interception.Configuration"/> <container> <extensiontype="Interception"/> </container> </unity>

Youdonotneedtoexplicitlyaliastheinterceptioncontainerextensionstypeoradda <namespace>or<assembly>element.WhenyouaddtheInterceptionConfigurationExtensionto the<sectionExtension>element,thealias"Interception"isautomaticallyadded,alongwiththe otherdefaultaliasesforcommontypesusedininterceptionconfiguration.

StandardInterceptionAliases
ThefollowingtablecontainsthelistofpredefinedtypealiasesprovidedbytheUnityinterception extension.AllofthesetypesareintheMicrosoft.Practices.Unity.Interception.dllassemblyandthe Microsoft.Practices.Unity.InterceptionExtensionnamespace.
Alias Description

Interception IInterceptionBehavior PolicyInjectionBehavior Policy Injection Types IMatchingRule ICallHandler Policy Injection Matching Rules AssemblyMatchingRule CustomAttributeMatchingRule MemberNameMatchingRule ParameterTypeMatchingRule PropertyMatchingRule TagAttributeMatchingRule TypeMatchingRule Interceptor Types

The interception container extension. Interface for interception behaviors. Behavior implementing policy injection. Policy injection types. The matching rule interface. The policy injection call handler interface. Policy injection matching rules. Match based on being in a particular assembly. Match based on having a given attribute. Match based on member name. Match based on parameter types. Match based on a property name. Match based on having the Tag attribute. Match based on type. Interceptor type.
61

VirtualMethodInterceptor InterfaceInterceptor TransparentProxyInterceptor

Virtual method type interceptor. Interface interceptor. Transparent proxy interceptor.

EnablingInterceptiononaType
Toturnoninterceptionforatypeinthecontainer,youspecifytheinterceptorandbehaviorsusing thefollowingchildelementsofthe<register>element. <interceptor> <interceptionBehavior> <policyInjection> <addInterface>

Thefollowingexampleturnsoninterceptionusingthetransparentproxyinterceptorandperforms policyinjection. XML


<unityxmlns="http://schemas.microsoft.com/practices/2010/unity"> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionC onfigurationExtension,Microsoft.Practices.Unity.Interception.Configuration"/> <container> <extensiontype="Interception"/> <registertype="MyType"> <!Otherchildren,likeconstructororproperty> <interceptortype="TransparentProxyInterceptor"/> <policyInjection/> </register> </container> </unity>

Afterloadingthisconfiguration,anyobjectsoftypeMyTypewillbeinterceptedbyusingthe transparentproxyinterceptorandtheywillhavethepolicyinjectionbehaviorappliedtothem.

ConfiguringPolicyInjectionPolicies
PolicyinjectionpolicescanalsobeconfiguredthroughtheUnityconfigurationsection.Thissection describeshowtoperformtheconfigurationalongwithseveraloptionsyoucanusewhendefining policies. Policiesaredefinedonapercontainerbasisinsidean<interception>element.Thefollowing exampledefinestwopolicies,withmatchingrulesandacallhandlerapplied.
62

XML
<unityxmlns="http://schemas.microsoft.com/practices/2010/unity"> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionC onfigurationExtension,Microsoft.Practices.Unity.Interception.Configuration"/> <container> <extensiontype="Interception"/> <interception> <policyname="addDataAccessTypes"> <matchingRulename="DataLayerMatch"type="NamespaceMatchingRule"> <constructor> <paramname="namespaceName"value="MyApp.DataAccess"/> </constructor> </matchingRule> <callHandlername="LogHandler"type="LoggingCallHandler"/> <callHandlername="SecurityHandler" type="DatabaseSecurityCheckHandler"/> </policy> <policyname="webMethods"> <matchingRulename="MatchWebRequestMethods"/> <callHandlername="LogWebMethodHandler"type="LoggingCallHandler"/> </policy> </interception> <registertype="IMatchingRule"name="MatchWebRequestMethods" mapTo="MemberNameMatchingRule"> <constructor> <paramname="nameToMatch"value="Begin*Request"/> </constructor> </register> </container> </unity>

Thisexampledemonstratesthetwomostcommonapproachesfordefiningmatchingrulesandcall handlersinaconfigurationfile.Thefirstapproach,theinlinestyle,declaresthetypeandinjection membersdirectlywithinthepolicydefinition.Thisiswhatwasusedinthefirstmatchingrule declaration,asshowninthefollowingextractfromthepreviousexample. XML


... <matchingRulename="DataLayerMatch"type="NamespaceMatchingRule"> <constructor> <paramname="namespaceName"value="MyApp.DataAccess"/> </constructor> </matchingRule> ...

Thisapproachisdesignedtoworkmuchlikea<register>element.Theonlydifferenceisthatyou cannotprovideatypemapping.TheunderlyingtypegiventothecontainerisalwaysIMatchingRule.
63

Anyvalidchildelementforthe<register>elementcanbeusedwiththe<matchingRule>element (including<lifetime>,<constructor>,and<property>elements).Inthisexample,theactual matchingruletypeisNamespaceMatchingRule,andwhenthematchingruleobjectmustbe created,itiscreatedbycallingtheconstructorthattakesasinglestringparameternamed namespaceName.ThevalueforthatwillbeMyApp.DataAccess.Theintentofthismatchingrule configurationistomatchallmethodsonthetypesinthatnamespace. Thesamedesignappliestothe<callHandler>element,exceptthatyouaredefininginjectionfora callhandler(atypethatimplementsICallHandler)insteadofamatchingrule. Thesecondmostcommonapproachistouseanamedreference,asinthefollowingexamplewith theMatchWebRequestMethodsnamedreference. XML
... <matchingRulename="MatchWebRequestMethods"/> ... <registertype="IMatchingRule"name="MatchWebRequestMethods" mapTo="MemberNameMatchingRule"> <constructor> <paramname="nameToMatch"value="Begin*Request"/> </constructor> </register> ...

Inthisapproach,atypeofmatchingruleisnotspecified.Instead,anameisprovided.At configurationtime,thecontainerwillattempttoresolveanIMatchingRulewiththename MatchWebRequestMethodsthatyouspecified.Theresultisthatthecontainerwilllookfora registrationforthetypeICallHandlerwiththenameMatchWebRequestMethods.Thatregistration isdefinedafewlineslowerinthepreviousexamplefile,whichworksbecausetheorderofdefinition inthefiledoesnotmatter.Thesamedesignappliestothe<callHandler>element. Thenameisalwaysrequiredbytheconfigurationsystem.However,whenusinganinlinestyle registration,thenameisignoredinthecontainer. Theapproachyouchoosetouseisamatterofpersonalpreference.Thefollowingarefactorsto considerwhenchoosinganapproachtouseforpolicies,matchingrules,andcallhandlersinyour configurationfile: Ifyourpoliciesarefairlysmallandinitializationofthematchingrulesandcallhandlersis straightforward,theinlinestylewillbethesimplestapproach.Everythingrelatedtoyour policiesistheninoneplace. Ifyouwanttoreuseacallhandlerdefinitionormatchingruleacrosspolicies,anamed referencewillfacilitatethisapproach.Usinganamedreferenceletsyoudefinethe configurationforthecallhandlerormatchingruleinasingleplaceandsimplyreferenceit fromthepolicies.Choosingthenametodescribewhatthematchingruleorcallhandlers purposeismakesiteasiertotrackthem;forexample,MatchWebRequestMethodsisclearly formatchingmethodsthatdoWebrequests.

64

Ifyouhavealargenumberofpoliciesormanymatchingrulesandcallhandlers,usingnamed referenceswillfacilitateyourwork.Usingtheinlinestylecanquicklybloatyourpolicy definitions,makingithardtotellwhatthepoliciesareandwhichonesaregroupedtogether. Formoreinformationonregisteringinterceptionatruntime,seeRegisteringInterception. Formoreinformationonregisteringpolicies,matchingRules,andcallHandlersatruntimesee RegisteringPolicyInjectionComponents.

LegacyInterceptionConfiguration
InearlierversionsofUnity,enablinginterceptiononatypewasdoneusingaseparateelement entirely.Unity2.0supportsthisapproachaswell,inordertoallowsomereuseofother configurationfiles.Thesyntaxisnotidentical,soyouwillstillneedtocopyandupdateyour configurationfile;youcannotuseanolderUnityconfigurationfiledirectly.Fornewdevelopment, configuringinterceptionthroughthe<register>elementasexplainedaboveistherecommended approach. The<interceptors>elementcanappearwithina<container>element,andyoucanthenspecifya seriesofinterceptorsandthetypestheyshouldintercept. XML
<container> <extensiontype="Interception"/> <interceptors> <interceptortype="VirtualMethodInterceptor"> <defaulttype="wrappableVirtual"/> </interceptor> <interceptortype="TransparentProxyInterceptor"> <keytype="wrappable"/> </interceptor> <interceptortype="TransparentProxyInterceptor"> <keytype="wrappable"name="name"/> </interceptor> </interceptors> </container>

The<interceptor>elementletsyouspecifyasingleinterceptortype.Youcanusethechildelements of<interceptor>tospecifythetypethatthisinterceptorshouldbeappliedto.See<the<default> Elementandthe<key>Elementformoreinformation. Whendefininginterceptionthroughthe<interceptors>element,policyinjectionisautomatically enabledforthetypesapplied,andyoucannotaddanyadditionalinterceptionbehaviors. Formoreinformationonbackwardcompatibility,seeReusingConfigurationFilesBasedona PreviousSchema. FormoreinformationaboutUnity1.2interception,seeUsingInterceptionwithUnityonMSDN.

65

InterceptionConfigurationSchema Elements
Whenconfiguringfilesforinterception,thefollowingelementsmayappearaschildrenofa <register>element.FormoreinformationseeTheregisterElement.Theseelementsareusedto describethe<interceptors>and<policies>elements,theirchildelements,andtheirattributesin moredetail: The<interceptor>Element The<interceptionBehavior>Element The<addInterface>Element The<interception>Element The<policy>Element The<matchingRule>Element The<callHandler>Element The<interceptors>Element Theinterceptors<interceptor>Element The<default>Element The<key>Element

Formoreinformationaboutinterception,andselectingtheobjectsandtheirmemberstoadda handlerpipeline,seeUsingInterceptionandPolicyInjection.

The<interceptor>Element
Theinterceptorelementspecifiesatypethatshouldbeinterceptedandprovidesthetypeof interceptortouse. The<interceptor>elementisavalidchildofthe<register>element. Thefollowingtableliststheattributesfortheinterceptorelement.
Attribute name Description The name to use when registering this interceptor. This attribute is required only when there are two or more entries for the same interceptor type. The type of the interceptor. This attribute is required. Default is false. If true, then this interceptor will be used for all registrations for this type, ignoring the name that the registration is under. This flag is useful if you are registering many implementations of the same interface with different names, and want all of them 66

type isDefaultForType

intercepted. Setting this to "true" lets you define interception once instead of in every registration. This attribute is optional.

Therearenovalidchildelementsforthe<interceptor>element.

The<interceptionBehavior>Element
This<interceptionBehavior>elementspecifieswhichinterceptionbehaviorswillbeexecutedwhen theinterceptedobjectiscalled.Thiselementmayappearmultipletimes,witheachinstanceadding aseparatebehaviorinterface. The<interceptionBehavior>elementisavalidchildofthe<register>Element. ThefollowingtableliststheattributesfortheinterceptionBehaviorelement.
Attribute name Description The name, if provided, used to resolve the interceptor type. Behaviors are resolved out of the container. This attribute is optional. The Type of behavior to create. This attribute is required. Default is false. If true, then this behavior will be applied for all registrations for this type, ignoring the name that the registration is under. This flag is useful if you are registering many implementations of the same interface with different names, and want all of them intercepted. Setting this to true lets you define the behavior once instead of in every registration. This attribute is optional.

type isDefaultForType

Therearenovalidchildelementsforthe<interceptionBehavior>element.

The<addInterface>Element
This<addInterface>elementletsyouimplementadditionalinterfaces.Itispossibleforthe interceptionsystemtoaddextrainterfacestotheproxyclassesthatarecreated.Theseare interfacesaboveandbeyondtheinterfacesthatareimplementedbytheinterceptedtypes.These interfacesmustbeimplementedbyanappropriateinterceptionbehavior.Inmostcases,the behavioritselfwillindicatewhenitaddsaninterface.Thereareoccasions,suchasforamockobject framework,whenthebehavioritselfcouldimplementanyinterfaceoralargesetofinterfaces.If youareusingsuchabehavior,youneedtoexplicitlyindicatewhichinterfacestoadd.Thiselement enablesyoutodothat.Thiselementmayappearmultipletimeswitheachappearanceaddingan individualinterface. The<addInterface>elementisavalidchildofthe<register>Element. ThefollowingtableliststheattributesfortheaddInterfaceelement.
Attribute type Description The interface to add. This attribute is required.

Therearenovalidchildelementsforthe<addInterface>element. XML
<registertype="MyViewModel">
67

<interceptortype="VirtualMethodInterceptor"/> <interceptionBehaviortype="SpecialSupportBehavior"/> <addInterfacetype="ISupportInterface1"/> </register>

The<interception>Element
This<interception>elementisusedtogrouptogetherasetofpolicyinjectionpolicydefinitions. The<interception>elementisavalidchildofthe<container>Element. The<interception>elementhasnovalidAttributes. The<interception>elementhasonevalidchildelement,the<policy>element.

The<policy>Element
Eachpolicyelementisusedtodefineapolicyinjectionpolicyandspecifiesthecomplete configurationforasinglepolicy. The<policy>elementisavalidchildofthe<interception>element. Thefollowingtableliststheattributesforthepolicyelement.
Attribute name Description The name to use when registering this policy. All policies must have unique names. This attribute is required.

Thepolicyelementhastwovalidchildelements,the<matchingRule>Elementandthe <callHandler>Element,thatspecifydetailsofthepolicy.

The<matchingRule>Element
EachmatchingRuleelementdefinesamatchingruleobjectthatwillbeusedwhendeterminingifits containingpolicywillbeappliedinpolicyinjection.AllofthematchingruleswithinamatchingRules elementmustevaluatetoTrueforapolicytoapplytoaspecifictypeormemberofatype. The<matchingRule>elementcanbeusedinmultiplewaystodefineamatchingruleobjectdirectly inthepolicyortoreferenceonethathasbeendefinedelsewhereinthecontainer.SeeConfiguring PolicyInjectionPoliciesformoreinformation. The<matchingRule>elementisavalidchildofthe<policy>element. ThefollowingtabledescribestheattributesofthematchingRuleelement.
Attribute name Description The name by which code in Unity and the configuration tools will refer to this matching rule. This attribute is required.

68

type

The type of object that will be created and registered with the container. If omitted, the container will be used to resolve the matching rule. The container will search for a mapping of IMatchingRule with the name supplied in the name attribute This attribute is not required if the types are registered elsewhere within the configuration, and the name attribute matches one of these named registrations.

Matchingrulesareonlyusedtodeterminewhichpoliciesapplyforeachinterceptablemethod.They arenotusedatruntime. ThematchingRuleelementhasthevalidchildelement,the<lifetime>Element,andanyother elementsderivedfromInjectionMemberElement.

The<callHandler>Element
EachcallHandlerelementdefinesacallhandlerobjectthatwillbeusedwhendeterminingifits containingpolicywillbeappliedinpolicyinjection.Itprovidesthedetailsofasinglecallhandler.The <callHandler>elementcanbeusedinmultiplewaystodefineacallhandlerobjectdirectlyinthe policyortoreferenceonethathasbeendefinedelsewhereinthecontainer.SeeConfiguringPolicy InjectionPoliciesformoreinformation. The<callHandler>elementisavalidchildofthe<policy>element. ThefollowingtabledescribestheattributesofthecallHandlerelement.
Attribute name Description The name of the call handler and the name by which code in Unity and the configuration tools will refer to this call handler. The name must be unique within the policy. This attribute is required. The type of the call handler. If provided, this is the type of object that will be created and registered with the container. If omitted, the container will be used to resolve the matching rule, looking for a mapping of ICallHandler with the name supplied in the name attribute. This attribute is not required if the types are registered elsewhere within the configuration, and the name attribute matches one of these named registrations.

type

ThematchingRuleelementhasthevalidchildelement,the<lifetime>element,andanyother elementsderivedfromInjectionMemberElement.

The<interceptors>Element
The<interceptors>elementispartofthelegacysupportforUnity1.xconfigurationfiles.Itis recommendedthatfornewdevelopmentyoudefineinterceptiondirectlyinthe<register>Element byusingthe<interception>elementandtherestoftheinterceptionelements.SeeLegacy InterceptionConfigurationformoreinformation. The<interceptors>elementisavalidchildofthe<container>element. Therearenotheattributesoftheinterceptorselement.
69

The<interceptors>elementhasonevalidchildelement,the<interceptor>element>.

Theinterceptors<interceptor>Element
This<interceptor>element,whenplacedwithinthe<interceptors>element,isusedtoenable interceptiononatypethatisotherwiseregisteredelsewhereintheconfigurationfile. Therearetwo<interceptor>elements.Theyareactuallytwodifferentelements(differentC# classes)thathavethesamenameintheXML.Themeaningchangesbasedoncontext(wherethey areintheXMLfile.Theycanappearinthe<register>elementorinthe<interceptors>element andaredefinedaccordingly. Itisrecommendedthatfornewdevelopmentyoudefineinterceptiondirectlyinthe<register> Elementbyusingthe<interceptor>Elementandtherestoftheinterceptionelements.SeeLegacy InterceptionConfigurationformoreinformationaboutthe<interceptors>element. Thefollowingtableliststheattributesfortheinterceptorelement.
Attribute type value Description The type of the interceptor to create. This attribute is required. If a type converter is used to create the interceptor, this value is passed to the type converter. If left out, the type converter will receive null. This attribute is optional. The type converter to use to create the interceptor. If omitted, the interceptor is created with Activator.CreateInstance.

typeConverter

Therearetwovalidchildelementsforthe<interceptor>element,the<default>elementandthe <key>element.

The<default>Element
The<default>elementspecifieswhichtypestoapplythecontaininginterceptorto.Theinterceptor willbeappliedeverytimethistypeisresolvedfromthecontainer,regardlessofwhichnameisused toresolveit. Itisrecommendedthatfornewdevelopmentyoudefineinterceptiondirectlyinthe<register> Elementbyusingthe<interceptor>elementandtherestoftheinterceptionelements The<default>elementisavalidchildoftheinterceptors<interceptor>element..SeeLegacy InterceptionConfigurationformoreinformationaboutthe<interceptors>elementanditschild elements. Thefollowingtableliststheattributesforthekeyelement.
Attribute Description 70

type

Type to apply the interceptor to. This attribute is required.

Therearenovalidchildelementsforthe<default>element.

The<key>Element
The<key>elementisusedtospecifywhichtypestoapplythecontaininginterceptorto.The interceptorwillbeappliedonlytothetype/namepairspecifiedintheattributesofthiselement.The nameandtypeattributesofthe<key>elementspecifythetypeoftheobjectthatshouldbe interceptedwhenresolved. Itisrecommendedthatfornewdevelopmentyoudefineinterceptiondirectlyinthe<register> Elementbyusingthe<interceptor>elementandtherestoftheinterceptionelements. The<key>elementisavalidchildoftheinterceptors<interceptor>element..SeeLegacy InterceptionConfigurationformoreinformationaboutthe<interceptors>elementanditschild elements. Thefollowingtableliststhevalidattributesforthe<key>element.
Attribute name Description The name of the registration to apply interception to. If omitted, the interceptor is applied to the default registration. The name attribute is only required where you configure more than one key for the same type. This attribute is optional. The type to apply the interceptor to. This attribute is required.

type

Therearenovalidchildelementsforthe<key>element.

RunTimeConfiguration
ThistopicexploresthetechniquesyoucanusetoconfigureUnitycontainersusingcodethat executesatruntimeandcallstheregistrationmethodsoftheUnitycontainer.Itcontainsthe followingtopics: UsingRunTimeConfiguration.ThistopicdescribesthefluentinterfacethatUnityexposes, andotherissuesyoushouldbeawareofwhenconfiguringthecontaineratruntimeusing code. RegisteringTypesandTypeMappings.Thistopicexplainshowtoregistermappingsinthe containerbetweentypes.Ingeneral,youwillcreatemappingsbetweenaninterfaceanda typethatimplementstheinterface,orbetweenabaseclassandatypethatinheritsthat baseclass. CreatingInstanceRegistrations.Thistopicexplainshowtoregisterexistingobjectsinthe containerthatyoucanresolveinyourapplication.ThistechniqueisusefulifyouwantUnity tomanagethelifetimeoftheobjectsyouregister.
71

RegisteringInjectedParameterandPropertyValues.Thistopicexplainshowtoregisterthe informationrequiredsothatUnitywillautomaticallypopulateconstructorandmethod parametersandpropertyvalueswhenitresolvesinstancesoftypes. RegisteringGenericParametersandTypes.Thistopicexplainshowyoucanregisterthe informationrequiredforinjectionforgenerictypes,includinggenericarrays. RegisteringContainerExtensions.Thistopicexplainshowtoregisterinformationthatinstructs Unitytoloadandusecontainerextensionsthataddadditionalfunctionalitytothecontainer, andhowyoucanregisterconfigurationinformationfortheseextensions. RegisteringInterception.Thistopicexplainshowtoregisterbehaviors,policies,handlers,and matchingrulesthatUnitywillusewhencreatinginstancesoftypestowhichyouwanttoadd interceptioncapabilitiestochangethebehaviorofthatobjectortype.

ForinformationabouthowtoconfigureUnityatdesigntime,includingthetechniquesforloading configurationfromafileorothersource,seeDesignTimeConfiguration.Forinformationabout resolvingtypesatruntime,seeResolvingObjects.

UsingRunTimeConfiguration
Thistopicdiscussessomeofthefactorsyoushouldkeepinmindwhenusingruntimeconfiguration, andexplainssomefeaturesoftheUnityruntimeconfigurationmechanism.Fordetailsonhowto specifyconfigurationusingaconfigurationfile,seeDesignTimeConfiguration.

UsingtheUnityContainerFluentInterface
TheAPIfortheUnitycontainerprovidesafluentconfigurationinterfacewhichenablesyoutochain methodcallsinonestatement.Tousethefluentinterface,callallthemethodsyouwant,oneafter theother,inasinglestatement,asshowninthefollowingcode. C#
IUnityContainermyContainer=newUnityContainer() .RegisterType<IMyService,DataService>() .RegisterType<IMyService,EmailService>() .RegisterType<MyServiceBase,LoggingService>();

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(OfIMyService,DataService)()_ .RegisterType(OfIMyService,EmailService)()_ .RegisterType(OfMyServiceBase,LoggingService)()

Methodchainingisnotarequirement,butitdoesexpeditecodingbyrelievingyoufromrepeatedly typing"container."YoucanusethisapproachtochainanyofthemethodsoftheUnityContainer
72

classwhenyoucreatethecontainer.Forexample,youcanuseanycombinationofthe RegisterType,RegisterInstance,AddExtension,andConfiguremethodstopreparethecontainer. ExtensionsusetheConfiguremethodofthecontainertoprovideaccesstoaconfigurationinterface fortheextension.Manyextensionsexposeafluentinterfacethatmakesiteasiertoconfigurethe featuresofthatextension.Forexample,interceptionisimplementedasacontainerextensionand exposestheAddPolicymethodthatyouusetodefineaninterceptionpolicyatruntime.Youspecify thetypeofmatchingrule,MatchingRuleType,andtypeofcallhandler,HandlerType. C#


IUnityContainermyContainer=newUnityContainer() .AddNewExtension<Interception>() .Configure<Interception>() .AddPolicy("PolicyName") .AddMatchingRule<MatchingRuleType>() .AddCallHandler<HandlerType>() .Container;

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer()_ .AddNewExtension(OfInterception)()_ .Configure(OfInterception)()_ .AddPolicy("PolicyName")_ .AddMatchingRule(OfMatchingRuleType)()_ .AddCallHandler(OfHandlerType)()_ .Container

WhenusingVisualBasic,youshouldusethefullsyntaxfordeclaringthecontainer,asshowninthe previouscodeexample.ThefluentinterfacemethodsallreturnIUnityContainer,not UnityContainer.IfyouusetheshortsyntaxDimmyContainerAsNewUnityContainer(),thefluent interfacemechanismwillresultinatypemismatchandcompileerrors.

RegisteringTypesandTypeMappings
Thistopicexplainshowtoregistertypesinthecontainer.Registeringatypeletsyouconfigurehow thecontainercreatesinstancesofthespecifiedtype.Ingeneral,youwillcreatemappingsbetween aninterfaceandatypethatimplementstheinterface,orbetweenabaseclassandatypethat inheritsthatbaseclass.However,youcanregistertypesinthecontainerwithoutcreatinga mapping. TheRegisterTypemethodregistersatypewiththecontainer.Attheappropriatetime,thecontainer willbuildaninstanceofthetypeyouspecify.Thiscouldbeinresponsetodependencyinjection throughclassattributesorwhenyoucalltheResolvemethod.Thelifetimeoftheobjectitbuildswill correspondtothelifetimeyouspecifyintheparametersofthemethod.Ifyoudonotspecifyavalue
73

forthelifetime,thetypeisregisteredforatransientlifetime,whichmeansthatanewinstancewill becreatedoneachcalltoResolve. ThistopiccontainsthefollowingsectionsthatexplainuseoftheRegisterTypemethod: RegisteringanInterfaceorClassMappingtoaConcreteType RegisteringaNamedType RegisteringTypeMappingswiththeContainer UsingaLifetimeManagerwiththeRegisterTypeMethod SummaryoftheRegisterTypeMethodOverloads MoreInformation

RegisteringanInterfaceorClassMappingtoaConcreteType
ThisisthemostcommonscenariofordependencyinjectionusingUnity.Itinvolvesregisteringa mappingbetweentypessuchasaninterfaceorabaseclassandacorrespondingconcreteclassthat implementsorinheritsfromit. FirstyoumustcreateanewinstanceoftheUnityContainerclassorobtainareferencetoanexisting instancesothatyoucancalltheRegisterTypemethodofthecontainerinwhichyouwanttoregister themappingortype.ThefollowingexamplecreatesanewinstanceoftheUnityContainerclassby usingthenewoperator. C#
IUnityContainermyContainer=newUnityContainer();

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer()

YoucalltheRegisterTypemethodtospecifytheregisteredtypeasaninterfaceorobjecttypeand thetargettypeyouwantreturnedinresponsetoaqueryforthattype.Thetargettypemust implementtheinterface,orinheritfromtheclass,thatyouspecifyastheregisteredtype.The followingcodecreatesadefault(unnamed)mappingusinganinterfaceasthedependencykey. C#


myContainer.RegisterType<IMyService,CustomerService>();

VisualBasic
myContainer.RegisterType(OfIMyService,CustomerService)()

Youcanmapaclassorobjecttypetoamorespecificclassthatinheritsfromitbyusingthesame syntaxbutprovidetheinheritedobjectastheregisteredtype,asshowninthefollowingexample. C#
myContainer.RegisterType<MyServiceBase,DataService>();

VisualBasic
74

myContainer.RegisterType(OfMyServiceBase,DataService)()

Theregistrationcontrolshowyouwillretrieveobjectsfromthecontainer.Itisthetypethatyou willspecifywhenyoucalltheResolveorResolveAllmethodtoretrievetheconcreteobject instance. Youcancreatemorethanoneregistrationormappingforthesametype,bycreatinganamed(non default)mappingbyspecifyinganameasaparameter,asshowninthefollowingexample. C#


myContainer.RegisterType<IMyService,CustomerService>("Customers");

VisualBasic
myContainer.RegisterType(OfIMyService,CustomerService)("Customers")

Ifthetargetclassorobjectspecifiesanydependenciesofitsown,theinstancereturnedwillhave thesedependentobjectsinjectedautomatically.Forinformationaboutusingconstructor, property,ormethodcallinjectiontechniques,seeUsingInjectionAttributes.

RegisteringaNamedType
YoucancreatesimpletyperegistrationsatruntimeusingtheUnityAPI.Toregisteratypewitha name,yousimplyspecifythenameasaparameteroftheRegisterTypecall.Thefollowingexample simplyregistersanamedtypeinthecontainermyContainer. C#
IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType(typeof(MyEmailService),"MyBestEmail");

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(GetType(MyEmailService),"MyBestEmail")

RegisteringTypeMappingswiththeContainer
Mappingtypesisusefulforretrievinginstancesofdifferentobjectsthatimplementthesame specifiedinterfaceorthatinheritfromthesamespecifiedbaseclass.Thetargettypeforthe mappingmustinheritfromorimplementthebasetypeorinterfaceofthesource.Youcangenerate bothdefaultandnamedmappingsforatyperegistrationbyusingthegenericoverloadsofthe containermethods. C#
//Registeradefault(unnamed)typemapping myContainer.RegisterType<IMyObject,MyRealObject>();
75

//FollowingcodewillreturnanewinstanceofMyRealObject myContainer.Resolve<IMyObject>(); //Registeranamedtypemapping myContainer.RegisterType<IMyObject,MyRealObject>("MyMapping"); //FollowingcodewillreturnanewinstanceofMyRealObject myContainer.Resolve<IMyObject>("MyMapping");

VisualBasic
'Registeradefault(unnamed)typemapping myContainer.RegisterType(OfIMyObject,MyRealObject)() 'FollowingcodewillreturnanewinstanceofMyRealObject myContainer.Resolve(OfIMyObject)() 'Registeranamedtypemapping myContainer.RegisterType(OfIMyObject,MyRealObject)("MyMapping") 'FollowingcodewillreturnanewinstanceofMyRealObject myContainer.Resolve(OfIMyObject)("MyMapping")

ThefollowingcoderegistersatypemappingbetweenanexampleinterfacenamedIRepositoryand aconcretetypenamedSqlRepositorythatimplementsthisinterface.Thecodethenregistersa mappingfortheSqlRepositorytypeasanopengenerictypeandshowshowyoucanresolvea specificinstanceusingtheIRepositoryinterfaceasthedependencyidentifier.Formoreinformation ongenericsseeRegisteringGenericParametersandTypes. C#


publicinterfaceIRepository<TEntity> { TEntityGetById(intid); } publicclassSqlRepository<TEntity>:IRepository<TEntity> { publicTEntityGetById(intid) { ... } } IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType(typeof(IRepository<>),typeof(SqlRepository<>)); IRepository<Customer>result=myContainer.Resolve<IRepository<Customer>>();

VisualBasic
PublicInterfaceIRepository(OfTEntity) FunctionGetById(ByValidAsInteger)AsTEntity EndInterface PublicClassSqlRepository(OfTEntity) ImplementsIRepository(OfTEntity) PublicFunctionGetById(ByValidAsInteger)AsTEntity_ ImplementsIRepository(OfTEntity).GetById
76

... EndFunction EndClass DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(GetType(IRepository(Of)),GetType(SqlRepository(Of))) DimresultAsIRepository(OfCustomer)=myContainer.Resolve(OfIRepository(Of Customer)())()

UsingaLifetimeManagerwiththeRegisterTypeMethod
YoucanalsoprovidealifetimemanagerwhencallingRegisterType.TheLifetimeManageryou specifywhenyouregisteratypecontrolswhenobjectinstancesarecreatedanddisposed.Ifyoudo notspecifyalifetimemanagerforyourtyperegistration,theobjectinstancesreturnedbythe containerhaveatransientlifetime.Thecontainerdoesnotstoreareferencetotheobject,and createsanewinstanceofthetypeeachtimeyoucalltheResolvemethod.Ifyouwantadifferent objectlifetime,specifyalifetimemanagerwhenyoucalltheRegisterTypemethod. FormoreinformationonlifetimemanagersseeUnderstandingLifetimeManagers. Themostcommonscenarioistocreateaninstancethatbehaveslikeasingleton,sothatthe containercreatestheobjectthefirsttimeyoucallResolveandthenreturnsthesameinstancefor allsubsequentcallstoResolveforaslongasthecontainerisinscope.Registerasingletonmapping byincludinganinstanceoftheContainerControlledLifetimeManagerclassintheparameterstothe RegisterTypemethod. FirstyoumustcreateanewinstanceoftheUnityContainerclassorobtainareferencetoanexisting instancesothatyoucancalltheRegisterTypemethodofthecontainerinwhichyouwanttoregister themappingortype. C#
IUnityContainermyContainer=newUnityContainer();

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer()

Thefollowingexamplecreatesadefault(unnamed)singletonmappingbyaddingnew ContainerControlledLifetimeManager()totheRegisterTypemethodparameters. C#
myContainer.RegisterType<IMyService,CustomerService>(new ContainerControlledLifetimeManager());

VisualBasic
myContainer.RegisterType(OfIMyService,CustomerService)(New ContainerControlledLifetimeManager())

Youcanalsojustregisteraspecifictypeasasingletonbyspecifyingastheregistrationtypethe concretetypeyouwantreturnedinresponsetoaqueryforthattype.Includeaninstanceofthe ContainerControlledLifetimeManagerclassintheparameterstotheRegisterTypemethod.The followingexamplecreatesadefault(unnamed)singletonregistrationforthetypeCustomerService.


77

C#
myContainer.RegisterType<CustomerService>(new ContainerControlledLifetimeManager());

VisualBasic
myContainer.RegisterType(OfCustomerService)(New ContainerControlledLifetimeManager())

Youcancreatemorethanoneregistrationusingthesameregisteredtype,CustomerService,by creatinganamed(nondefault)registrationbyspecifyinganameasaparameter.Eachnamed registrationusesaseparatelifetimemanager.Inthisexample,calling container.Resolve<CustomerService>()andcontainer.Resolve<CustomerService>("Customers") willresultintwodifferentinstances.Butcallingcontainer.Resolve<CustomerService>("Customers") multipletimeswillgivethesameinstanceeachtime. C#


myContainer.RegisterType<CustomerService>("Customers", newContainerControlledLifetimeManager());

VisualBasic
myContainer.RegisterType(OfCustomerService)("Customers",_ NewContainerControlledLifetimeManager())

Youcanregistermorethanonemappingforanobjecttype,IMyService,CustomerServicethatwill returnasingletonusingtheregisteredtype.Youcandothisbycreatinganamed(nondefault) registrationbyspecifyinganameasaparameter,asshowninthefollowingexample. C#


myContainer.RegisterType<IMyService,CustomerService>("Customers", newContainerControlledLifetimeManager());

VisualBasic
myContainer.RegisterType(OfIMyService,CustomerService)("Customers",_ NewContainerControlledLifetimeManager())

Thefollowingexampleregistersadefault(unnamed)typemappingforthetypeMyRealObjectwith aperthreadlifetimebyspecifyingthePerThreadLifetimeManager()classintheparameterlist. C#
//Specifyadefaulttypemappingwithanperthreadlifetime myContainer.RegisterType<IMyObject,MyRealObject>(new PerThreadLifetimeManager()); //Followingcodewillreturnareferencetotheobject myContainer.Resolve<IMyObject>(); //Specifyadefaulttypemappingwithanexternallycontrolledlifetime myContainer.RegisterType<IMyObject,MyRealObject>(new ExternallyControlledLifetimeManager()); //FollowingcodewillreturnasingletoninstanceofMyRealObject //Containerwillholdonlyaweakreferencetotheobject myContainer.Resolve<IMyObject>();

VisualBasic
78

'Specifyadefaulttypemappingwithanperthreadlifetime myContainer.RegisterType(OfIMyObject,MyRealObject)(New PerThreadLifetimeManager()) 'Followingcodewillreturnareferencetotheobject myContainer.Resolve(OfIMyObject)() 'Specifyadefaulttypemappingwithanexternallycontrolledlifetime myContainer.RegisterType(OfIMyObject,MyRealObject)(New ExternallyControlledLifetimeManager()) 'FollowingcodewillreturnasingletoninstanceofMyRealObject 'Containerwillholdonlyaweakreferencetotheobject myContainer.Resolve(OfIMyObject)()

ThefollowingcodeshowsadditionalusesoftheRegisterTypemethodwithalifetimemanagerto specifythecontainerbehavior.Itshowshowyoucangeneratebothdefaultandnamedmappings foratyperegistration. C#


IUnityContainermyContainer=newUnityContainer(); //Registeradefault(unnamed)typemappingwithasingletonlifetime myContainer.RegisterType<IMyObject,MySingletonObject>(new ContainerControlledLifetimeManager()); //FollowingcodewillreturnasingletoninstanceofMySingletonObject //Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve<IMyObject>(); //Registeranamedtypemappingwithasingletonlifetime myContainer.RegisterType<IMyObject,MySingletonObject>("MyMapping",new ContainerControlledLifetimeManager()); //FollowingcodewillreturnasingletoninstanceofMySingletonObject //Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve<IMyObject>();

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer() 'Registeradefault(unnamed)typemappingwithasingletonlifetime myContainer.RegisterType(OfIMyObject,MySingletonObject)(new ContainerControlledLifetimeManager()) 'FollowingcodewillreturnasingletoninstanceofMySingletonObject 'Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve(OfIMyObject)() 'Registeranamedtypemappingwithasingletonlifetime myContainer.RegisterType(OfIMyObject,MySingletonObject)("MyMapping",new ContainerControlledLifetimeManager()) 'FollowingcodewillreturnasingletoninstanceofMySingletonObject 'Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve(OfIMyObject)()
79

SummaryoftheRegisterTypeMethodOverloads
Thefollowingtablesummarizesthemethodoverloadsyoucanusetoregistertypemappingswith thecontaineratruntime.
Method RegisterType<TFrom, TTo>(params InjectionMember[] injectionMembers) Description Registers a default type mapping with the container so that it returns an instance of the type specified as TTo when a Resolve method requests an instance of the type TFrom. The injectionMembers parameter configures specific objects to be injected. Registers a default type mapping with the container so that it returns an instance of the type specified as TTo when a Resolve method requests an instance of the type TFrom. Also registers the specified LifetimeManager instance with the container to manage the lifetime of the returned object. The injectionMembers parameter configures specific objects to be injected. Registers a named type mapping with the container so that it returns an instance of the type specified as TTo when a Resolve method requests an instance of the type TFrom with the specified name. If name is null, generates a default type mapping. Names are case sensitive. The injectionMembers parameter configures specific objects to be injected. Registers a named type mapping with the container so that it returns an instance of the type specified as TTo when a Resolve method requests an instance of the type TFrom with the specified name. If name is null, generates a default type mapping. Names are case sensitive. Also registers the specified LifetimeManager instance with the container to manage the lifetime of the returned object. The injectionMembers parameter configures specific objects to be injected. Creates a default type registration with the container so that it returns an instance of that type in response to a call from the Resolve method. Allows you to register a LifetimeManager with the container to manage the lifetime of the registered type. The injectionMembers parameter configures specific objects to be injected. Creates a named type registration with the container so that it returns an instance of that type in response to a call from the Resolve method with the specified name. Allows you to register a LifetimeManager with the container to manage the lifetime of the registered type. The injectionMembers parameter configures specific objects to be injected. Registers a default type mapping with the container so that it returns an instance of the type specified as to when a Resolve method requests an instance of the type from. The injectionMembers parameter configures specific objects to be injected. Registers a named type mapping with the container so that it returns an instance of the type specified as to when a Resolve method requests an instance of the type from with the specified name. If name is null, generates a default type mapping. Names are case sensitive. The injectionMembers parameter configures specific objects to be 80

RegisterType<TFrom, TTo>(LifetimeManager lifetime, params InjectionMember[] injectionMembers)

RegisterType<TFrom, TTo>(String name, params InjectionMember[] injectionMembers)

RegisterType<TFrom, TTo>(String name, LifetimeManager lifetime, params InjectionMember[] injectionMembers)

RegisterType<T>(LifetimeManager lifetime, params InjectionMember[] injectionMembers)

RegisterType<T>(String name, LifetimeManager lifetime, params InjectionMember[] injectionMembers)

RegisterType(Type from, Type to, params InjectionMember[] injectionMembers)

RegisterType(Type from, Type to, String name, params InjectionMember[] injectionMembers)

injected. RegisterType(Type from, Type to, LifetimeManager lifetime, params InjectionMember[] injectionMembers) Registers a default type mapping with the container so that it returns an instance of the type specified as to when a Resolve method requests an instance of the type from. Also registers the specified LifetimeManager instance with the container to manage the lifetime of the returned object. The injectionMembers parameter configures specific objects to be injected. Registers a named type mapping with the container so that it returns an instance of the type specified as to when a Resolve method requests an instance of the type from with the specified name. If name is null, generates a default type mapping. Names are case sensitive. Also registers the specified LifetimeManager instance with the container to manage the lifetime of the returned object. The injectionMembers parameter configures specific objects to be injected. Creates a default type registration with the container so that it returns an instance of that type in response to a call from the Resolve method. Allows you to register a LifetimeManager with the container to manage the lifetime of the registered type. The injectionMembers parameter configures specific objects to be injected. Creates a named type registration with the container so that it returns an instance of that type in response to a call from the Resolve method with the specified name. Allows you to register a LifetimeManager with the container to manage the lifetime of the registered type. The injectionMembers parameter configures specific objects to be injected.

RegisterType(Type from, Type to, String name, LifetimeManager lifetime, params InjectionMember[] injectionMembers)

RegisterType(Type t, LifetimeManager lifetime, params InjectionMember[] injectionMembers)

RegisterType(Type t, String name, LifetimeManager lifetime params InjectionMember[] injectionMembers)

ThefollowingexampleusesRegisterTypetoconfigureclassmethodsforinjectionbythecontainer. C#
IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType<MyObject>( newInjectionConstructor(12,"HelloUnity!"), newInjectionProperty(MyProperty));

VisualBasic
DimmyContainerasIUnityContainer=NewUnityContainer() myContainer.RegisterType(OfMyObject)(_ newInjectionConstructor(12,"HelloUnity!"),_ newInjectionProperty(MyProperty))

MoreInformation
Formoreinformationaboutthetechniquesdiscussedinthistopic,seethefollowingtopics:

CreatingInstanceRegistrations

RegisteringInjectedParameterandPropertyValues ResolvingObjectsbyUsingOverrides UnderstandingLifetimeManagers UsingContainerHierarchies


81

CreatingInstanceRegistrations
Thistopicexplainshowtoregisterexistingobjectsinthecontainerthatyoucanresolveinyour application.Thistechniqueisusefulifyoualreadyhaveaninstanceofanobjectthatyouhave previouslycreatedandwantUnitytomanageitslifetime,orifyouwantUnitytoinjectthatobject intootherobjectsthatitisresolving. TheRegisterInstancemethodregistersanexistinginstancewiththecontainer.Youspecifythe instancetypeandoptionallifetimeintheparameterlist.Thecontainerwillreturnthespecified existinginstanceforthedurationofthespecifiedlifetime.TheRegisterInstancemethodoverloads areverysimilartotheRegisterTypemethodoverloads,buttheyacceptanadditionalparameter,the objectinstancetoregister.Theuseoftheregistrationtypeandanoptionalnameareidenticalfor thetwomethods. Whenresolvingtypeswithdependencies,instancesofobjectsaddedtothecontainerwiththe RegisterInstancemethodactjustlikethoseregisteredthroughRegisterType.TheRegisterType methodwithaContainerControlledLifetimeManagerautomaticallygeneratesthissingleinstance thefirsttimeyourcodecallsit,whiletheRegisterInstancemethodacceptsanexistinginstancefor whichitwillreturnreferences.Ifyoudonotspecifyalifetimemanager,thecontainerwillusea ContainerControlledLifetimeManageranditwillreturnareferencetotheoriginalobjectoneach calltoResolve. Thistopiccontainsthefollowingsections,whichexplaintheuseoftheRegisterInstancemethod: RegisteringanExistingObjectInstanceofanInterfaceorTypetoaContainer UsingaLifetimeManagerwiththeRegisterInstanceMethod SummaryoftheRegisterInstancesMethodOverloads MoreInformationonUsingtheRegisterInstanceMethod

RegisteringanExistingObjectInstanceofanInterfaceorTypetoa Container
Instanceregistrationissimilartotyperegistration,exceptthatinsteadofthecontainercreatingthe instanceyoufirstcreatetheinstancedirectlyandthenusetheRegisterInstancemethodtoaddthat instancetothecontainer.Therefore,thecontainerdoesnotneedtocreatetheinstanceonthefirst Resolverequest.TheLifetimeManagerstillcontrolsthelifetimeoftheobject,includingwhenobject instancesarecreatedanddisposed,andthecontainerreturnstheexistinginstancefortheduration ofthespecifiedlifetime.Forexample,youfirstcreatetheinstancebutthelifetimemanager determineswhetherthatinstanceisasingletonorhasaperthreadlifetime.
82

Bydefault,theRegisterInstancemethodregistersexistingobjectinstanceswithacontainer controlledlifetime,ContainerControlledLifetimeManager,andholdsontoastrongreferenceto theobjectforthelifeofthecontainer.Youcanchangethisbehaviorbyusingadifferentlifetime managertocontrolthelifetimeanddisposaloftheobject.Formoreinformation,see UnderstandingLifetimeManagers.Forinformationabouthowtocreatecustomlifetimemanagers, seeCreatingLifetimeManagers. TheUnitycontainerexposesoverloadsoftheRegisterInstancemethodthatallowyoutoregister dependencyinjectionmappingsthatreturnreferencestoasingleexistinginstanceofanobject. Eachofthesemethodsacceptsatypeparameterthatidentifiestheobjectinterfaceortypeandan existinginstanceoftheobject.Optionally,youcanprovideanametodisambiguateinstanceswhen thereismorethanoneregistrationforthesametype.Inallcasesyoumustfirstcreateorobtaina referencetoacontainer. Onceyouhaveareferencetothepropercontainer,calltheRegisterInstancemethodofthat containertoregistertheexistingobject.Specifyastheregistrationtypeaninterfacethatthetarget objectimplements,anobjecttypefromwhichthetargetobjectinherits,ortheconcretetypeofthe targetobject. Thefollowingexamplecreatesadefault(unnamed)registrationforanobjectoftypeEmailService thatimplementstheIMyServiceinterface. C#
EmailServicemyEmailService=newEmailService(); myContainer.RegisterInstance<IMyService>(myEmailService);

VisualBasic
DimmyEmailServiceAsNewEmailService() myContainer.RegisterInstance(OfIMyService)(myEmailService)

Theregistrationtypecontrolshowyouwillretrieveobjectsfromthecontainer.Itisthetypethat youwillspecifywhenyoucalltheResolveorResolveAllmethodtoretrievetheconcreteobject instance.Inthiscase,IMyServicetheDataService=myContainer.Resolve<IMyService>(). Ifyoudonotwanttomaptheexistingobjecttypetoaninterfaceorbaseclasstype,youcanspecify theactualconcretetype,myEmailService,fortheregisteredtype,EmailService,asshowninthe followingexample. C#


myContainer.RegisterInstance<EmailService>(myEmailService);

VisualBasic
myContainer.RegisterInstance(OfEmailService)(myEmailService)

Ifyouwanttocreatemorethanoneexistingobjectregistrationusingthesameregisteredtype,you cancreatenamed(nondefault)mappingsbyspecifyinganameasaparameter,suchas"Email"as showninthefollowingexample. C#


83

myContainer.RegisterInstance<EmailService>("Email",myEmailService);

VisualBasic
myContainer.RegisterInstance(OfEmailService)("Email",myEmailService)

Ingeneral,youshouldneverneedtospecifythesameregisteredtypeincallstotheRegisterType andRegisterInstancemethods.Inotherwords,ifyouregisteramappingforIMyObjectusingthe RegisterTypemethod,youshouldavoidusingIMyObjectastheregistrationtypeparameterofthe RegisterInstancemethod.Youarelikelytogetunexpectedbehaviorbecausetypemappingoccurs beforeinstancesareresolved. Ifyouwanttomanagetheinstancelifetime,provideareferencetotheexistingobjectandan instanceofthelifetimemanager.Thefollowingexamplecreatesadefault(unnamed)externally managedregistrationusinganinterface,IMyService,astheregisteredtypeandspecifiesthe lifetimemanagerbyprovidingtheExternallyControlledLifetimeManagerclassasaparameterofthe RegisterInstancemethod. C#
EmailServicemyEmailService=newEmailService(); myContainer.RegisterInstance<IMyService>(myEmailService, newExternallyControlledLifetimeManager());

VisualBasic
DimmyEmailServiceAsNewEmailService() myContainer.RegisterInstance(OfIMyService)(myEmailService,_ NewExternallyControlledLifetimeManager())

WhenyouusetheRegisterInstancemethodtoregisteranexistingobject,dependencyinjection willnottakeplaceonthatobjectbecauseithasalreadybeencreatedoutsideoftheinfluenceof theUnitycontainer.Youcanforcepropertyandmethodcallinjectiontooccurbypassingthe objectthroughtheBuildUpmethod,butyoucannotforceconstructorinjectiontooccurbecause theclassconstructorwillneverexecuteforanexistingobject.Forinformationaboutusing constructor,property,ormethodcallinjectiontechniques,seeRegisteringInjectedParameterand PropertyValues. ThefollowingexampleusestheRegisterInstancemethodtoregisterexistinginstancesofobjects thatimplementtheIMyServiceinterface.Thisexampleusesboththegenericandthenongeneric overloadsofthecontainermethodsandshowstheResolvemethodcallforeachinstance. C#
DataServicemyDataService=newDataService(); EmailServicemyEmailService=newEmailService(); LoggingServicemyLoggingService=newLoggingService();
84

//Createcontainerandregisterexistingobjectinstance IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterInstance<IMyService>(myDataService); myContainer.RegisterInstance<IMyService>("Email",myEmailService); myContainer.RegisterInstance(typeof(IMyService),"Logging",myLoggingService); //Retrieveaninstanceofeachtype IMyServicetheDataService=myContainer.Resolve<IMyService>(); IMyServicetheEmailService=myContainer.Resolve<IMyService>("Email"); IMyServicetheLoggingService =(IMyService)myContainer.Resolve(typeof(IMyService),"Logging");

VisualBasic
DimmyDataServiceAsNewDataService() DimmyEmailServiceAsNewEmailService() DimmyLoggingServiceAsNewLoggingService() 'Createcontainerandregisterexistingobjectinstance DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterInstance(OfIMyService)(myDataService) myContainer.RegisterInstance(OfIMyService)("Email",myEmailService) myContainer.RegisterInstance(GetType(IMyService),"Logging",myLoggingService) 'Retrieveaninstanceofeachtype DimtheDataServiceAsIMyService=myContainer.Resolve(OfIMyService)() DimtheEmailServiceAsIMyService=myContainer.Resolve(OfIMyService)("Email") DimtheLoggingServiceAsIMyService=myContainer.Resolve(GetType(IMyService), "Logging")

YoucanusetheRegisterInstancemethodtoregistersimpletypesandmorecomplexorcustom types.Forexample,youcanregisterStringvaluessuchasdatabaseconnectionstringswiththe containerandhavetheminjectedintoyourcodeasrequired. IfyouregisteratypemorethanonceusingtheRegisterInstancemethod(inotherwords,ifyou registermorethanoneinstanceofthesametype),onlythelastoneyouregisterremainsinthe containerandisreturnedwhenyouexecutetheResolveorResolveAllmethod.

UsingaLifetimeManagerwiththeRegisterInstanceMethod
Thelifetimemanageryouspecifywhenyouregisteranexistingobjectenablesyoutomanageobject lifetimes.Ifyoudonotspecifyalifetimemanagerforyourinstanceregistration,bydefault,the objectinstancesreturnedbythecontainerwhenyouusetheRegisterInstancemethodhavea containercontrolledlifetime.Ifyouwanttospecifythelifetimeoftheobject,specifyalifetime managerwhenyoucalltheRegisterInstancemethod.

85

Someobjects,suchasunmanagedcomponentsandotherapplications,mayholdontoreferences toanobjectthatyoupasstotheRegisterInstancemethod.Inthiscase,youshouldusethe ExternallyControlledLifetimeManager.However,youshouldalwaysdesignyourcodesothat disposableobjectsalwayshaveonlyone"owner." Themostcommonscenarioistocreateaninstancethatbehaveslikeasingleton,sothatthe containercreatestheobjectthefirsttimeyoucallResolveandthenreturnsthesameinstancefor allsubsequentcallstoResolveforaslongasthecontainerisinscope.Youcanspecifyoneofthe followingUnityBuiltInLifetimeManagerstypesoryourcustomtypewhenyoucallthe RegisterInstancemethod: ContainerControlledLifetimeManager ExternallyControlledLifetimeManager HierarchicalLifetimeManager

ItisnotappropriatetouseeitherPerResolveLifetimeManagerorTransientLifetimeManagerwith RegisterInstancesincetheybothcreateanewinstanceoneverycalltoresolve. ThefollowingexamplesummarizeshowyoucanusetheRegisterInstancemethodwithalifetime managertospecifythecontainerbehavior.Itshowshowyoucangeneratebothdefaultandnamed mappingswhenyouregisteranexistingobject.Thisexampleusesthegenericoverloadsofthe containermethods. C#


IUnityContainermyContainer=newUnityContainer(); //Registeranexistingobjectasadefault(unnamed)registrationwith //thedefaultcontainercontrolledlifetime. myContainer.RegisterInstance<IMyObject>(MyRealObject); //FollowingcodewillreturnasingletoninstanceofMyRealObject //Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve<IMyObject>(); //Registeranexistingobjectasanamedregistrationwiththedefault //containercontrolledlifetime. myContainer.RegisterInstance<IMyObject>("MySingleton",MyRealObject); //FollowingcodewillreturnasingletoninstanceofMyRealObject //Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve<IMyObject>("MySingleton"); //Sameasabove,butspecifythedefaultlifetimemanager myContainer.RegisterInstance<IMyObject>("MySingleton",MyRealObject,new ContainerControlledLifetimeManager()); //FollowingcodewillreturnasingletoninstanceofMyRealObject
86

//Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve<IMyObject>("MySingleton"); //Registeranexistingobjectasadefault(unnamed)registration //withanexternallycontrolledlifetime. myContainer.RegisterInstance<IMyObject>(MyRealObject,new ExternallyControlledLifetimeManager()); //FollowingcodewillreturnasingletoninstanceofMyRealObject //Containerwillholdonlyaweakreferencetotheobject myContainer.Resolve<IMyObject>(); //Registeranexistingobjectasanamedregistration //withanexternallycontrolledlifetime. myContainer.RegisterInstance<IMyObject>("MySingleton",MyRealObject,new ExternallyControlledLifetimeManager()); //FollowingcodewillreturnasingletoninstanceofMyRealObject //Containerwillholdonlyaweakreferencetotheobject myContainer.Resolve<IMyObject>("MySingleton"); //Registeranexistingobjectasanamedregistration //withaperthreadlifetime. myContainer.RegisterInstance<IMyObject>("MySingleton",MyRealObject,new PerThreadLifetimeManager()); //FollowingcodewillreturnasingletoninstanceofMyRealObject //Containerwillholdonlyaweakreferencetotheobject myContainer.Resolve<IMyObject>("MySingleton");

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer() 'Registeranexistingobjectasadefault(unnamed)registrationwith 'thedefaultcontainercontrolledlifetime. myContainer.RegisterInstance(OfIMyObject)(MyRealObject) 'FollowingcodewillreturnasingletoninstanceofMyRealObject 'Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve(OfIMyObject)() 'Registeranexistingobjectasanamedregistrationwiththedefault 'containercontrolledlifetime. myContainer.RegisterInstance(OfIMyObject)("MySingleton",MyRealObject) 'FollowingcodewillreturnasingletoninstanceofMyRealObject 'Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve(OfIMyObject)("MySingleton") 'Sameasabove,butspecifythedefaultlifetimemanager myContainer.RegisterInstance(OfIMyObject)("MySingleton",MyRealObject,new ContainerControlledLifetimeManager()) 'FollowingcodewillreturnasingletoninstanceofMyRealObject 'Containerwilltakeoverlifetimemanagementoftheobject myContainer.Resolve(OfIMyObject)("MySingleton") 'Registeranexistingobjectasadefault(unnamed)registration
87

'withanexternallycontrolledlifetime. myContainer.RegisterInstance(OfIMyObject)(MyRealObject,new ExternallyControlledLifetimeManager()) 'FollowingcodewillreturnasingletoninstanceofMyRealObject 'Containerwillholdonlyaweakreferencetotheobject myContainer.Resolve(OfIMyObject)() 'Registeranexistingobjectasanamedregistration 'withanexternallycontrolledlifetime. myContainer.RegisterInstance(OfIMyObject)("MySingleton",MyRealObject,new ExternallyControlledLifetimeManager()) 'FollowingcodewillreturnasingletoninstanceofMyRealObject 'Containerwillholdonlyaweakreferencetotheobject myContainer.Resolve(OfIMyObject)("MySingleton") 'Registeranexistingobjectasanamedregistration 'withaperthreadlifetime. myContainer.RegisterInstance(OfIMyObject)("MySingleton",MyRealObject,new PerThreadLifetimeManager()) 'FollowingcodewillreturnasingletoninstanceofMyRealObject 'Containerwillholdonlyaweakreferencetotheobject myContainer.Resolve(OfIMyObject)("MySingleton")

FormoreinformationaboutlifetimemanagersseeUnderstandingLifetimeManagers.

SummaryoftheRegisterInstanceOverloads
Thefollowingtablesummarizesthemethodoverloadsyoucanusetoregisterexistingobject instanceswiththecontaineratruntime.
Method RegisterInstance<TInterface>(TInterface instance) Description Registers a default instance mapping with the container so that it returns the specified instance when a Resolve method requests an instance of the type TInterface (which can be an implemented interface instead of the actual type). The container takes over the lifetime of the instance. Registers a default instance mapping with the container so that it returns the specified instance when a Resolve method requests an instance of the type TInterface (which can be an implemented interface instead of the actual type). Also registers the specified LifetimeManager instance with the container to manage the lifetime of the returned object. Registers a named instance mapping with the container so that it returns the specified instance when a Resolve method requests an instance of the type TInterface (which can be an implemented interface instead of the actual type) and the specified name. The container takes over the lifetime of the instance. Names are case sensitive. Registers a named instance mapping with the container so that it returns the specified instance when a Resolve method requests an instance of the type TInterface (which can be an implemented interface instead of the actual type) and the specified name. Names are case sensitive. Also registers the specified LifetimeManager instance with the container to 88

RegisterInstance<TInterface>(TInterface instance, LifetimeManager lifetime)

RegisterInstance<TInterface>(String name, TInterface instance)

RegisterInstance<TInterface>(String name, TInterface instance, LifetimeManager lifetime)

manage the lifetime of the returned object. RegisterInstance(Type t, Object instance) Registers a default instance mapping with the container so that it returns the specified instance when a Resolve method requests an instance of the type t (which can be an implemented interface instead of the actual type). The container takes over the lifetime of the instance. Registers a default instance mapping with the container so that it returns the specified instance when a Resolve method requests an instance of the type t (which can be an implemented interface instead of the actual type). Also registers the specified LifetimeManager instance with the container to manage the lifetime of the returned object. Registers a named instance mapping with the container so that it returns the specified instance when a Resolve method requests an instance of the type t (which can be an implemented interface instead of the actual type) and the specified name. Names are case sensitive. Also registers the specified LifetimeManager instance with the container to manage the lifetime of the returned object. Registers a named instance mapping with the container so that it returns the specified instance when a Resolve method requests an instance of the type t (which can be an implemented interface instead of the actual type) and the specified name. Names are case sensitive. Also registers the specified LifetimeManager instance with the container to manage the lifetime of the returned object.

RegisterInstance(Type t, Object instance, LifetimeManager lifetime)

RegisterInstance(Type t, String name, Object instance)

RegisterInstance(Type t, String name, Object instance, LifetimeManager lifetime)

MoreInformation
Formoreinformationaboutthetechniquesdiscussedinthistopic,seethefollowingtopics: ResolvingObjectsbyUsingOverrides UnderstandingLifetimeManagers.

RegisteringInjectedParameterand PropertyValues
Thistopicexplainshowtoconfigureacontainertoperformdependencyinjectionatruntimeby usingtheRegisterTypemethodoverloadswiththeInjectionMembersparameterandavoidrelying onannotatingtheclassestoresolvewithattributes.Thistopicincludesinformationonconfiguring Unitytoautomaticallypopulateconstructorandmethodparametersandpropertyvalueswhenit resolvesinstancesoftypes. ThistopiccontainsthefollowingsectionstoexplaintheuseoftheInjectionMembersmethods: RegisteringInjectionforParametersPropertiesandMethodsUsingInjectionMembers
89

InjectingArraysatRunTime SummaryoftheInjectionMemberMethodsandOverloads ForMoreInformationonInjectionMembers

RegisteringInjectionforParameters,Properties,andMethodsusing InjectionMembers
TheRegisterTypeoverloadsallowforconfiguringinjectionbyacceptingInjectionMembers.Include theInjectionConstructor,InjectionProperty,andInjectionMethodclassesasaRegisterType parametertoprovidedependencyinjectionconfigurationinacontainerforInjectionMember objects. ThefollowingexampleshowsthegeneralsyntaxforusinganInjectionMembersubclass, InjectionConstructor,withtheRegisterTypemethod.Inthisexamplethedefaultconstructoris called. C#
IUnityContainercontainer=newUnityContainer() .RegisterType<AType>(newInjectionConstructor()); ATypeaType=container.Resolve<AType>();

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(OfAType)(NewInjectionConstructor()) DimaTypeAsAType=container.Resolve(OfAType)()

YoucanalsouseattributesappliedtotargetclassmemberstoinstructUnitytoinjectdependent objects.Formoreinformation,seeUsingInjectionAttributes. YoucanusetheRegisterTypeoverloadstodothefollowing: RegisterConstructorsandParameters SpecifyaPropertyforInjection SpecifyaMethodforInjection

RegisterConstructorsandParameters
Youcanspecifyaconstructorfortheinjectionofaspecificnamedinstance.Whenyouincludeacall totheInjectionConstructormethodwithaspecificname,thisprovidesthenecessaryinformation onwhichconstructortouseandyoudonotneedtocallRegisterInstance.Ifyouusetheannotated constructor,yourequireacalltoRegisterInstance.

90

Inthefollowingexample,InjectionConstructorindicateswhichconstructortousebasedonits arguments,thestring"UI,"andcausestheTraceSourceLoggerconstructorwithasinglestring parametertobeinvoked. C#


container.RegisterType<ILogger,TraceSourceLogger>( "UI", newInjectionConstructor("UI"));

VisualBasic
container.RegisterType(OfILogger,TraceSourceLogger)_ ("UI",NewInjectionConstructor("UI"))

C#
[InjectionConstructor] publicTraceSourceLogger(TraceSourcetraceSource) { this.traceSource=traceSource; }

VisualBasic
<InjectionConstructor>_ PublicSubNew(traceSourceAsTraceSource) Me.traceSource=traceSource EndSub

InjectionConstructor()takesprecedenceovertheconstructorannotatedwiththe InjectionConstructorattribute. YoucouldalsousetheInjectionConstructormethodtoconfigurethecontainertocallthe constructorwiththeprovidedvaluesandbuildtheinstanceinsteadofjustregisteringaninstance createdelsewhere.Thefollowingexamplepassesvaluestotheconstructor. C#


IUnityContainercontainer=newUnityContainer() .RegisterType<MyObject>( newInjectionConstructor(someInt,someString,someDouble));

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() .RegisterType(OfMyObject) (NewInjectionConstructor(someInt,someString,someDouble))

91

Youcoulduseconstructorinjectiontospecifyanyofaseriesofconstructorsormethodoverloads; however,youcouldinadvertentlycauseinfiniterecursion.Toavoidtheinfiniterecursion,specify whichconstructortocallintheRegisterTypecall.FormoreinformationseeCircularReferences withDependencyInjection.

SpecifyaPropertyforInjection
Youcanconfigurethecontainertoinjectapropertywithorwithoutavaluefortheproperty. Inthefollowingexample,propertyinjectionisconfiguredforthepropertynamedMyPropertyto usethedefaultconfigurationofthecontainer.Thecontainerresolvesthevalueforthisproperty usingregistrationsandmappingswithinthecontainer. C#
container.RegisterType<DriveController>( newInjectionProperty("MyProperty"));

VisualBasic
container.RegisterType(OfDriveController)_ (NewInjectionProperty("MyProperty"))

ThefollowingexampleconfigurespropertyinjectionforthepropertynamedIntPropertytousea specifiedvalue.Thecontainersetsthepropertytothevalue"8." C#
intexpectedInt=8; container.RegisterType<DriveController>( newInjectionProperty("IntProperty",expectedInt));

VisualBasic
DimexpectedIntAsInteger=8 container.RegisterType(OfDriveController)(NewInjectionProperty("IntProperty", expectedInt))

Inthefollowingexample,theInjectionPropertyobjectisconfigured,indicatingthattheproperty withthenameLoggerwillbeinjected.Becausethereisnofurtherconfigurationforthisproperty, theunnamedinstancefortheproperty'stype,ILogger,willberesolvedwhenobtainingthevalueto injecttotheproperty. C#


using(IUnityContainercontainer=newUnityContainer()) { container .RegisterType<IStocksTickerView,StocksTickerForm>() //Configurepropertyinjection. .RegisterType<IStockQuoteService,MoneyCentralStockQuoteService>( newInjectionProperty("Logger")) .RegisterType<ILogger,ConsoleLogger>() .RegisterType<ILogger,TraceSourceLogger>("UI") .RegisterInstance(newTraceSource("UI",SourceLevels.All));
92

StocksTickerPresenterpresenter=container.Resolve<StocksTickerPresenter>(); Application.Run((Form)presenter.View); }

VisualBasic
UsingcontainerAsIUnityContainer=NewUnityContainer() container_ .RegisterType(OfIStocksTickerView,StocksTickerForm)()_ .RegisterType(OfIStockQuoteService,MoneyCentralStockQuoteService)_ (NewInjectionProperty("Logger"))_ .RegisterType(OfILogger,ConsoleLogger)()_ .RegisterType(OfILogger,TraceSourceLogger)("UI")_ .RegisterInstance(NewTraceSource("UI",SourceLevels.All)) DimpresenterAsStocksTickerPresenter=container.Resolve(Of StocksTickerPresenter)() Application.Run(DirectCast(presenter.View,Form)) EndUsing

ThisissimilartotheuseoftheDependencyattributewithoutfurtherconfigurationtoannotate theproperty.AddtheDependencyattributetotheLoggerproperty,toindicatethattheproperty shouldbeinjectedwiththeresultthattheproperty'stype,ILogger,isresolvedinthecontainer. ThefollowingexampleshowsthecomparableuseoftheDependencyattribute. C#


privateILoggerlogger; [Dependency] publicILoggerLogger { get{returnlogger;} set{logger=value;} }

VisualBasic
PrivateloggerAsILogger <Dependency>_ PublicPropertyLogger()AsILogger Get Returnlogger EndGet Set logger=value EndSet EndProperty

93

SpecifyaMethodforInjection
Youcanconfigureacontainertocallmethodsduringinjection.Thefollowingexampleconfigures themethodnamedInitializeMeforinjection.Itisconfiguredwithtwoparameters,aDoublevalue andaninstanceofaclassthatimplementstheILoggerinterface.Itpassesthevalue42.0tothefirst parameterandresolvestheILoggertypethroughthecontainerbylookingforamappingforthat typewiththenameSpecialLoggerandpassestheresulttothesecondparameterofthemethod. C#
container.RegisterType<DriveController>( newInjectionMethod("InitializeMe",42.0, newResolvedParameter(typeof(ILogger),"SpecialLogger")));

VisualBasic
container.RegisterType(OfDriveController)(_ NewInjectionMethod("InitializeMe",42,_ NewResolvedParameter(GetType(ILogger),"SpecialLogger")))

InjectingArraysatRunTime
Althoughanarraycanbeinjectedasavaluebysupplyingitwhenconfiguringinjectionjustasyou wouldforanyotherCLRobject,Unityenablesyoutoconfigurearrayinjectionbyusingtheresultof resolvingotherkeysaselements. UnityprovidesAPIregistrationsupportforarraysbyprovidingaresolverobjectthatresolvesallthe namedinstancesofthetyperegisteredinacontainerandanInjectionParameterValuethatisused toconfigureparametersforconstructorormethodinjection.Theimplementationforthe ResolvedArrayAPIsupportreliesontheResolveAllmethodinIUnityContainer.TheResolveAll methodenablesyoutospecifythetypeandreturnsallinstancesofallregisteredtypesrequested evenafteryouregistermultipletypenamesofthesametype. TheinjectionconfigurationAPIsarebasedonthesubclassesofInjectionParameterValue.Youcan alsoprovideothertypesofobjectswhensettingupinjection.Theobjectsaretranslatedtoa InjectionParameterValueaccordingtothefollowingrules: 1. IftheobjectisaninstanceofasubclassoftheInjectionParameterValueclass,the injectionsystemusestheobject. 2. IftheobjectisaninstanceoftheTypeclass,theinjectionsystemcreatesa ResolvedParameterthatdescribeshowthecontainershouldperforminjectionto resolveaninstanceofthattype. InordertospecifyaninstanceoftheTypeclassasaliteralargumentandensurethatthe overrideisnotresolvedinthecontainerasaninstanceofthespecifiedtypeperthisrule, youmustinjectanInjectionParameterwiththeTypeobject. C#
container.Resolve<Cars>(newDependencyOverride(typeof(Type),new InjectionParameter(typeof(int))));
94

VisualBasic
container.Resolve(OfCars)(NewDependencyOverride(GetType(Type),_ NewInjectionParameter(GetType(Integer))))

3. Inallothercases,theconfigurationAPIcreatesanInjectionParameterinstancethe containerusestogetthevaluetobeinjectedintoaproperty. 4. Youcannotsupplynullasthevaluetoinject.Youmustexplicitlyprovidean InjectionParameter,aswithtypes.

TheinjectionrulesarelocatedintheToParametermethodoftheInjectionParameterValueclass. Youcanexaminethisclasstoseetheimplementation.TheInjectionConstructor, InjectionProperty,andInjectionMethodsubclassesoftheInjectionMemberbaseclassareusedto describetheinjectionatthetimetheBuildPlanforakeyiscreated.TheBuildPlaniscreatedthe firsttimeakeyisresolved.Afterthat,injectiondoesnotusethesethreesubclasses.Youcan createyourownsubclassesbasedonthisclassifyouwanttoextendorchangethebehaviortosuit yourownspecificrequirements.Youcanalsocreateyourownsubclassesbasedonthe InjectionParameterValueclassifyouwanttocustomizethehandlingofindividualparameters. TherearetwokindsofarrayinjectioninUnity: Injectinganarraythatcontainsalltheinstancesofthearray'selementtyperegisteredinthe container(intheordertheywereregistered). Thisiscomparabletousingthe<dependency>or<optional>elementintheconfiguration. Attributesupportforinjectingallregisteredmembersofanarrayisprovidedbyusingthe [Dependency]attribute.Usingthe[Dependency]attributeproducestheequivalentresults forinjection.Youcanalsousethe[OptionalDependency]attributejustlikeyouusethe Dependencyattributeonlyitisforoptionaldependencies. Injectinganarraycontainingtheresultofresolvingaspecifickeybyusing ResolvedArrayParameter.Thereisnoattributesupportinthiscase.Use InjectionParameterValuestospecifyhoweachelementinthearrayshouldberesolved. UsingResolvedArrayParameteriscomparabletousingorthe<array>elementinthe configurationfilewhereyouwouldusethe<array>elementtospecifyhoweachelement shouldberesolved.

Injectionofpropertiescanbespecifiedsimultaneouslyintheconfigurationfileandthroughcode. TheinjectionspecificationusingtheAPIoverridesanypreviousspecificationfromtheconfiguration file,butnonoverlappingdefinitionswillbeobservedregardlessoftheiroriginbecausethe underlyingmechanismisthesame.Injectionofpropertiesindicatedthroughattributesinthe resolvedtypesisobservedonlywhentherearenootherinjectionspecificationsforanypropertyin thesametype.


95

InjectingSpecificArrayInstances
TheResolvedArrayParameterworkslikeanyotherInjectionParameterValueusedtospecifyhowto supplyaconstructorargumentorapropertyvalue.InthefollowingexampletheILogger[] parameterisinjectedwithatwoelementarraybasedonthetwoargumentsfor ResolvedArrayParameter.ThefirstelementistheresultofresolvingtheILoggerinterfacewithouta nameperthetypeof(ILogger)argument. typeof(ILogger)isequivalenttonewResolvedParameter<ILogger>(). ThesecondelementistheresultofresolvingtheILoggerinterfacewiththeUInameperthenew ResolvedParameter<ILogger>("UI")argumentexpression.Whenusingthiskindofarrayinjection, literalvaluescanbespecifiedasmembersofthearrayandasunnamedinstances. C#
//MaptheILoggerinterfacetotheCompositeLoggerclasstoinject //anarrayofspecificinstancesthroughtheconstructor. container.RegisterType<ILogger,CompositeLogger>( "composite", newInjectionConstructor( newResolvedArrayParameter<ILogger>( typeof(ILogger), newResolvedParameter<ILogger>("UI"))));

VisualBasic
'MaptheILoggerinterfacetotheCompositeLoggerclasstoinject 'anarrayofspecificinstancesthroughtheconstructor. container.RegisterType(OfILogger,CompositeLogger)(_ "composite",_ NewInjectionConstructor(_ NewResolvedArrayParameter(OfILogger)(_ GetType(ILogger),_ NewResolvedParameter(OfILogger)("UI"))))

Thefollowingexampleshowshowtoinjectaspecificinstanceofanarray.Startwiththeclass MyClasswithamember,myLogger,whichisanILoggerarray. C#
classMyClass{ publicMyClass(ILogger[]myLogger) {} }

VisualBasic
ClassMyClass PublicSubNew(ByValmyLogger()AsILogger) EndSub EndClass
96

Thefollowingexamplecodeinjectsaspecificinstance,myLogger,ofanarray,ILogger,intoMyClass. C#
container.RegisterType<MyClass>( newInjectionConstructor(newResolvedArrayParameter<ILogger>(myLogger)));

VisualBasic
container.RegisterType(MyClass)(_ NewInjectionConstructor(NewResolvedArrayParameter(OfILogger)(myLogger)))

ByusingResolvedArrayParameterasaconstructorparameteryouwillgettheregisteredinstances ofthespecifiedarray,myLogger.Atresolvetime,thecontainercallsResolveAll<ILogger>andinjects theresultingarrayintotheconstructor. Thefollowingexampleconfiguresthecontainertoinjectspecificarrayvalues,log1andlogger2. ResolvedArrayParametersuppliestheInjectionConstructorconstructorargument.typeof(ILogger) isshorthandfornewResolvedParameter<ILogger>(). C#


ILoggerlogger2=newSpecialLogger(); IUnityContainercontainer=newUnityContainer(); container.RegisterType<MyTypeArray>(newInjectionConstructor( newResolvedArrayParameter( typeof(ILogger), newResolvedParameter<ILogger>("log1"), typeof(ILogger),logger2)));

VisualBasic
Dimlogger2AsILogger=NewSpecialLogger() DimcontainerAsIUnityContainer=NewUnityContainer() container.RegisterType(OfMyTypeArray)(NewInjectionConstructor(_ NewResolvedArrayParameter(_ GetType(ILogger),_ NewResolvedParameter(OfILogger)("log1"),_ GetType(ILogger),logger2)))

InjectingAllArrayNamedInstances
Thefollowingexampleconfiguresthecontainertocalltheconstructorwithanarrayparameter.The entirearraywillbeinjected. C#
ILoggero1=newMockLogger(); ILoggero2=newSpecialLogger(); container.RegisterType<MyArrayType>( newInjectionConstructor(typeof(ILogger[])));

VisualBasic
Dimo1AsILogger=NewMockLogger() Dimo2AsILogger=NewSpecialLogger() container.RegisterType(OfMyArrayType)(_
97

NewInjectionConstructor(GetType(ILogger())))

SummaryoftheInjectionMemberMethodsandOverloads
TheRegisterTypemethodoverloadstakeanoptionalInjectionMemberparameter.Forthetableof RegisterTypemethodoverloadsseethe"SummaryoftheRegisterTypeMethodOverloads"tablein theRegisteringTypesandTypeMappingstopic. ThefollowingtablesummarizestheInjectionMembersmethodsusedinRegisterTypemethod overloadsthatallowforconfiguringinjectionofparameters,properties,andmethods.Youcanuse thesetoregistertheinformationrequiredforinjectingtypesandvaluesintoconstructorand methodparametersandpropertiesatruntime.
Method RegisterType(Type from, Type to, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers); Description General form for using the RegisterType method. Registers a type mapping with the container so that it returns an instance of the type specified as to when a Resolve method requests an instance of the type from with the specified name, null if a default registration, The lifetimeManager controls the lifetime of the returned instance. Objects configured to get injected by the container are specified by injectionMembers. RegisterType<AType>(new InjectionConstructor()) RegisterType<AType>(new InjectionConstructor(params object[] parameterValues)) RegisterType<AType>(new InjectionProperty(string propertyName)) Creates a new instance of InjectionConstructor that uses the default constructor. Creates a new instance of InjectionConstructor that looks for a constructor with the given set of parameters. parameterValues: The values for the parameters. Configures the container to inject the given property name, resolving the value via the container. The propertyName parameter is the name of the property to inject. Configures the container to inject the given property name, using the value supplied. The propertyName parameter is the name of the property to inject. The propertyValue parameter is the value for the property. Creates an instance of InjectionParameter that stores the given value, using the runtime type of that value as the type of the parameter.

RegisterType<AType>(new InjectionProperty((string propertyName, object propertyValue)) RegisterType<AType>(new InjectionParameter(object parameterValue)) RegisterType<AType>(new InjectionParameter(System.Type parameterType, object parameterValue))

Creates an instance of InjectionParameter that stores the given value, associated with the given type. parameterType: Type of the parameter. parameterValue: Value of the parameter

RegisterType<AType>(new InjectionParameter<TParameter>)

A generic version of Microsoft.Practices.Unity.InjectionParameter. Creates a new InjectionParameter<TParameter>. TParameter = value for the parameter. Configures the container to call the given methods with the given parameters. 98

RegisterType<AType>(new InjectionMethod(string methodName, params object[] methodParameters)

methodName: Name of the method to call. methodParameters: Parameter values for the method.

MoreInformation
Formoreinformationaboutthetechniquesdiscussedinthistopic,seethefollowingtopics:

RegisteringTypesandTypeMappings

ResolvingObjectsbyUsingOverrides UsingInjectionAttributes

RegisteringGenericParametersand Types
Thistopicexplainshowyoucanregistertheinformationrequiredforinjectionforgenerictypes, includinggenericarrays.YoucanspecifyagenerictypewhenyouregisteratypeintheUnity containerinalmostexactlythesamewayasyouregisternongenerictypes.Unityprovidestwo classesspecificallyforregisteringgenerics,GenericParameterforspecifyingthataninstanceofa generictypeparametershouldberesolved,andGenericResolvedArrayParameterforspecifying thatanarraycontainingtheregisteredinstancesofagenerictypeparametershouldberesolved. Seethe"SpecifyingTypesintheConfigurationFile"sectionintheSpecifyingTypesinthe ConfigurationFiletopicformoredetailsongenerics,includingadiscussionofunbounded,closed, andopengenerictypes. Thistopiccontainsthefollowingsectionsthatexplainregisteringgenerics: RegisteringGenericInterfacesandClasses RegisteringTypeMappingsForGenerics RegisteringGenericArrays SupportforGenericDecoratorChains MethodsforRegisteringGenericParametersandTypes MoreInformation

99

RegisteringGenericInterfacesandClasses
Registeringclosedgenerictypesworksexactlylikeitdoesfornongenerictypes.Formore informationseeRegisteringTypesandTypeMappings,CreatingInstanceRegistrationsand RegisteringInjectedParameterandPropertyValues. YoucanusetheRegisterInstancemethodtoregisteropengenerictypes,typeswithalltheirgeneric typeparametersleftunspecified,withnonambiguousconstructors. UnitygenericparameterinjectionruntimeAPIconfigurationsupportforparametersandproperties isprovidedbytheGenericParameterclass.UsetheRegisterTypeoverloadswithGenericParameter toregistergenerictypes.Thefollowingexampleregisterstheopengenericinterface,IGenericClass, inthecontainerastheregisteredtype,andregistersGenericClassasthetargettypetobereturned inresponsetoaqueryforIGenericClass.DuetothesyntaxlimitationsinC#andVisualBasic.NET, youmustusetheoverloadsofRegisterTypethattakeexplicitTypeobjectsinsteadofthegeneric versionofRegisterType. C#
container.RegisterType(typeof(IGenericClass<>),typeof(GenericClass<>));

VisualBasic
container.RegisterType(GetType(IGenericClass(Of)),GetType(GenericClass(Of)))

Thefollowingexampleclasstakingagenericparameterisusedinthegenerictyperegistration examples. C#
publicclassMyClass1<T> { publicTInjectedValue; publicMyClass1(strings,objecto) { } publicMyClass1(TinjectedValue) { InjectedValue=injectedValue; } }

VisualBasic
PublicClassMyClass1(OfT) PublicInjectedValueAsT PublicSubNew(sAsString,oAsObject) EndSub PublicSubNew(injectedValueAsT) InjectedValue=injectedValue EndSub EndClass

100

Thefollowingexamplesshowtheregistrationforopengenerictypesandtypemappingsusing RegisterTypewithagenericparameter. Hereishowtocallanongenericconstructoronanopengenerictype. C#


//WhereMyClass1hasatleastonegenericparameter container.RegisterType(typeof(MyClass1<>), newInjectionConstructor("Name", newInjectionParameter<object>("objectName")));

VisualBasic
'WhereMyClass1hasatleastonegenericparameter container.RegisterType(GetType(MyClass1(Of)),_ NewInjectionConstructor("Name",_ NewInjectionParameter(OfObject)("objectName")))

Hereishowtocallaconstructorthattakesagenericparameter.Herewedesignatethegeneric parameterbyusingGenericParameter. C#
//WhereMyClass1hasatleastonegenericparameter //InjectconstructorwithargumentGenericParameter. container.RegisterType(typeof(MyClass1<>), newInjectionConstructor(newGenericParameter("T"))); Accounta=newAccount(); container.RegisterInstance<Account>(a);

VisualBasic
'WhereMyClass1hasatleastonegenericparameter 'InjectconstructorwithargumentGenericParameter. container.RegisterType(GetType(MyClass1(Of)),_ NewInjectionConstructor(NewGenericParameter("T"))) DimaAsNewAccount() container.RegisterInstance(OfAccount)(a)

HereweconfigureanamedresolutionofGenericParameter()anddesignatethegenericparameter byusingGenericParameter. C#
//WhereMyClass1hasatleastonegenericparameter. //Injectconstructorwithargument. container.RegisterType(typeof(MyClass1<>), newInjectionConstructor(newGenericParameter("T","named"))); //CreateAccountinstancesandregisterusingregisterInstance Accounta=newAccount(); container.RegisterInstance<Account>(a); Accountnamed=newAccount(); container.RegisterInstance<Account>("named",named);

VisualBasic
'WhereMyClass1hasatleastonegenericparameter. 'Injectconstructorwithargument.
101

container.RegisterType(GetType(MyClass1(Of)),_ NewInjectionConstructor(NewGenericParameter("T","named"))) 'CreateAccountinstancesandregisterusingregisterInstance DimaAsNewAccount() container.RegisterInstance(OfAccount)(a) DimnamedAsNewAccount() container.RegisterInstance(OfAccount)("named",named)

Ifyouneedtospecifyamappingforexample,ifaninstanceisregisteredtosupplythe implementationforaninterface,thegenerictypeargumentmustbeprovidedwiththe RegisterInstancemethod.

RegisteringTypeMappingsforGenerics
YoucanusetheRegisterTypemethodtoregistermappingsinthecontainerthatincludegenerics. Thefollowingexamplemapsanopengenericinterface,IOpenGenericInterface<,>,toanopenclass, MyOpenClass<,>,withthevalidatingname. C#
//MaptheopengenericinterfaceIOpenGenericInterfacetothe //openclassMyOpenClass. publicMyOpenClass(IOpenGenericInterface<T>repository, IValidator<T>validator) { ... } publicclassMyOpenClass<T>:IOpenGenericInterface<T> { } //MaptheopengenericinterfaceIOpenGenericInterface //totheopenclassMyOpenClasswiththename"validating". //UsethetypeofkeywordtospecifyTypeinstances. container.RegisterType(typeof(IOpenGenericInterface<>), typeof(MyOpenClass<>), "validating");

VisualBasic
'MaptheopengenericinterfaceIOpenGenericInterfacetothe 'openclassMyOpenClass. PublicClassMyOpenClass(repositoryAsIOpenGenericInterface(OfT),_ validatorAsIValidator(OfT)) ... EndClass PublicClassMyOpenClass(OfT) ImplementsIOpenGenericInterface(OfT) ... EndClass
102

'MaptheopengenericinterfaceIOpenGenericInterface 'totheopenclassMyOpenClasswiththename"validating". 'UsetheGetTypekeywordtospecifyTypeinstances. container.RegisterType(GetType(IOpenGenericInterface(Of)),_ GetType(MyOpenClass(Of)),_ "validating")

Opengenerictypescannotbeusedasgenerictypearguments.TheversionoftheRegisterType methodtakingTypeinstancesasparametersisusedinsteadoftheversionwithgenerictype parameters.Theversionwithgenerictypeparametersbenefitsfromcompiletimetypechecks. Thefollowingexamplemapsaclosedgenericinterfacetoanongenericclassbyusingthe RegisterTypemethodtomaptheclosedIValidator<StockQuote>interfacetothenongeneric RandomStockQuoteValidator.TheRandomStockQuoteValidatorclassisanongenericclassthat implementstheclosedgenericinterface,IValidator<StockQuote>. C#


container.RegisterType<IValidator<StockQuote>,RandomStockQuoteValidator>();

VisualBasic
container.RegisterType(OfIValidator(OfStockQuote),_ RandomStockQuoteValidator)()

RegisteringGenericArrays
UnityprovidestheGenericResolvedArrayParametertoenableyoutospecifythatanarray containingtheregisteredinstancesofagenerictypeparametershouldberesolved.Youcanspecify theentirearrayorspecificnamedinstances. ThefollowingexamplesusetheMyClass2class.MyClass2hasaconstructorwithagenericarray parameter. C#
publicclassMyClass2<T> { publicT[]injectedValue; publicreadonlyboolDefaultConstructorCalled; publicMyClass2() { DefaultConstructorCalled=true; } publicMyClass2(T[]injectedValue) { DefaultConstructorCalled=false; this.injectedValue=injectedValue;
103

} publicT[]InjectedValue { get{returnthis.injectedValue;} set{this.injectedValue=value;} } }

VisualBasic
PublicClassMyClass2(OfT) PublicinjectedValueAsT() PublicReadOnlyDefaultConstructorCalledAsBoolean PublicSubNew() DefaultConstructorCalled=True EndSub PublicSubNew(injectedValueAsT()) DefaultConstructorCalled=False Me.injectedValue=injectedValue EndSub PublicPropertyInjectedValue()AsT() Get ReturnMe.injectedValue EndGet Set Me.injectedValue=value EndSet EndProperty EndClass

ThefollowingexampleregistersagenericarraybyusingtheRegisterTypemethodwitha GenericResolvedArrayParameterparameter. Herewecallaconstructorbyusingconstructorinjection,InjectionConstructor,thattakesageneric array,asaparameter,newGenericResolvedArrayParameter("T"). C#


IUnityContainercontainer=newUnityContainer() .RegisterType( typeof(MyClass2<>), newInjectionConstructor(newGenericResolvedArrayParameter("T")));

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(_ GetType(MyClass2(Of)),_ NewInjectionConstructor(NewGenericResolvedArrayParameter("T")))

Thenregisterthreenamedinstances,a0,a1anda3,forthetypeAccount:
104

C#
Accounta0=newAccount(); container.RegisterInstance<Account>("a0",a0); Accounta1=newAccount(); container.RegisterInstance<Account>("a1",a1); Accounta2=newAccount(); container.RegisterInstance<Account>(a2);

VisualBasic
Dima0AsNewAccount() container.RegisterInstance(OfAccount)("a0",a0) Dima1AsNewAccount() container.RegisterInstance(OfAccount)("a1",a1) Dima2AsNewAccount() container.RegisterInstance(OfAccount)(a2)

Youresolvethearrayasfollows: C#
MyClass2<Account>result=container.Resolve<MyClass2<Account>>();

VisualBasic
DimresultAsMyClass2(OfAccount)=container.Resolve(OfMyClass2(OfAccount))()

Thenspecifythenamedinstancestoresolve.TheInjectionConstructorargumentisagainsupplied bynewGenericResolvedArrayParameterbuthasitsargumentssuppliedbynew GenericParameter("T","a2")thatreturnsanamedinstance. C#


IUnityContainercontainer=newUnityContainer() .RegisterType( typeof(MyClass2<>), newInjectionConstructor( newGenericResolvedArrayParameter( "T", newGenericParameter("T","a2"), newGenericParameter("T","a1"))));

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(GetType(MyClass2(Of)),_ NewInjectionConstructor(_ NewGenericResolvedArrayParameter(_ "T",_ NewGenericParameter("T","a2"),_ NewGenericParameter("T","a1"))))

Now,setapropertywithagenericparameterarraytype.PropertyinjectionforMyClass2is specifiedbyInjectionProperty,whichinjectsthepropertynamedInjectedValuewiththegeneric arrayreturnedbynewGenericResolvedArrayParameter("T"). C#


IUnityContainercontainer=newUnityContainer()
105

.RegisterType(typeof(MyClass2<>), newInjectionConstructor(), newInjectionProperty("InjectedValue", newGenericResolvedArrayParameter("T")));

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(GetType(MyClass2(Of)),_ NewInjectionConstructor(),_ NewInjectionProperty("InjectedValue",_ NewGenericResolvedArrayParameter("T")))

SupportforGenericDecoratorChains
Supportforgenericdecoratorchainsisprovidedbythegenericparameter.Thefollowingexample usesagenericdecoratorwithagenericclassandagenericarrayparameter. C#
publicclassSupportClass {} publicclassClassGeneric<T> { privateT[]arrayProperty; publicT[]ArrayProperty { get{returnarrayProperty;} set{arrayProperty=value;} } privateT[]arrayCtor; publicT[]ArrayCtor { get{returnarrayCtor;} set{arrayCtor=value;} } publicClassGeneric() {} //Agenericclasswithangenericarrayproperty publicClassGeneric(T[]arrayCtor) { ArrayCtor=arrayCtor; } }

VisualBasic
PublicClassSupportClass EndClass PublicClassClassGeneric(OfT)
106

Privatem_arrayPropertyAsT() PublicPropertyArrayProperty()AsT() Get Returnm_arrayProperty EndGet Set(ByValvalueAsT()) m_arrayProperty=value EndSet EndProperty Privatem_arrayCtorAsT() PublicPropertyArrayCtor()AsT() Get Returnm_arrayCtor EndGet Set(ByValvalueAsT()) m_arrayCtor=value EndSet EndProperty PublicSubNew() EndSub 'Agenericclasswithangenericarrayproperty PublicSubNew(ByValarrayCtor__1AsT()) ArrayCtor=arrayCtor__1 EndSub EndClass

Thefollowingexampleprogrammaticallyconfigurespropertyinjection.TheRegisterTypemethod registersapropertywiththenameArrayProperty,withClassGeneric.InjectionPropertyprovides thepropertynameandvalue.Thenameofthepropertyisspecifiedbythefirstparameterfor InjectionPropertyandthevalueforthepropertyisspecifiedbythesecondparameter, GenericResolvedArrayParameter("T"). C#


publicvoidConfigureGenericInjection() { IUnityContainercontainer=newUnityContainer() .RegisterType(typeof(ClassGeneric<>), newInjectionProperty("ArrayProperty", newGenericResolvedArrayParameter("T"))); }

VisualBasic
PublicSubConfigureGenericInjection() DimcontainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(GetType(ClassGeneric(Of)),_ NewInjectionProperty("ArrayProperty",_ NewGenericResolvedArrayParameter("T")))
107

EndSub

MethodsforRegisteringGenericParametersandTypes
Thefollowingtablesummarizesthemethodsyoucanusetoregistergenericparametersandtypes withthecontaineratruntime.
Method GenericResolvedArrayParameter(string genericParameterName, params object[] elementValues) Description Creates a new GenericResolvedArrayParameter instance that specifies that the given named generic parameter should be resolved where genericParameterName is the generic parameter name to resolve and elementValues represents the values for the elements that will be converted to InjectionParameterValue objects. Creates a new GenericParameter instance that specifies that the given named generic parameter should be resolved where genericParameterName is the generic parameter name to resolve. GenericParameter(string genericParameterName, string resolutionKey) Creates a new GenericParameter instance that specifies that the given named generic parameter should be resolved where genericParameterName is the generic parameter name to resolve and resolutionKey is the name to use when looking up the value in the container.

GenericParameter(string genericParameterName)

MoreInformation
Formoreinformationaboutthetechniquesdiscussedinthistopic,seethefollowingtopics: SpecifyingTypesintheConfigurationFile RegisteringTypesandTypeMappings

RegisteringContainerExtensions
ThistopicexplainshowtoregisterinformationthatinstructsUnitytoloadandusecontainer extensionsthataddadditionalfunctionalitytothecontainer,andhowyoucanregisterconfiguration informationfortheseextensions. Thistopiccontainsthefollowingsectionsthatexplaincontainerextensions: AddingandRemovingExtensions AccessingConfigurationInformationforExtensions MethodsforRegisteringandConfiguringContainerExtensions
108

MoreInformation

AddingandRemovingExtensions
YoucanaddacustomorthirdpartyextensiontotheUnitycontaineratruntimeusingthe AddExtensionandAddNewExtensionmethods,andyoucanremoveextensionsusingthe RemoveAllExtensionsmethod. Toaddanextension,usetheAddNewExtensionorAddExtensionmethodofthecontainer.For example,thiscodecreatesanewinstanceofanextensionclassnamedMyCustomExtensionthat youhavepreviouslycreated,andwhichresidesinthisorareferencedproject,andaddsittothe container. C#
IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<MyCustomExtension>();

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfMyCustomExtension)()

Ifyoualreadyhaveanexistingextensioninstance,youaddittothecontainerusingthe AddExtensionmethod.Forexample,thiscodeaddsanextensioninstancereferencedbythe variablenamedmyExistingExtensiontothecontainer. C#


IUnityContainercontainer=newUnityContainer(); container.AddExtension(myExistingExtension);

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() container.AddExtension(myExistingExtension)

TheAddNewExtensionmethodcreatestheactualextensionobjectbyresolvingitfromthe container.ThepreviousexampleusingAddNewExtensionisequivalenttothefollowingexample. C#
IUnityContainercontainer=newUnityContainer(); container.AddExtension(container.Resolve<MyCustomExtension>());

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() container.AddExtension(container.Resolve(OfMyCustomExtension)())

Youcannotremoveindividualextensionsfromthecontainer.However,youcanremoveallcurrently registeredextensionsandthenaddbackanyyouwanttouse.Toremoveallexistingextensions,use theRemoveAllExtensionsmethodofthecontainer.Forexample,thiscoderemovesallextensions fromanexistingcontainerreferencedinthevariablenamedcontainer.


109

C#
container.RemoveAllExtensions();

VisualBasic
container.RemoveAllExtensions()

Importantpartsofthecontainer'scorefunctionalityareimplementedusingtheextension mechanism.YouwillbeunabletosuccessfullyresolveobjectsafteryoucallRemoveAllExtensions unlessyouexplicitlyaddthosecorepartsbacktothecontainer.

AccessingConfigurationInformationforExtensions
Containerextensionswillusuallyaddstrategiesandpoliciestothecontainer.However,extensions canexposeconfigurationinterfacesthatallowthemtoreadandexposeconfigurationinformation. Theextensionmustprovideitsownfeaturestoreadandmanageconfigurationinformation. Toaccesstheconfigurationinformationforanextension,usetheConfiguremethod.Thismethodof theUnityContainerclasswalksthelistofextensionsaddedtothecontainerandreturnsthefirst onethatimplementsthetypeyouspecifyintheparameteroftheConfiguremethod.Themethod returnstherequiredconfigurationinterface,oritreturnsnull(NothinginVisualBasic)ifthe configurationtypeisnotfound. TherearetwooverridesoftheConfiguremethod.Youcanspecifytheextensiontypeinthegeneric overloadasaconfigurator(aclassthatimplementstheIUnityContainerExtensionConfigurator interface),oryoucanusethenongenericoverloadthatacceptsandreturnsanObjecttype.The followingcodeshowsbothoverridesoftheConfiguremethodusedtoretrievetheconfigurationas atypenamedMyConfigInterface. C#
//usinga"configurator"whereMyConfigInterfaceimplements //theIUnityContainerExtensionConfiguratorinterface MyConfigInterfaceconfigurator=container.Configure<MyConfigInterface>(); //usinganObjecttype Objectconfig=container.Configure(typeof(MyConfigInterface));

VisualBasic
'usinga"configurator"whereMyConfigInterfaceimplements 'theIUnityContainerExtensionConfiguratorinterface DimconfiguratorAsMyConfigInterface=container.Configure(Of MyConfigInterface)() 'usingtheconfigurationinterfacetype DimconfigAsObject=container.Configure(GetType(MyConfigInterface))

Formoreinformationaboutconfigurationforcontainerextensions,seeCreatingandUsing ContainerExtensions.

110

MethodsforRegisteringandConfiguringContainerExtensions
Thefollowingtablesummarizesthemethodoverloadsyoucanusetoregisterandconfigure containerextensionsatruntime.
Method AddExtension(UnityContainerExtension extension) Description Adds the specified extension object, which must be of type UnityContainerExtension, to the container. Returns a reference to the container, equivalent to this in C# or Me in Visual Basic. Creates a new extension object of type TExtension and adds it to the container. Returns a reference to the container, equivalent to this in C# or Me in Visual Basic. Returns the configuration of the specified extension interface as an object of type TConfigurator or null if the specified extension interface is not found. Extensions can expose configuration interfaces in addition to adding strategies and policies to the container. This method walks the list of extensions and returns the first one that implements the specified type. Returns the configuration of the specified extension interface as an object of type configurationInterface or null if the specified extension interface is not found. Extensions can expose configuration interfaces in addition to adding strategies and policies to the container. This method walks the list of extensions and returns the first one that implements the specified type. Removes all installed extensions from the container, including all extensions that implement the default behavior, but it does not remove registered instances and singletons already set up in the container. To use the container again after executing this method, you must add either the default extensions or your own custom extensions. Returns a reference to the container, equivalent to this in C# or Me in Visual Basic.

AddNewExtension<TExtension>( )

Configure<TConfigurator>( )

Configure(Type configurationInterface)

RemoveAllExtensions( )

MoreInformation
Formoreinformationaboutthetechniquesdiscussedinthistopic,seethefollowingtopics: ExtendingtheUnityConfigurationSchema ConfigurationFilesforInterception CreatingandUsingContainerExtensions DesignofUnity RegisteringInterception

RegisteringInterception
111

Thistopicexplainsruntimeregistrationofthevariousinterceptionelements,includinginterceptors, behaviors,policies,handlers,andmatchingrulesthatUnityusestoconfigureacontainerfor interception.Theconfigurationinformationisusedwhencreatinginstancesoftypesforwhichyou wanttoaddinterceptioncapabilitiestochangethebehaviorofthatobjectortype.Inorderto providebackwardcompatibility,Unity2.0supportscallingtheolderAPISetInterceptorForand SetDefaultInterceptorFormethodsontheInterceptioncontainerextensioninadditionto supportingtheUnity2.0approachusingtheRegisterTypeAPItoexplicitlyconfigureinterceptors, behaviors,andadditionalinterfaces. RegisteringInterceptorsandInterceptorBehaviorsExplicitlyUsingRegisterType DefaultInterceptorforaType RegisteringAdditionalInterface RegisteringPolicyInjectionComponents

Forinformationonusingaconfigurationfiletoconfigureacontainerforinterception,see ConfigurationFilesforInterception. ForinformationonthedesignofUnityinterceptionseeInterceptionwithUnity. Forinformationonusinginterceptionwithoutadependencyinjection(DI)container,seethe"Stand AloneUnityInterception"sectioninUsingInterceptioninApplications.

RegisteringInterceptorsandInterceptorBehaviorsExplicitlyUsing RegisterType
Unity2.0enablesinterceptionlikeanyothercontainerextensionbyusing container.AddNewExtension.Thenyoucanconfigureatypeforinterceptionusinganinterceptorof yourchoosing,withbehaviorsofyourchoosing.InUnity2.0youexplicitlyconfigurewhichobjectis tobeinterceptedbywhichinterceptionmechanismandspecifythebehaviorbyusing InterceptionBehavior;Unity1.2implicitlysetuppolicyinjectionwhenyouconfiguredan interceptor.Thefollowingexampleshowshowtoconfigureinterceptionforatypeandturnona custombehavior.ThisexamplefirstaddstheInterceptionextensionbycallingAddNewExtension, andthenusesRegisterTypetoregisteraVirtualMethodInterceptorandaninterceptionbehavior. Thebehaviormustbedefinedelsewhere. C#
IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<Interception>(); container.RegisterType<TypeToIntercept>( newInterceptor<VirtualMethodInterceptor>(), newInterceptionBehavior<CustomBehavior>());

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfInterception)() container.RegisterType(OfTypeToIntercept)(_ NewInterceptor(OfVirtualMethodInterceptor)(),_
112

NewInterceptionBehavior(OfCustomBehavior)())

UsingthisoverloadoftheInterceptorconstructoractuallytellsthecontainertoresolvethe interceptorthroughthecontainer.Youcanpassanoptionalstring,whichbecomesthenameto resolvewith.Inmostapplicationsyouwouldsimplyleavethisblank,butifyouhaveimplemented custominterceptors,youmightwanttoprovideadditionalconfiguration.Thereisanotheroverload oftheInterceptorconstructoryoucanusetospecifytheinterceptorsandbehaviorsbycreating instancesandpassingtheactualinstancesintothecontainer,asdoneinthefollowingexample: C#


//Addtheinterceptionextensiontothecontainer IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<Interception>(); //Configureinterception container.RegisterType<IInterface,BaseClass>( "myInterceptor", newInterceptor(newInterfaceInterceptor()), newInterceptionBehavior(newCustomBehavior()), newInterceptionBehavior(newSomeOtherBehavior()));

VisualBasic
'Addtheinterceptionextensiontothecontainer DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfInterception)() 'Configureinterception container.RegisterType(OfIInterface,BaseClass)_ ("myInterceptor",_ NewInterceptor(NewInterfaceInterceptor()),_ NewInterceptionBehavior(NewCustomBehavior()),_ NewInterceptionBehavior(NewSomeOtherBehavior()))

DefaultInterceptorforaType
Whenusingmultiplenamedregistrationsforthesametype,youoftenwantallimplementationsof thattypetobeintercepted.Ratherthanrequiringyoutospecifytheinterceptorforallregistrations, youcaninsteadspecifyadefaultinterceptoronanyoneoftheregistrations.Thisinterceptorwillbe appliedanytimethattypeisresolved,regardlessofthenameusedtoresolveit.Additionally,you canalsoprovidedefaultinterceptionbehaviors,whichapplythebehaviorstoallinstancesofthat typeregardlessoftheinstancename. C#
//Addtheinterceptionextensiontothecontainer IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<Interception>(); //ConfiguredefaultinterceptionforBaseClass container.RegisterType<IInterface>( newDefaultInterceptor<InterfaceInterceptor>(), newDefaultInterceptionBehavior(newCustomBehavior()), newDefaultInterceptionBehavior(newSomeOtherBehavior());
113

//Configuretypemappings container.RegisterType<IInterface,BaseClass>("myInterceptor") .RegisterType<IInterface,OtherClass>("interceptedToo");

VisualBasic
'Addtheinterceptionextensiontothecontainer DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfInterception)() container.RegisterType(OfIInterface)(_ newDefaultInterceptor(OfInterfaceInterceptor)(),_ newDefaultInterceptionBehavior(newCustomBehavior()),_ newDefaultInterceptionBehavior(newSomeOtherBehavior()) 'Configuretypemappings container.RegisterType(OfIInterface,BaseClass)("myInterceptor")_ .RegisterType(OfIInterface,OtherClass)("interceptedToo")

VisitMSDNforinformationonhowpreviousversionsofUnityprovidedConfigurationSupportfor Interception.

RegisteringAdditionalInterfaces
Theinterceptionmechanismcanaddentirelynewinterfacestoobjects.Theinterfacesare implementedbytheinterceptionbehaviors.Inmostcases,thebehaviorsthemselvesprovidethe informationaboutwhichadditionalinterfacestheyimplement.Inrarecasessuchasforamock objectbehavior,thebehaviorcanimplementanyinterface,soextrainformationisrequiredabout exactlywhichextrainterfacestoaddtotheobject. TheInterceptionExtension.AdditionalInterfaceclassenablesyoutoimplementadditionalinterfaces ontargetobjects.Itcontainsinformationforadditionalinterfacesthatwillbeaddedtothe interceptedobjectandconfiguresacontaineraccordingly. Inthefollowingexample,IOtherInterfaceisanAdditionalInterfaceinterfacethatconfiguresthe interceptortoimplementaspecifiedinterfaceinadditiontotheoriginalinterfacesimplementedby thetargetobject,andMyInterceptionBehaviorisanimplementationoftheIInterceptionBehavior interfacewhichdefinesaninterceptionbehavior. C#
IUnityContainercontainer=newUnityContainer(); container.RegisterType<IInterface,BaseClass>( "sample", newInterceptor<VirtualMethodInterceptor>(), newAdditionalInterface<IOtherInterface>(), newInterceptionBehavior<MyInterceptionBehavior>());

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() container.RegisterType(OfIInterface,BaseClass)(_ "sample",_
114

NewInterceptor(OfVirtualMethodInterceptor)(),_ NewAdditionalInterface(OfIOtherInterface)(),_ NewInterceptionBehavior(OfMyInterceptionBehavior)())

Forinformationonusingaconfigurationfiletoconfigureinterceptionforadditionalinterfacessee ConfigurationFilesforInterception.

RegisteringPolicyInjection Components
Thistopicexplainshowtoregisterthevariouselements,includinginterceptors,behaviors,policies, callhandlers,andmatchingrulesthatUnityusestoconfigureacontainerforinterceptionandfora policyinjectionbehavior. Whenyouconfigurepolicyinjectionyoumustspecifywhichobjectswillbeinterceptedwiththe policyinjectionbehaviorandwhichpoliciesinthecontaineraretobeused.Thenwhenbuildingthe object,thepolicyinjectionbehaviorissetupusingthepoliciesalreadydefinedinthecontainer. Thistopiccontainsthefollowingsections: PolicyInjectionRunTimeConfiguration DefiningPoliciesbyUsingtheAPI

PolicyInjectionRunTimeConfiguration
Therearetwostepstoconfiguringatypeforpolicyinjection.First,youmustregisterthetypeinthe container.Inthatregistration,youmustconfigureaninterceptorandenablethe PolicyInjectionBehavior.Second,youmustconfigurethepolicyinjectionpoliciesthatdetermine whichcallhandlersexecuteonwhichmethods. C#
intintercepted=0; varcontainer=newUnityContainer(); container .AddNewExtension<Interception>() .RegisterType<ActionCallHandler>() //Registerthetypetobeintercepted .RegisterType<InterceptedType>( newInterceptor<TransparentProxyInterceptor>(), newInterceptionBehavior<PolicyInjectionBehavior>()) //Configurepolicies .Configure<Interception>() .AddPolicy("policy") .AddCallHandler(newActionCallHandler(()=>intercepted++)) .AddMatchingRule(newMemberNameMatchingRule("MethodX"));
115

VisualBasic
DiminterceptedAsInteger=0 Dimcontainer=NewUnityContainer() container_ .AddNewExtension(OfInterception)()_ .RegisterType(OfActionCallHandler)()_ 'Registerthetypetobeintercepted .RegisterType(OfInterceptedType)(_ NewInterceptor(OfTransparentProxyInterceptor)(),_ NewInterceptionBehavior(OfPolicyInjectionBehavior)())_ 'Configurepolicies .Configure(OfInterception)()_ .AddPolicy("policy")_ .AddCallHandler(NewActionCallHandler(Function()_ System.Math.Max(System.Threading.Interlocked.Increment_ (intercepted),intercepted1)))

DefiningPoliciesbyUsingtheAPI
ThestreamlinedInterceptionExtension.PolicyDefinitionAPIsprovideasimplifiedwaytowireup RuleDrivenpoliciesandtheirIMatchingRulesandICallHandlers.ThegeneralpurposeAPIsrequire repeatedcallstotheRegisterTypemethod.ThestreamlinedextensionAPIsreducetheoverhead requiredtomanagethevariousstringsandcrosslinks,thusmakingtheprocessmoreobviousand convenient. EverythingyoucandowiththeInterceptionExtension.PolicyDefinitionAPIcanbedonewiththe generalpurposeAPIs. Formoreinformationaboutinterceptionandselectingtheobjectsandtheirmemberstoadda handlerpipeline,seeUsingInterceptionandPolicyInjection. ThefollowingarestreamlinedconfigurationInterceptionExtension.PolicyDefinitionmethods: AddPolicy.Thesemethodsareasetofmethodsontheinterceptiontype. AddMatchingRule.ThesemethodsareonthePolicyDefinitionclassyougetwhenyoucall AddPolicy. AddCallHandler.ThesemethodsareonthePolicyDefinitionclassyougetwhenyoucall AddPolicy.

Thesemethodsareonlyusedforconfiguringruledrivenpolicies,whicharealsotheonlypolicies configurablewiththestandardinstallationandsetup.Foruserdefinedpolicies,youmustusethe generalpurposeAPIs. ThestreamlinedInterceptionExtension.PolicyDefinitionAPIissimilartotheexpandedRegisterType APIinthatyoucanprovidealifetimemanager(justlikeRegisterType),themapping,andthe injectionconfiguration.Italsodiffersinthefollowingways: TheentrypointfortheAPIistheAddPolicymethodintheinterceptionextension.


116

TheresultofthismethodisatransientPolicyDefinitionobject,whichcanbeusedtoadd matchingrulesandaddcallhandlers.Thesemethodsaddrulesandhandlerstothepolicy, buttheyalsoconfigurethecontainerasnecessary. ThesignaturesforthesemethodsaresimilartothoseofRegisterType,butthenamesimply theinterfacebeingregisteredinsteadofrelyingongenerictypeparameters,aswiththe generalpurposeRegisterTypeMethods.Thefollowingisanexample: C#


//Insteadof: RegisterType<ICallHandler,MyCallHandler>(...) //youuse: AddCallHandler<MyCallHandler>(...).

VisualBasic
'Insteadof: RegisterType(OfICallHandler,MyCallHandler)(...) 'youuse: AddCallHandler(OfMyCallHandler)(...).

Therearethreeapproachesforusingthestreamlinedinterceptionmethods: Supplyastringparameter.Useastringparametertoindicatethatyouwanttouseanobject thatwasconfiguredelsewhere.IfyouusedthegeneralpurposeAPItoconfigureahandlerin thecontainer,youwouldjustlinktoitwiththisapproach. Youcansupplyastringandconfigurethecorrespondingruleorhandleratalatertime. Thefollowingisanexampleofapolicywithexternallyconfiguredrulesandhandlers. C#


publicvoidPolicyUseExample() { IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<Interception>(); container .Configure<Interception>() .AddPolicy("MyPolicy") .AddMatchingRule("rule1") .AddCallHandler("handler1") .AddCallHandler("handler2") .Interception.Container .RegisterType<IMatchingRule,AlwaysMatchingRule>("rule1") .RegisterType<ICallHandler,LogCallHandler>( "handler1", newInjectionConstructor("handler1")) .RegisterType<ICallHandler,LogCallHandler>( "handler2", newInjectionConstructor("handler2"), newInjectionProperty("Order",10)); .RegisterType<TypeToIntercept>("wrappable", newInterceptor<TransparentProxyInterceptor>(),
117

newInterceptionBehavior<PolicyInjectionBehavior>()); LogCallHandler.Calls.Clear(); varwrappable1=container.Resolve<TypeToIntercept>("wrappable"); wrappable1.Method2(); }

VisualBasic
PublicSubPolicyUseExample() DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfInterception)() container_ .Configure(OfInterception)()_ .AddPolicy("MyPolicy")_ .AddMatchingRule("rule1")_ .AddCallHandler("handler1")_ .AddCallHandler("handler2")_ .Interception.Container_ .RegisterType(OfIMatchingRule,AlwaysMatchingRule)_ ("rule1")_ .RegisterType(OfICallHandler,LogCallHandler)_ ("handler1",NewInjectionConstructor("handler1"))_ .RegisterType(OfICallHandler,LogCallHandler)_ ("handler2",_ NewInjectionConstructor("handler2"),_ NewInjectionProperty("Order",10))_ .RegisterType(OfTypeToIntercept)("wrappable",_ newInterceptor(OfTransparentProxyInterceptor)(),_ newInterceptionBehavior(OfPolicyInjectionBehavior)()) LogCallHandler.Calls.Clear() container_ .Configure(OfInterception)()_ .SetInterceptorFor(OfTypeToIntercept)_ ("wrappable",NewTransparentProxyInterceptor()) Dimwrappable1AsTypeToIntercept=container.Resolve(Of TypeToIntercept)("wrappable") wrappable1.Method2() EndSub

Supplyaninstance.Usethiscasewhenyoualreadyhavetheobjectandwantonlythenew policytouseit. C#
publicvoidAPolicyGivenRulesAndHandlers() { IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<Interception>(); IMatchingRulerule1=newAlwaysMatchingRule(); ICallHandlerhandler1=newCallCountHandler(); container .Configure<Interception>() .AddPolicy("MyPolicy")
118

.AddMatchingRule(rule1) .AddCallHandler(handler1); .RegisterType<TypeToIntercept>("wrappable", newInterceptor<TransparentProxyInterceptor>(), newInterceptionBehavior<PolicyInjectionBehavior>()); varwrappable1=container.Resolve<TypeToIntercept>("wrappable"); wrappable1.Method2(); }

VisualBasic
PublicSubAPolicyGivenRulesAndHandlers() DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfInterception)() Dimrule1AsIMatchingRule=NewAlwaysMatchingRule() Dimhandler1AsICallHandler=NewCallCountHandler() container_ .Configure(OfInterception)()_ .AddPolicy("MyPolicy")_ .AddMatchingRule(rule1)_ .AddCallHandler(handler1) container.RegisterType(OfTypeToIntercept)("wrappable", newInterceptor(OfTransparentProxyInterceptor)(),_ newInterceptionBehavior(OfPolicyInjectionBehavior)()) Dimwrappable1=container.Resolve(OfTypeToIntercept)("wrappable") wrappable1.Method2() EndSub

Supplyatype.Supplyatypeeitherasagenerictypeparameteroranormalparameter,and, optionally,aname,alifetimecontainer,andinjectionconfigurationinanycombination.Use thisifthematchingruleorcallhandlerobjectisuniquetothepolicyitisdefinedin,asit allowsyoutocentralizetheconfigurationofthepolicyinonespot.Normally,youdonot needtospecifyanameforthematchingrulesorcallhandlers.Ifyoudo,thatnamecanbe usedinotherpoliciestoreusethenamedmatchingruleorcallhandlerusingthe configurationapproach,asshowninsupplyastringparameter.Inthisapproach,you describehowtoresolveforinjection. C#


publicvoidAPolicyGivenRulesAndHandlersTypes() { IUnityContainercontainer=newUnityContainer(); container.AddNewExtension<Interception>(); container .Configure<Interception>() .AddPolicy("MyPolicy") .AddMatchingRule(typeof(AlwaysMatchingRule)), newInjectionConstructor("rule1")) .AddCallHandler(typeof(LogCallHandler)), newInjectionConstructor("handler1"), newInjectionProperty("Order",10)) container.RegisterType<TypeToIntercept>("wrappable", newInterceptor<TransparentProxyInterceptor>(),
119

newInterceptionBehavior<PolicyInjectionBehavior>()); LogCallHandler.Calls.Clear(); TypeToInterceptwrappable1= container.Resolve<TypeToIntercept>("wrappable"); wrappable1.Method2(); }

VisualBasic
PublicSubAPolicyGivenRulesAndHandlersTypes() DimcontainerAsIUnityContainer=NewUnityContainer() container.AddNewExtension(OfInterception)() container.Configure(OfInterception)()_ .AddPolicy("MyPolicy")_ .AddMatchingRule(GetType(AlwaysMatchingRule)), newInjectionConstructor("rule1"))_ .AddCallHandler(GetType(LogCallHandler)), newInjectionConstructor("handler1"),_ newInjectionProperty("Order",10)) container.RegisterType(OfTypeToIntercept)("wrappable",_ newInterceptor(OfTransparentProxyInterceptor)(),_ newInterceptionBehavior(OfPolicyInjectionBehavior)()) LogCallHandler.Calls.Clear() Dimwrappable1AsTypeToIntercept=_ container.Resolve(OfTypeToIntercept)("wrappable") wrappable1.Method2() EndSub

OnesignificantdifferencebetweentheRegisterTypemethodsandthisstreamlinedAPIisthatwhen youdonotspecifyaname,anameisgeneratedforyou,soallanonymousdefinitionswithout nameswillnotbeoverwrittenbyotherdefinitionswithoutnames.Ifyoudospecifyaname,itis usedandmayoverridepreviousexistingpolicieswiththesamename. Youcanusegenericparametersupportwhenyouconfigureforinjection,justlikeyoudowith RegisterType. ThegenericversionsoftheAddMatchingRuleandAddCallHandlermethodscontainthetypesyou cansupply,unlikeRegisterType.RegisterTypeisageneralpurposemethodandplacesno constraintsonthetypesyoucansupply.ForAddCallHandler<TCallHandler>(),youcanonlyprovide atypevalueforTCallHandlerthatimplementsICallHandler.Thenongenericversionofthemethod islimitedtoperformingruntimechecks.Similarly,AddMatchingRule<TRule>()isconstrainedto typesimplementingIMatchingRule. Onceyouhavedefinedapolicy,youmustalsosetupaninterceptorandturnonpolicyinjectionfor eachtypeyouwantintercepted.Settingtheinterceptorjustsayshowtodointerceptiononatypeif ithasmembersthatmatchanyrules.Withoutthepolicyinjectionbehavior,ruleswillnotbe checked.Andyoumusthaveatleastonematchingruledefinedornothingwillhappen. Ingeneral,youdonotwanttouseAlwaysMatchingRule,sincethatmatchesabsolutelyeverything, whichisratherindiscriminate(andisonlypartofthetestsuite,notthemain.dllfile).Itisusefulasa shortcutfortestingpurposes;but,usingtheTypeorNamespacematchingrulesisbetterformore generalizedmatches.
120

UsingUnityinApplications
ThistopicdescribeshowtodevelopapplicationsusingUnity,andhowtocreateandbuildinstances ofobjects.ItassumesthatyouunderstandhowtoconfiguretheUnitycontainer.Thissection includesthefollowingtopics: ApplicationDesignConceptswithUnity.ThistopicexplainshowUnitycanhelpyouto implementcommondesignpatternsandachievedecouplingandcoherenceinyourdesigns. AddingUnitytoYourApplication.ThistopicdescribeshowtoaddUnitytoyourproject,and howtoreferencetheappropriateassembliesinyourcode. ResolvingObjects.Thistopiccontainsaseriesofsectionsthatdescribehowyoucanresolve objectsthroughtheUnitycontainersothatitcreatestheappropriatetypeandoptionally populatesanydependenciesspecifiedforthesetypes. UnderstandingLifetimeManagers.ThistopicdescribesthewaythatUnitymanagesthe lifetimeofobjectsitcreates,andhowyoucanusethelifetimemanagersincludedwithUnity. UsingContainerHierarchies.ThistopicexplainshowyoucanuseahierarchyofnestedUnity containerstoachievefinelygrainedcontrolovertheconfigurationofUnityandmanagethis configurationatruntime.

ForinformationonhowtoconfigureUnity,seeConfiguringUnity. Unityshipsasbothsourcecodeandsignedbinaryassemblies.Youcanusethesignedassemblies directly.Ifyouintendtocompilethesourcecode,seeTargetAudienceandSystemRequirements.

ApplicationDesignConceptswithUnity
Featuressuchasinversionofcontrol,dependencyinjection,interception,factory,andlifetime (someofwhicharedescribedinthe"ScenariosforUnity"sectionofthetopicWhenShouldIUse Unity?)provideseveralmajoradvantageswhenbuildingapplicationsthatconsistofmanyindividual classesandcomponents.Designingapplicationsthatconformtothesepatternscanprovidethe following: Thecapabilitytosubstituteonecomponentforanotherusingapluggablearchitecture. Thecapabilitytocentralizeandabstractcommonfeaturesandtomanagecrosscutting concernssuchaslogging,authentication,caching,andvalidation. Increasedconfigurationflexibility. Thecapabilitytolocateandinstantiateservicesandcomponents,includingsingletoninstances oftheseservicesandcomponents.
121

Simplifiedtestabilityforindividualcomponentsandsectionsoftheapplication. Simplifiedoveralldesign,withfasterandlesserrorpronedevelopment. Easeofreuseforcommoncomponentswithinotherapplications.

Ofcourse,implementingthesepatternscaninitiallymakethedesignanddevelopmentprocess morecomplex,buttheadvantageseasilyjustifythisextracomplexity.Inaddition,theuseofa comprehensivedependencyinjectionmechanismcanactuallymakethetaskofdesigningand developingapplicationsmucheasier. Fundamentally,therearetwoapproachestousingadependencyinjectionmechanism: Youcanarrangetohavedependentobjectsautomaticallyinjected,usingtechniquessuchas constructorinjection,property(setter)injection,andmethodcallinjectionthatinject dependentobjectsimmediatelywhenyouinstantiatetheparentobject.Thisapproachis generallymostappropriateforapplicationsthatrequireapluggablearchitectureorwhere youwanttomanagecrosscuttingconcerns. Youcanhaveobjectsinjectedonlyondemand,bycallingtheResolvemethodofthecontainer onlywhenyouneedtoretrieveareferencetoaspecificobject. Thisapproachisknownasservicelocator.Itismoreintrusiveintoyourapplication,butcanbe simplerifyourarchitecturedoesnotlenditselftohavingacentralcontainer.

Inadditiontodependencyinjection,developersmaywishtoimplementpatternssuchas Interception,Decorator,ChainOfResponsibility,andInterceptingFilter,whereacallfromaclientor processpassesthroughagraphofobjects,witheachoneabletoaccessandactupondetailsofthe call,suchasthemethodorpropertyname,theparametertypesandvalues,thereturnedtypeand value,andotherinformation.Unityachievesthisthroughinterceptionofmethodcalls,providing opportunitiestoapplypoliciestoobjectsusingatechniqueoftenreferredtoaspolicyinjection. Unityprovidesacomprehensivedependencyinjectionandinterceptionmechanism,andiseasyto incorporateintoyourapplications.However,itdoeschangethewaythatyoudesignthese applications.Thefollowingsectionsofthistopicdescribeareaswheredependencyinjectionis useful: PluggableArchitectures ManagingCrosscuttingConcerns ServiceandComponentLocation PolicyInjectionthroughInterception

PluggableArchitectures
Bydesigningapplicationstouseapluggablearchitecture,developersanduserscanaddandmodify thefunctionalityofanapplicationwithoutchangingthecorecodeorprocesses.ASP.NETisan exampleofapluggablearchitecture,whereyoucanaddandremoveprovidersforfeaturessuchas
122

authentication,caching,andsessionmanagement.Unityalsofacilitatesapluggablearchitecture thatallowsyoutosubstitutethecontainerforoneofyourowndesignandaddextensionsthrough thecontainerextensionsarchitecture. Byusingdependencyinjectionmechanisms,suchasUnitycontainer,developerscanmapdifferent componentsthatimplementaspecificinterface(suchasaproviderinterface)orthatinheritfroma specificbaseclasstotheappropriateconcreteimplementations.Developerscanthenobtaina referencetotheappropriateprovidercomponentatruntime,withouthavingtospecifyexactly whichimplementationofthecomponentisrequired.Thefollowingsectionsofthistopic,Managing CrosscuttingConcernsandServiceandComponentLocation,showhowyoucanusedependency injectiontocreateinstancesofaspecificclassbasedonarequestforamoregeneralclass(suchas aninterfaceorbaseclassdefinition). Inaddition,theprovidersmayrequireinstancesofothercomponents.Forexample,acaching providermayneedtousetheservicesofacryptographycomponentorservice.Whencomponents requiretheservicesofothercomponents,youcanusedependencyinjectiontoautomatically instantiateandinjectinstancesofthesecomponentsintoacomponent,basedoneither configurationsettingsinthecontaineroroncodewithintheapplication. Formoreinformationabouthowyoucanusedependencyinjectioninthisway,seeUsingInjection Attributes.

ManagingCrosscuttingConcerns
Thefeaturesandtasksimplementedinapplicationsareoftenreferredtoasconcerns.Thetasks specifictotheapplicationarecoreconcerns.Thetasksthatarecommonacrossmanypartsofthe application,andevenacrossdifferentapplications,arecrosscuttingconcerns.Mostlarge applicationsrequireservicessuchaslogging,caching,validation,andauthorization,andtheseare crosscuttingconcerns. Thesimplestwaytocentralizethesefeaturesistobuildseparatecomponentsthatimplementeach oftherequiredfeatures,andthenusethesecomponentswhereverthemanagementofthat concernisrequiredinoneormoreapplications.Byusingdependencyinjectionmechanisms,such asaUnitycontainer,developerscanregistercomponentsthatimplementcrosscuttingconcernsand thenobtainareferencetothecomponentatruntime,withouthavingtospecifyexactlywhich implementationofthecomponentisrequired. Forexample,ifyouhaveacomponentnamedFileLoggerthatperformsloggingtasks,your applicationcaninstantiatethiscomponentusingthenewoperator,asshowninthefollowingcode. C#
FileLoggermyLogger=newFileLogger();

VisualBasic
DimmyLoggerAsNewFileLogger()

Ifyouthenwanttochangetheapplicationtousethenewcomponent,FastFileLogger,youmust changetheapplicationcode.However,ifyouhaveaninterfaceILoggerthatallimplementationsof theloggingcomponentuses,youmightinsteadwritethecodelikethefollowing.


123

C#
ILoggermyLogger=newFileLogger();

VisualBasic
DimmyLoggerAsILogger=NewFileLogger()

However,thisdoesnotsolvetheproblembecauseyoustillmustfindeverywhereinthecodewhere youusednew()tocreateaninstanceofthespecificclass.Instead,youcanuseadependency injectionmechanismtomaptheILoggerinterfacetoaspecificconcreteinstanceofthelogging component,oreventomultipleimplementations,sothattheapplicationcanspecifywhichoneit requires.ThefollowingcodeusesUnitytoregisteramappingforbothadefaulttypeoflogging componentandanamedtypewiththeILoggerinterface.Alternatively,youcanspecifythese mappingsusingtheUnityconfigurationfile. C#


//Createcontainerandregistertypes IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType<ILogger,FileLogger>();//defaultinstance myContainer.RegisterType<ILogger,FastFileLogger>("FastLogger");

VisualBasic
'Createcontainerandregistertypes DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(OfILogger,FileLogger)()'defaultinstance myContainer.RegisterType(OfILogger,FastFileLogger)("FastLogger")

Theapplicationcanthenobtainareferencetothedefaultloggingcomponentusingthefollowing code. C#
ILoggermyLogger=myContainer.Resolve<ILogger>();

VisualBasic
DimmyLoggerAsILogger=myContainer.Resolve(OfILogger)()

Inaddition,theapplicationcanuseavariable(perhapssetinconfigurationoratruntime)tospecify adifferentimplementationoftheloggingcomponentinterfaceasrequired,asshowninthe followingcode. C#


//Retrieveloggertypenamefromconfiguration StringloggerName=ConfigurationManager.AppSettings["LoggerName"].ToString(); ILoggermyLogger=myContainer.Resolve<ILogger>(loggerName);

VisualBasic
'Retrieveloggertypenamefromconfiguration DimloggerNameAsString= ConfigurationManager.AppSettings("LoggerName").ToString() DimmyLoggerAsILogger=myContainer.Resolve(OfILogger)(loggerName)

Formoreinformationaboutregisteringtypes,typemappings,andresolvinginstances,seeResolving Objects.
124

ServiceandComponentLocation
Frequently,applicationsrequiretheuseofservicesorcomponentsthatarespecifictothe application;examplesarebusinesslogiccomponents,dataaccesscomponents,interface components,andprocesscontrollers.Insomecases,theseservicesmaybeinstancebased,sothat eachsectionoftheapplicationoreachtaskrequiresaseparateindividualinstanceoftheservice. However,itisalsocommonforservicestobesingletonbased,sothateveryuseroftheservice referencesthesamesingleinstanceoftheservice. Aservicelocationfacilitymakesiteasyforanapplicationtoobtainareferencetoaserviceor component,withouthavingtospecifywheretolookforthespecificserviceorwhetheritisa singletonbasedoraninstancebasedservice.Byusingdependencyinjectionmechanisms,suchas theUnitycontainer,developerscanregisterservicesintheappropriatewayandthenobtaina referencetotheserviceatruntime,withouthavingtospecifyexactlywhichimplementationofthe serviceisrequiredorwhattypeofinstanceitactuallyis. Forexample,ifyouhaveasingletonserviceclassnamedCustomerDatathatyouinteractwithto readandupdateinformationforanycustomer,yourapplicationobtainsareferencetothisservice usuallybycallingastaticGetInstancemethodoftheservice(whichensuresthatitisasingletonand thatonlyoneinstancecanexist),asshowninthefollowingcode. C#
CustomerDatacData=CustomerData.GetInstance();

VisualBasic
DimcDataAsCustomerData=CustomerData.GetInstance()

Instead,youcanusetheUnitycontainertosettheCustomerDataclasstypewithaspecificlifetime thatensuresitbehavesasasingletonsothateveryrequestfortheservicereturnsthesame instance,asshowninthefollowingcode.Alternatively,youcouldspecifythesemappingsusingthe Unityconfigurationfile. C#


//Createcontainerandregistertypeasasingletoninstance IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType<CustomerData>(newContainerControlledLifetimeManager());

VisualBasic
'Createcontainerandregistertypeasasingletoninstance DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(OfCustomerData)(New ContainerControlledLifetimeManager())

TheapplicationcanthenobtainareferencetothesingleinstanceoftheCustomerDataserviceusing thefollowingcode.Iftheinstancedoesnotyetexist,thecontainercreatesit. C#
CustomerDatacData=myContainer.Resolve<CustomerData>();

VisualBasic
DimcDataAsCustomerData=myContainer.Resolve(OfCustomerData)()
125

Inaddition,perhapsanewCustomerFilecomponentyoudecidetouseinyourapplicationinherits thesamebaseclassnamedCustomerAccessBaseastheCustomerDataservice,butitisnota singletoninstead,itrequiresthatyourapplicationinstantiateaninstanceforeachcustomer.In thiscase,youcanspecifymappingnameswhenyouregisteronecomponentasasingletontypeand onecomponentasaninstancetype(withthedefaulttransientlifetime),andthenusethesame applicationcodetoretrievetherequiredinstance. Forexample,thefollowingcodeshowshowyoucanregistertwonamedmappingsforobjectsthat inheritfromthesamebaseclass,thenatruntimecollectastringvaluefromelsewhereinthe applicationconfigurationthatspecifieswhichofthemappingstouse.Inthiscase,thevaluecomes fromtheAppSettingssectionoftheconfigurationfile.IfthevaluewiththekeyCustomerService containsCustomerDataService,thecodereturnsaninstanceoftheCustomerDataclass.Ifit containsthevalueCustomerFileService,thecodereturnsaninstanceoftheCustomerFileclass. C#
IUnityContainermyContainer=newUnityContainer(); //RegisterCustomerDatatypeasasingletoninstance myContainer.RegisterType<CustomerAccessBase,CustomerData>("CustomerDataService", newContainerControlledLifetimeManager()); //RegisterCustomerFiletypewiththedefaulttransientlifetime myContainer.RegisterType<CustomerAccessBase, CustomerFile>("CustomerFileService"); ... StringserviceName= ConfigurationManager.AppSettings["CustomerService"].ToString(); CustomerAccessBasecData =(CustomerAccessBase)myContainer.Resolve<CustomerAccessBase>(serviceName);

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer() 'RegisterCustomerDatatypeasasingletoninstance myContainer.RegisterType(OfCustomerAccessBase, CustomerData)("CustomerDataService",_ NewContainerControlledLifetimeManager()) 'RegisterCustomerFiletypewiththedefaulttransientlifetime myContainer.RegisterType(OfCustomerAccessBase, CustomerFile)("CustomerFileService") ... DimserviceNameAsString= ConfigurationManager.AppSettings("CustomerService").ToString() DimcDataAsCustomerAccessBase=myContainer.Resolve(Of CustomerAccessBase)(serviceName)

Formoreinformationaboutregisteringtypes,typemappings,andresolvinginstances,seeResolving Objects.Formoreinformationaboutusinglifetimemanagerstocontrolthecreation,lifetime,and disposalofobjects,seeUnderstandingLifetimeManagers.

126

PolicyInjectionthroughInterception
Unityinterceptionwithitsbuiltinpolicyinjectionmoduleenablesyoutoeffectivelycapturecallsto objectsyouresolvethroughtheUnityDIcontainer,andapplyapolicythataddsadditional functionalitytothetargetobject.Typically,youwillusethistechniquetochangethebehaviorof existingobjects,ortoimplementthemanagementofcrosscuttingconcernsthroughreusable handlers.Youcanspecifyhowtomatchthetargetobjectusingawiderangeofmatchingrules,and constructapolicypipelinethatcontainsoneormorecallhandlers. Callstotheinterceptedmethodsorpropertiesofthetargetobjectthenpassthroughthecall handlersintheorderyouaddthemtothepipeline,andreturnthroughtheminthereverseorder. Yourcallhandlerscanaccessthevaluesinthecall,changethesevalues,andcontrolexecutionof thecall.Forexample,thecallhandlersmightauthorizeusers,validateparametervalues,cachethe returnvalue,andshortcutexecutionsothatthetargetmethoddoesnotactuallyexecutewherethis isappropriate. YoucanconfigureUnityforpolicyinjectionbyusingaconfigurationfileatdesigntime,see ConfiguringPolicyInjectionPolicies,orbyusingtheAPIatruntime,seeRegisteringPolicyInjection Components. ThefollowingexampleusestheUnityAPItodemonstratehowyoucanconfigureUnitytoperform interceptiononatargetobject,usingapolicythatcontainsalogginghandlerandavalidation handler.Noticethatthelogginghandlerisaddedfirst,sothatitwilllogcallsevenifvalidationfails andthevalidationhandlershortcutsthepipelineinsteadofcallingthemethodofthetargetobject. YoucanusethestreamlinedpolicydefinitionAPIprovidedbytheUnityinterceptioncontainer extensiontoconfigurethecontaineratruntimeoryoucanspecifythesamebehavioratdesigntime byusingaconfigurationfile.ForanexampleusingtheAPI,seeRegisteringPolicyInjection Components.Foradesigntimeexample,seeConfigurationFilesforInterception. C#
//Createacontainerandaddtheinterceptionextension. IUnityContainermyContainer=newUnityContainer(); myContainer.AddNewExtension<Interception>(); //ConfigurethecontainerwithapolicynamedMyPolicy //thatusesaTypeMatchingRuletomatchacustomclass //andaddsalogginghandlerandavalidationhandler //tothehandlerpipeline.Youmustspecifyatleastone //matchingruleorthepolicywillnotbeapplied. myContainer.Configure<Interception>() .AddPolicy("MyPolicy") .AddMatchingRule<TypeMatchingRule>( newInjectionConstructor("MyCustomType")) .AddCallHandler(typeof(MyLoggingCallHandler)) .AddCallHandler(typeof(MyValidationCallHandler)); //Configurethecontainertointerceptcallstothe //customclassusingaTransparentProxyInterceptor. myContainer.RegisterType<MyCustomType>("myType", newInterceptor<TransparentProxyInterceptor>(),
127

newInterceptionBehavior<PolicyInjectionBehavior>()); //Resolvethecustomtypethroughthecontainerwhen //youarereadytouseit.Whenyoucallamethodor //setapropertyonit,thecallwillpassthrough //thelogginghandlerandthevalidationhandler. MyCustomTypemyNewInstance=myContainer.Resolve<MyCustomType>("myType");

VisualBasic
'Createacontainerandaddtheinterceptionextension. DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.AddNewExtension(OfInterception)() 'ConfigurethecontainerwithapolicynamedMyPolicy 'thatusesaTypeMatchingRuletomatchacustomclass 'andaddsalogginghandlerandavalidationhandler 'tothehandlerpipeline.Youmustspecifyatleastone 'matchingruleorthepolicywillnotbeapplied. myContainer.Configure(OfInterception)()_ .AddPolicy("MyPolicy")_ .AddMatchingRule(OfTypeMatchingRule)(_ newInjectionConstructor("MyCustomType"))_ .AddCallHandler(GetType(MyLoggingCallHandler))_ .AddCallHandler(typeof(MyValidationCallHandler)) 'Configurethecontainertointerceptcallstothe 'customclassusingaTransparentProxyInterceptor. myContainer.RegisterType(OfMyCustomType)(_ NewInterceptor(OfTransparentProxyInterceptor)(),_ NewInterceptionBehavior(OfPolicyInjectionBehavior)()) 'Resolvethecustomtypethroughthecontainerwhen 'youarereadytouseit.Whenyoucallamethodor 'setapropertyonit,thecallwillpassthrough 'thelogginghandlerandthevalidationhandler. DimmyNewInstanceAsMyCustomType=myContainer.Resolve(Of MyCustomType)("myType");

Formoreinformationaboutinterceptionandpolicyinjection,seeUsingInterceptionandPolicy Injection.

AddingUnitytoYourApplication
Unityisdesignedtosupportarangeofcommonscenariosforresolvinginstancesofobjectsthat, themselves,dependonotherobjectsorservices.However,youmustfirstprepareyourapplication touseUnity.Thefollowingproceduredescribeshowtoincludethenecessaryassembliesand elementsinyourcode.
128

Toprepareyourapplication 1. AddareferencetotheUnityassembly.InVisualStudio,rightclickyourprojectnodein SolutionExplorer,andthenclickAddReference.ClicktheBrowsetabandfindthelocation oftheMicrosoft.Practices.Unity.dllassembly.Selecttheassembly,andthenclickOKtoadd thereference. 2. (Optional)Ifyouintendtousetheconfigurationtypeswhenyoucreateextensionsfor Unity,usethesameproceduretosetareferencetotheUnityconfigurationassembly, namedMicrosoft.Practices.Unity.Configuration.dll. 3. (Optional)IfyouintendtousetheinterceptionandpolicyinjectionfeaturesofUnity,use thesameproceduretosetareferencetotheUnityinterceptionassembly,named Microsoft.Practices.Unity.Interception.dll. 4. (Optional)Ifyouintendtousetheconfigurationtypesfortheinterceptionandpolicy injectionfeaturesofUnity,usethesameproceduretosetareferencetotheUnity interceptionconfigurationassembly,named Microsoft.Practices.Unity.Interception.Configuration.dll. 5. (Optional)TouseelementsfromUnitywithoutfullyqualifyingtheelementreference,add thefollowingusingstatements(C#)orImportsstatements(VisualBasic)tothetopofyour sourcecodefileasrequired. C#
usingMicrosoft.Practices.Unity; usingMicrosoft.Practices.Unity.Configuration; usingMicrosoft.Practices.Unity.InterceptionExtension;

VisualBasic
ImportsMicrosoft.Practices.Unity ImportsMicrosoft.Practices.Unity.Configuration ImportsMicrosoft.Practices.Unity.InterceptionExtension

6. (Optional)IfyouareusingtheIServiceLocatorinterface,addareferencetotheservice locationbinaryMicrosoft.Practices.ServiceLocation.dll.VisualStudiomayautomatically copythisfiletoyourbindirectorywhenitcompiles,butyoudonotneedtoincludeitunless youareexplicitlyusingtheUnityServiceLocatorAdapterclass. 7. Addyourapplicationcode.FormoreinformationabouthowyoucanuseUnityinyourown applications,seeWhatDoesUnityDo?

ForVisualBasicprojects,youcanalsousetheReferencespageoftheProjectDesignertomanage referencesandimportednamespaces.ToaccesstheReferencespage,selectaprojectnodein SolutionExplorer,andthenclickPropertiesontheProjectmenu.WhentheProjectDesigner appears,clicktheReferencestab. TherearelimitationswhenusingUnityinapartialtrustenvironment.Formoreinformation,see UsingUnityinPartialTrustEnvironments.


129

DependencyInjectionwithUnity
Ifyouareusingdependencyinjection(DI)throughaDIcontainerapproachtoyourapplication development,youcanuseanyavailableDIcontainerincludingthecontainerprovidedbyUnity. UsingtheUnitydependencyinjectioncontainerprovidesopportunitiesforyoutomoreeasily decouplecomponents,businessobjects,andservicesyouuseinapplications,andcansimplifyhow youorganizeandarchitecttheseapplications. YoucancreateinstancesofobjectsusingtheDIcontainerprovidedbyUnity.Unityisavailableasa standalonedependencyinjectionmechanism. Thefollowingsectionsofthistopicwillhelpyoutounderstandtheoverallprocess,anduseUnity dependencyinjectioninyourapplications: UsingBuildUptoWireUpObjectsNotCreatedbytheContainer.Thistopicexplainshowto useBuildUptopassexistingobjectinstancesthroughthecontainerinordertoapply dependencyinjectiontothatobject.Thisisanalternativetoresolvingtheobjectusinganyof theothertechniquesavailablewithUnity. UsingInjectionAttributes.Thistopiccontainsaseriesofsectionsthatdescribehowyoucan useattributesappliedtomembersoftargetclassestoinstructUnitytoinjectdependent objectsforconstructorandmethodparameters,andasthevaluesofproperties. CircularReferenceswithDependencyInjection.Thistopicdescribeshowyoushouldbeaware ofthepossibilityofcircularreferencesarisingwhenusingdependencyinjectiontechniques.

ResolvingObjects
YoucanusetheUnitycontainertogenerateinstancesofanyobjectthathasapublicconstructor(in otherwords,objectsthatyoucancreateusingthenewoperator),withoutregisteringamappingfor thattypewiththecontainer.WhenyoucalltheResolvemethodandspecifythedefaultinstanceof atypethatisnotregistered,thecontainersimplygeneratesandreturnsaninstanceofthattype. However,theonlytimethatthisisrealisticallypracticaliswhentheobjectyouaregenerating containsdependencyattributesthatthecontainerwillusetoinjectdependentobjectsintothe requestedobject. TheUnitycontaineridentifiestyperegistrationsandtypemappingsinthecontainerusingatype and,optionally,aname.Thetypeisaninterfaceoraclass(usuallyaninterfaceorbaseclass)that thedesiredconcreteobjecttypeimplementsorinherits.Thisidentifiesthemappingsothatthe containercanretrievethecorrectobjecttypeinresponsetoacalltotheResolveorResolveAll method.Wherethereismorethanonemappingforthesametype,theoptionalnamedifferentiates thesemappingsandallowscodetospecifywhichofthemappingsforthattypetouse.
130

TheprovisionofbothgenericandnongenericoverloadsofmanyoftheUnitycontainermethods ensuresthatUnitycanbeusedinlanguagesthatdonotsupportgenerics.Youcanuseeither approach(thegenericorthenongenericoverloads)inyourcodeandmixthemasrequired.For example,youcanregistermappingsusingthegenericoverloadsandthenretrieveobjectinstances usingthenongenericoverloads,andviceversa. Whenyouattempttoresolveanabstractbaseclassorinterfacewherethereisnomatchingtype mappinginthecontainer,Unitywillattempttocreateanewinstanceoftheclassyouspecified.As itcannotconstructandpopulateaninstanceofanabstractclassoraninterface,Unitywillraisean exception. Whenyouattempttoresolveanonmappedconcreteclassthatdoesnothaveamatching registrationinthecontainer,Unitywillcreateaninstanceofthatclassandpopulateany dependencies. ThefollowingtopicsdescribehowyoucanresolveobjectsusingtheResolveorResolveAllmethods: ResolvinganObjectbyType. ResolvinganObjectbyTypeandRegistrationName. ResolvingAllObjectsofaParticularType. ResolvingObjectsbyUsingOverrides RetrievingContainerRegistrationInformation

FormoreinformationabouthowyoucanconfigureUnitywithtyperegistrationsandmappings,see ConfiguringUnity. Formoreinformationabouthowyoucanperformdependencyinjectiononexistingobject instances,seeUsingBuildUptoWireUpObjectsNotCreatedbytheContainer.

ResolvinganObjectbyType
UnityprovidesamethodnamedResolvethatyoucanusetoresolveanobjectbytype,and optionallybyprovidingaregistrationname.Registrationsthatdonotspecifyanamearereferredto asdefaultregistrations.ThistopicdescribeshowtousetheResolvemethodtoresolvetypesand mappingsregisteredasdefaultregistrations.Forinformationaboutresolvingnamedregistrations, seeResolvinganObjectbyTypeandRegistrationName.

131

TheResolveMethodOverloadsforDefaultRegistrations
ThefollowingtabledescribestheoverloadsoftheResolvemethodthatreturninstancesofobjects basedonthedefaultregistrationsandmappingswiththecontainer.TheAPIfortheUnitycontainer containsbothgenericandnongenericoverloadsofthismethodsothatyoucanuseitwith languagesthatdonotsupportthegenericssyntax.
Method Resolve<T>( ) Resolve(Type t) Description Returns an instance of the default type registered with the container as the type T. Returns an instance of the default type registered with the container as the type t.

IfyoucalltheResolvemethodandspecifythedefaultinstanceofatypethatisnotregistered,the containersimplygeneratesandreturnsaninstanceofthattype.However,theonlytimethatthis isusefuliswhentheobjectyouaregeneratingcontainsdependencyattributesthatthecontainer willusetoinjectdependentobjectsintotherequestedobject,oryouwanttointerceptcallstothe objecttoinjectapolicy. IfyouregisteradefaulttypeoradefaulttypemappingmorethanonceusingtheRegisterType method(inotherwords,ifyouregistermorethanonetypeortypemappingthatspecifiesthe sametypesanddoesnotspecifyaregistrationname)onlythelastregistrationremainsinthe containerandisappliedwhenyouexecutetheResolvemethod. Thedefaultregistrationisthesameasaregistrationwherethenameisnulloranemptystring.

UsingtheResolveMethodwithDefaultRegistrations
ThefollowingexamplesshowhowyoucanusetheResolvemethodtocreateorobtainareference toanobjectdefinedinthecontainerconfiguration.Typicallyyouwillregisteratypemapping betweenaninterfaceandaconcretetypethatimplementsit,orbetweenabaseclassanda concretetypethatinheritsit.Theexamplesusetheruntimemethodsofthecontainertoregister thetypesitwillresolve.FormoreinformationabouthowyoucanconfigureUnitywithtype registrationsandmappings,seeConfiguringUnity.

ResolvingTypesRegisteredasInterfaces
ThefollowingcoderegistersamappingforaninterfacenamedIMyServiceandspecifiesthatthe containershouldreturnaninstanceoftheCustomerServiceclass(whichimplementsthe IMyServiceinterface).Inthiscase,thetypeIMyServiceidentifiestheregistrationtype.Codethat requestsaninstanceofthetypeIMyServicereceivesaninstanceoftheCustomerServiceclass.The followingexampleusesthegenericoverloadsofthecontainermethods. C#
132

IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType<IMyService,CustomerService>(); IMyServicemyServiceInstance=myContainer.Resolve<IMyService>();

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(OfIMyObject,CustomerService)() DimmyServiceInstanceAsIMyService=myContainer.Resolve(OfIMyService)()

Alternatively,youcanusethenongenericoverloadsofthemethods.Thefollowingcodeachieves thesameresult. C#
IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType(typeof(IMyService),typeof(CustomerService)); IMyServicemyServiceInstance= (IMyService)myContainer.Resolve(typeof(IMyService));

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(GetType(IMyService),GetType(CustomerService)) DimmyServiceInstanceAsIMyService=myContainer.Resolve(GetType(IMyService))

ResolvingTypesRegisteredasBaseClasses
Whenyouneedtoregisteramappingforabaseclassorotherobjecttype(insteadofaninterface), youusetheoverloadsoftheRegisterTypeandResolvemethodsthatacceptobjecttypenames.The followingexamplesshowtheuseoftheoverloadsoftheRegisterTypeandResolvemethodsthat acceptobjecttypenamesastheregistrationidentifier. ThefollowingcoderegistersamappingforanobjectnamedMyBaseServiceandspecifiesthatthe containershouldreturnaninstanceoftheCustomerServiceclass(whichinheritsfromthe MyBaseServiceclass).Inthiscase,thetypeMyBaseServiceidentifiestheregistration.Codethat requestsaninstanceofthetypeMyBaseServicereceivesaninstanceoftheCustomerServiceclass. C#
IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType<MyBaseService,CustomerService>(); MyBaseServicemyServiceInstance=myContainer.Resolve<MyBaseService>();

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(OfMyBaseService,CustomerService)() DimmyServiceInstanceAsMyBaseService=myContainer.Resolve(OfMyBaseService)()

Alternatively,youcanusethenongenericoverloadsofthemethods.Thefollowingcodeachieves thesameresult. C#
IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType(typeof(MyBaseService),typeof(CustomerService));
133

MyBaseServicemyServiceInstance= (MyBaseService)myContainer.Resolve(typeof(MyBaseService));

VisualBasic
DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(GetType(MyBaseService),GetType(CustomerService)) DimmyServiceInstanceAsMyBaseService= myContainer.Resolve(GetType(MyBaseService))

Ifthetargetclassorobjectspecifiesanydependenciesofitsown,usingconstructor,property,or methodcallinjectionattributes,theinstancereturnedwillhavethesedependentobjectsinjected automatically. Bydefault,theRegisterTypemethodregistersatypewithatransientlifetime,whichmeansthat thecontainerwillnotholdontoareferencetotheobjectsitcreateswhenyoucalltheResolve method.Eachtimeyoucalloneofthesemethods,thecontainergeneratesanewinstanceofthe specifiedormappedtype.However,youcanuselifetimemanagerstocontrolthecreation, lifetime,anddisposalofobjectsifrequired.

ResolvinganObjectbyTypeand RegistrationName
UnityprovidesamethodnamedResolvethatyoucanusetoresolveanobjectbytype,and optionallybyprovidingaregistrationname.Registrationsthatspecifyanamearereferredtoas namedregistrations.ThistopicdescribeshowtousetheResolvemethodtoresolvetypesand mappingsregisteredasnamedregistrations.Forinformationaboutresolvingdefaultregistrations, seeResolvinganObjectbyType.

TheResolveMethodOverloadsforNamedRegistrations
ThefollowingtabledescribestheoverloadsoftheResolvemethodthatreturninstancesofobjects basedonnamedregistrationsandmappingswiththecontainer.TheAPIfortheUnitycontainer containsbothgenericandnongenericoverloadsofthismethodsothatyoucanuseitwith languagesthatdonotsupportthegenericssyntax.
Method Resolve<T>(string name, params ResolverOverride[] resolverOverrides) Description Returns an instance of the type registered with the container as the type T with the specified name and where params provide any constructor overrides for the Resolve calls. Names are case sensitive.

134

Resolve(Type t, string name, params ResolverOverride[] resolverOverrides)

Returns an instance of the default type registered with the container as the type t with the specified name and where params provide any constructor overrides for the Resolve calls. Names are case sensitive.

IfyoucalltheResolvemethodandspecifyanameaswellastheregistrationtype,andthereisno mappingregisteredforthattypeandname,thecontainerwillattempttocreateaninstanceofthe typeyouresolved.Ifthattypeisabaseclassorinterface,whichcannotbeconstructed,Unitywill raiseanexception. Registration(mapping)namesarejuststrings,sotheycancontainspacesifrequired.However, theyarecasesensitive.Forexample,thenamesMymappingandMyMappingwillrefertotwo differentregistrationmappings. Youcanusethesamenamefordifferentregistrationsiftheyregisterdifferentobjecttypes.The keyusedtoretrievearegistrationiseffectivelyacombinationoftheregisteredtypeandthename. Ifyouregisteranamedtypeoranamedtypemappingmorethanonceusingthesametypeand name,onlythelastregistrationremainsinthecontainerandisappliedwhenyouexecutethe Resolvemethod.

UsingtheResolveMethodwithNamedRegistrations
Ifyouneedtoregistermultiplemappingsforthesametype,youcanspecifyanametodifferentiate eachmapping.Then,toretrieveanobjectoftheappropriatetype,youspecifythenameandthe registeredtype.Typicallyyouwillregisteratypemappingbetweenaninterfaceandaconcretetype thatimplementsit,orbetweenabaseclassandaconcretetypethatinheritsit. Thefollowingexamplesshowhowyoucanretrieveconcreteinstancesofregisteredobjectsfroma UnitycontainerusingtheResolvemethodwhenyouhaveregisteredoneormoremappingsfora typeanddifferentiatedthembyname.Theexamplesusetherunmemethodsofthecontainerto registerthetypesitwillresolve.FormoreinformationabouthowyoucanconfigureUnitywithtype registrationsandmappings,seeConfiguringUnity.

ResolvingTypesRegisteredasInterfaces
Thefollowingcodedemonstrateshowyoucanregistertwomappingsforthesameinterfaceclass andhavethecontainerreturntheappropriateobjecttypedependingonthetypeandnameyou specifyinthecalltotheResolvemethod.Thefollowingexampleusesthegenericoverloadsofthe containermethods(thoughyoucanalsousethenongenericmethodoverloads). C#
135

//Createcontainerandregistertypes IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType<IMyService,DataService>("Data"); myContainer.RegisterType<IMyService,LoggingService>("Logging"); //Retrieveaninstanceofeachtype IMyServicemyDataService=myContainer.Resolve<IMyService>("Data"); IMyServicemyLoggingService=myContainer.Resolve<IMyService>("Logging");

VisualBasic
'Createcontainerandregistertypes DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(OfIMyService,DataService)("Data") myContainer.RegisterType(OfIMyService,LoggingService)("Logging") 'Retrieveaninstanceofeachtype DimmyDataServiceAsIMyService=myContainer.Resolve(OfIMyService)("Data") DimmyLoggingServiceAsIMyService=myContainer.Resolve(Of IMyService)("Logging")

ResolvingTypesRegisteredasBaseClasses
Thefollowingcodedemonstrateshowyoucanregistertwomappingsforthesamebaseorother classusingtheoverloadsoftheRegisterTypeandResolvemethodsthataccepttypenames,and thenhavethecontainerreturntheappropriateobjecttypedependingonthetypeandnameyou specifyinthecalltotheResolvemethod.Thisexampleusesthenongenericoverloadsofthe containermethods(thoughyoucanalsousegenericmethodoverloads). C#
//Createcontainerandregistertypes IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType(typeof(MyServiceBase),typeof(DataService),"Data"); myContainer.RegisterType(typeof(MyServiceBase),typeof(LoggingService), "Logging"); //Retrieveaninstanceofeachtype MyServiceBasemyDataService= (MyServiceBase)myContainer.Resolve(typeof(MyServiceBase),"Data"); MyServiceBasemyLoggingService= (MyServiceBase)myContainer.Resolve(typeof(MyServiceBase),"Logging");

VisualBasic
'Createcontainerandregistertypes DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(GetType(MyServiceBase),GetType(DataService),"Data") myContainer.RegisterType(GetType(MyServiceBase),GetType(LoggingService), "Logging") 'Retrieveaninstanceofeachtype DimmyDataServiceAsMyServiceBase=myContainer.Resolve(GetType(MyServiceBase), "Data")
136

DimmyLoggingServiceAsMyServiceBase= myContainer.Resolve(GetType(MyServiceBase),"Logging")

Ifthetargetclassorobjectspecifiesanydependenciesofitsown,usingconstructor,property,or methodcallinjectionattributes,theinstancereturnedwillhavethesedependentobjectsinjected automatically. Bydefault,theRegisterTypemethodregistersatypewithatransientlifetime,whichmeansthat thecontainerwillnotholdontoareferencetotheobjectsitcreateswhenyoucalltheResolve method.Eachtimeyoucalloneofthesemethods,thecontainergeneratesanewinstanceofthe specifiedormappedtype.However,youcanuselifetimemanagerstocontrolthecreation, lifetime,anddisposalofobjects,ifrequired.

ResolvingGenericTypesbyName
Youcanalsoresolvegenerictypesbyname,justasyoudowithnongenerictypes. Youcannotresolveunboundgenerictypes.WhenaninstanceiscreatedbyUnity,concretetype argumentsreplaceallofthegenerictypeparameters. Formoreinformationseethe"ResolvingGenericTypes"sectioninResolvinganObjectbyType. Youcanspecifytheparameterthatdefinesthebaseclassorinterfacetypeyoutoresolveasthe actualtypebyusingtheResolvemethodgenericoverload.Thefollowingexampleassumesthatyou haveregisteredanamedmappingbetweentheIMyServicetypeandaconcretetypenamed MyDataService.TheResolvemethodwillreturnthenamedinstance,Personal,ofthe MyDataServiceclass. C#
varmyInstance=myContainer.Resolve<IMyService>("Personal");

VisualBasic
DimmyInstance=myContainer.Resolve(OfIMyService)("Personal")

MoreInformation
Formoreinformationaboutthetechniquesdiscussedinthistopic,seethefollowing: ConfiguringUnity UsingInjectionAttributes UnderstandingLifetimeManagers

137

ResolvingGenericTypes
Youresolvegenerictypesinmuchthesamewayasyouresolvenongenerictypes.Theprimary differenceiswithunboundtypes.Thespecificationofthetypeargumentsdependonthedefinition ofthemappedtypeorthetypeyouareresolving: Ifthemappedtypeorthetypeyouareresolvingisaboundtype,youcanonlyresolvean instanceofthetypeusingthedefinedtypearguments.Forexample,ifthemappedtypehas typeargumentsoftypestringandDateTime,youmustspecifytheseinthecalltothe Resolvemethod. Ifthemappedtypeorthetypeyouareresolvingisanunboundtype,youcanresolvean instanceofthetypeusinganytypesforthetypearguments.Thetargetclassmustbeable toprocessargumentsofthetypeyouspecify.Forexample,ifoneofthetypearguments youspecifyisthetypeBoolean,theclassmustbeabletohandleBooleanvaluesforthat argumentandnotattempttoparsethevalueintoaDateTimeinstance. Youcannotresolveunboundgenerictypes.Youcanregisteranunboundgenerictypebut youmustspecifyamappingtoaconcretetypethatUnitycanresolve.

Theexamplesinthissectionusethefollowingaliasesandregistrations: XML
<!Generictypealiases> <aliasalias="IMyClosedInterface"type= "TypeMappingsExamples.MyTypes.IMyInterface`2[ System.String,System.DateTime],TypeMappingsExamples"/> <aliasalias="IMyUnboundInterface"type="TypeMappingsExamples. MyTypes.IMyInterface`2,TypeMappingsExamples"/> <aliasalias="MyClosedClass"type="TypeMappingsExamples. MyTypes.MyClass`2[System.String,System.DateTime],TypeMappingsExamples"/> <aliasalias="MyUnboundClass"type="TypeMappingsExamples. MyTypes.MyClass`2,TypeMappingsExamples"/> <containername="container1"> <!Generictypemappings> <registertype="IMyClosedInterface"mapTo="MyClosedClass" name="Closed(String,DateTime)ToClosed(String,DateTime)"/> <registertype="IMyUnboundInterface"mapTo="MyUnboundClass" name="UnboundToUnbound"/> <registertype="IMyUnboundInterface"mapTo="MyClosedClass" name="UnboundToClosed(String,DateTime)"/> </container>

Thefollowingexampleresolvesaninstanceusingclosedgenerictypes. C#
//ResolveclosedIMyInterfacetypeusingtypeparametersStringandDateTime. varresult1=myContainer.Resolve<IMyInterface<string,DateTime>>(
138

"Closed(String,DateTime)ToClosed(String,DateTime)");

VisualBasic
'ResolvetheclosedIMyInterfacetypeusingtypeparametersStringandDateTime. Dimresult1=myContainer.Resolve(OfIMyInterface(OfString,DateTime))(_ "Closed(String,DateTime)ToClosed(String,DateTime)")

Theresultisresolvedthroughthemappingbetweentheclosedtypes,andisvalidbecausethe combinationoftypeargumentssuppliedinthecalltotheResolvemethodmatchesthoseforthe mappingoftheclosedtypes.Unityreturnsthefollowingresult:


'MyClass`2[System.String,System.DateTime]'

Thefollowingexampleresolvesinstancesforunboundgenerictypes. C#
//ResolveunboundIMyInterfacetypeusingtypeparametersIntegerandDecimal. varresult2=myContainer.Resolve<IMyInterface<int,decimal>>( "UnboundToUnbound"); //ResolveunboundIMyInterfacetypeusingtypeparametersStringandDateTime. varresult3=myContainer.Resolve<IMyInterface<string,DateTime>>( "UnboundToClosed(String,DateTime)");

VisualBasic
'ResolvetheunboundIMyInterfacetypeusingtypeparametersIntegerand Decimal. Dimresult2=myContainer.Resolve(OfIMyInterface(OfInteger,Decimal))(_ "UnboundToUnbound") 'ResolvetheunboundIMyInterfacetypeusingtypeparametersStringand DateTime. Dimresult3=myContainer.Resolve(OfIMyInterface(OfString,DateTime))(_ "UnboundToClosed(String,DateTime)")

Theexamplesreturnthefollowingresults:
Resolvingwiththemapping'UnboundToUnbound' Unityreturns'MyClass`2[System.Int32,System.Decimal]' ResolvingIMyInterfaceusingthemapping'UnboundToClosed(String,DateTime)' Unityreturns'MyClass`2[System.String,System.DateTime]'

TheUnboundToUnboundexamplereturnsaclosedinstance.ThecalltotheResolvemethod specifiestheuseofthemappingbetweentheunboundtypes.However,asthecalltothismethod includesthedefinitionofthetypearguments,Unitywillresolveaninstanceoftheclosedtype.The typesusedforthetypeargumentsinthecalltotheResolvemethodcanbeanytypethatthetarget classcanprocess.

139

TheUnboundToClosedexamplecallisresolvedthroughthemappingsbetweentheunbound interfaceandaclosedtype.ThecalltotheResolvemethodspecifiestheappropriatetypesforthe closedtypesthatwillbereturned.

MoreInformation
Formoreinformationaboutthetechniquesdiscussedinthistopic,seethefollowing: ConfiguringUnity UsingInjectionAttributes UnderstandingLifetimeManagers

ResolvingAllObjectsofaParticular Type
Whenyouwanttoobtainalistofalltheregisteredobjectsofaspecifictype,youcanusethe ResolveAllmethod.Thetwooverloadsofthismethodaccepteitheraninterfaceoratypename, andtheyreturnaninstanceofIEnumerablethatcontainsreferencestoallregisteredobjectsofthat typethatarenotdefaultmappings.ThelistreturnedbytheResolveAllmethodcontainsonlynamed instanceregistrations.TheResolveAllmethodisusefulifyouhaveregisteredmultipleobjector interfacetypesusingthesametypebutdifferentnames.Youcanalsousetheparamstoprovide constructoroverridesfortheResolveAllcalls.

TheResolveAllMethodOverloads
ThefollowingtableshowstheoverloadsoftheResolveAllmethod.Youcanonlyrequestalistof objectsusingtheobjecttype.TheAPIfortheUnitycontainercontainsbothgenericandnongeneric overloadsofthismethodsothatyoucanuseitwithlanguagesthatdonotsupportthegenerics syntax.
Method ResolveAll<T>( params ResolverOverride[] resolverOverrides) Description Returns a list of IEnumerable<T>, where T is the type registered as a non-default mapping with the container as the type T and where params provide any constructor overrides for the ResolveAll calls. Returns a list of IEnumerable<object>, where object is the type registered as a non-default mapping with the container as the type t and where params provide any constructor overrides for the ResolveAll calls.

ResolveAll(Type t, params ResolverOverride[] resolverOverrides)

140

Itisimportanttorememberthatyoumustregistertypemappingsusinganameinadditiontothe registrationtype(whichidentifiestheregistration)ifyouwanttobeabletoretrievealistof mappedtypesusingtheResolveAllmethod.Inotherwords,youmustuseoverloadsofthe RegisterTypeandRegisterInstancemethodsthattakeaname(asaString)andthedependency type,orspecifythenameinyourconfigurationoftypemappings.Thisbehaviorisbydesign.The expectationisthatyouwilleitheruseonlynamedmappingsoruseonlydefaultmappings. Ifyouregisteranamedtypeoranamedtypemappingmorethanonceusingthesametypeand name,onlythelastregistrationremainsinthecontainerandisappliedwhenyouexecutethe ResolveAllmethod.Ifthecontainerdoesnotcontainanynamed(nondefault)mappingsforthe specifiedtype,itwillreturnnull(inC#)orNothing(inVisualBasic).

UsingtheResolveAllMethod
Thefollowingexamplesshowhowyoucanretrievealistofallregisteredtypesforaspecific registrationtype.Theyusetheruntimemethodsofthecontainertoregisterthetypesitwill resolve.FormoreinformationabouthowyoucanconfigureUnitywithtyperegistrationsand mappings,seeConfiguringUnity. C#
//Createcontainerandregistertypesusinganameforeachone IUnityContainermyContainer=newUnityContainer(); myContainer.RegisterType<IMyService,DefaultService>(); myContainer.RegisterType<IMyService,DataService>("Data"); myContainer.RegisterType<IMyService,LoggingService>("Logging"); //RetrievealistofnondefaulttypesregisteredforIMyService //ListwillonlycontainthetypesDataServiceandLoggingService IEnumerable<IMyService>serviceList=myContainer.ResolveAll<IMyService>();

VisualBasic
'Createcontainerandregistertypesusinganameforeachone DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(OfIMyService,DefaultService)() myContainer.RegisterType(OfIMyService,DataService)("Data") myContainer.RegisterType(OfIMyService,LoggingService)("Logging") 'RetrievealistofnondefaulttypesregisteredforIMyService 'ListwillonlycontainthetypesDataServiceandLoggingService DimserviceListAsIEnumerable(OfIMyService)=myContainer.ResolveAll(Of IMyService)

Alternatively,youcanusethenongenericmethodsofthecontainertoachievethesameresult, exceptthatthereturnvaluethistimeisanIEnumerablelistoftypeObject. C#
//Createcontainerandregistertypesusinganameforeachone IUnityContainermyContainer=newUnityContainer();
141

myContainer.RegisterType(typeof(MyServiceBase),typeof(DefaultService)); myContainer.RegisterType(typeof(MyServiceBase),typeof(DataService),"Data"); myContainer.RegisterType(typeof(MyServiceBase),typeof(LoggingService), "Logging"); //RetrievealistofnondefaulttypesregisteredforMyServiceBase //ListwillonlycontainthetypesDataServiceandLoggingService foreach(ObjectmappinginmyContainer.ResolveAll(typeof(MyServiceBase))) { MyServiceBasemyService=(MyServiceBase)mapping; }

VisualBasic
'Createcontainerandregistertypesusinganameforeachone DimmyContainerAsIUnityContainer=NewUnityContainer() myContainer.RegisterType(GetType(MyServiceBase),GetType(DefaultService)) myContainer.RegisterType(GetType(MyServiceBase),GetType(DataService),"Data") myContainer.RegisterType(GetType(MyServiceBase),GetType(LoggingService), "Logging") 'RetrievealistofnondefaulttypesregisteredforMyServiceBase 'ListwillonlycontainthetypesDataServiceandLoggingService ForEachmappingAsObjectInmyContainer.ResolveAll(GetType(MyServiceBase)) DimmyServiceAsMyServiceBase=CType(mapping,MyServiceBase) Next

ResolvingAllGenericTypesbyName
YoucanusetheResolveAllmethodwithgenerictypes,justasyoudowithnongenerictypes,to retrieveanenumerablelistofresolvedinstancesforallofthenamedmappingsforagenerictype. However,alloftheregistrationsormappingsmustresolvetoatypethathasthesamesetoftype arguments,andyoumustspecifythesetypeargumentsinthecalltotheResolveAllmethod. Whereyouresolveaclosedtype,andtherearebothunboundandclosedregistrationsinthe containerthatpotentiallymatchthetypeyouareresolving,Unitywillpreferentiallyusethe registrationortypemappingdefinedfortheclosedgenerictyperatherthantheunboundone. FormoreinformationseeResolvingAllObjectsofaParticularType.

ResolvingObjectsbyUsingOverrides
Theparameteranddependencyoverrides,ParameterOverrideandDependencyOverride,are ResolverOverrideimplementationsthatprovidesupportforoverridingtheregistrationinformation forresolvinginstancesoftypes.WhenyoucalltheResolvemethod,theseclassesenableyouto
142

overridevaluesspecifiedwhenthetypewasregistered,suchasbyaRegisterTypeor RegisterInstancestatement.Ineffect,RegisterTypesuppliedvaluesareoverriddenbyResolve suppliedvalues. UseParameterOverridetooverridethespecifiedconstructorparameterorparameters.The overrideapplieseverywheretheparameterappearsunlessyouuseOnTypetoconstrainthe overridetoaspecifiedtype.Sincethepurposeofoverridesistoaffecttheresolutionof dependenciesforallrelevantcreatedobjects,notjusttheobjectrequestedinthecalltoResolve, unconstrainedoverridescanproduceerrorsifthereareunconstrainedParameterOverride parametersthatmatchparameterswiththesamenamebutdifferenttypesontheselected constructorsforobjectscreatedinagivenresolveoperation. UsePropertyOverridetooverridethevalueofthespecifiedpropertyorproperties.Theoverride applieseverywherethepropertyappearsunlessyouuseOnTypetoconstraintheoverridetoa specifiedtype. UseDependencyOverridetooverridethevalueinjectedwheneverthereisadependencyofthe giventype.DependencyOverrideoverridesallinstanceswherethetypematches.Bothparameter overridesanddependencyoverridessupportgenerictypesandmultipleoverrides. IftheoverriddenobjectwaspreviouslycreatedandisaSingleton,theoverrideisignored.The lifetimemanagertakesprecedenceandSingletonsalwaysreturnthesameinstance. Thecontainerdoesnotstoreareferencefortheoverriddenobject. Overridesworkwiththeconstructorthatisselectedforthetype,byattributeorconfiguration.Ifthe constructortobeusedisnotidentifiedwithanattributeorexplicitcontainerconfiguration,thenthe defaultbehavioristhattheconstructorwiththemostparameterswillbeused. Aparameterandpropertyoverrideneveraffectswhatelementgetsselected.Theyonlycontrolthe valueofthespecifiedparameterorproperty.Youdonotchangewhichconstructoriscalledwithan override,andyoudonotchangewhichpropertiesgetsetwithanoverride. Ifthepropertyisnotsetasadependencythroughattribute,containerAPI,orconfigurationfile, thentheoverridedoesnothing. Thistopiccontainsthefollowingsectionstoexplainoverridesinmoredetail: UsingParameterOverrides UsingPropertyOverrides UsingDependencyOverrides MoreInformation

143

UsingParameterOverrides
ParameterOverrideenablesyoutopassinvaluesforconstructorparameterstooverridea parameterpassedtoagivennamedconstructor.Onlytheparametervalueisoverridden,notthe constructor. ParameterOverridecanbeusedonlyforconstructors. ThefollowingcodeconstrainstheoverridetotheNewCarinstance. C#
varanInstance=container.Resolve<ClassCar>(newParameterOverride("car","new car").OnType<NewCar>());

VisualBasic
DimanInstance=container.Resolve(OfClassCar)(NewParameterOverride("car","new car").OnType(OfNewCar)())

Iftheparameterdoesnotexist,thentheoverrideisignored. Whentheparametersyousettooverridedonotmatchtheconstructorsignature,thenthedefault parametervaluessetduringregistrationareused. Youcanoverridetheconstructorparametersbutnottheconstructor. ThetwoparametersforParameterOverride(parameterName,andparameterValue),specifythe nameoftheparametertooverrideandthevaluetousefortheparameter,respectively.Inthe followingexamplethevalueExpectedValueoverridestheconstructor'svaluefortheconstructor's parameterxforthetypeMyObject.TheOnTypemethodenablesyoutooptionallyspecifyatypeto constraintheoverrideto. C#


//Arbitraryvalues constintConfiguredValue=15; constintExpectedValue=42; //Createacontainerandregistertype"MyObject" varcontainer=newUnityContainer() .RegisterType<MyObject>(newInjectionConstructor(ConfiguredValue)); //Overridetheconstructorparameter"x"value //Use"ExpectedValue"insteadof"ConfiguredValue" varresult=container.Resolve<MyObject>( newParameterOverride("x",ExpectedValue) .OnType<MyOtherObject>());

VisualBasic
144

'Arbitraryvalues ConstConfiguredValueAsInteger=15 ConstExpectedValueAsInteger=42 'Createacontainerandregistertype"MyObject" Dimcontainer=NewUnityContainer().RegisterType(OfMyObject)(New InjectionConstructor(ConfiguredValue)) 'Overridetheconstructorparameter"x"value 'Use"ExpectedValue"insteadof"ConfiguredValue" Dimresult=container.Resolve(OfMyObject)(_ NewParameterOverride("x",ExpectedValue)_ .OnType(OfMyOtherObject)())

Unityalsosupportsoverridingmultipleparametersandtheuseofgenerics. ParameterOverridesisaconvenienceformofParameterOverridethatletsyouspecifymultiple parameteroverridesinonestatementratherthanhavingtoconstructmultipleobjects,oneforeach override.Thefollowingexampleoverridesthetwoparameters,yandx,withExpectedValue. C#


constintExpectedValue=42; varcontainer=newUnityContainer(); varresult=container.Resolve<MyObject>( newParameterOverrides { {"y",ExpectedValue*2}, {"x",ExpectedValue} } .OnType<MyOtherObject>());

ForVisualBasic.NETyoumusteitherusediscreteParameterOverrideobjectsinsteadofthe groupedone,ordosomethinglikethefollowing: VisualBasic


ConstExpectedValueAsInteger=42 Dimcontainer=NewUnityContainer() DimoverridesasnewParameterOverrides Withoverrides .Add("y",ExpectedValue*2) .Add("x",ExpectedValue) EndWith Dimresult=container.Resolve(OfMyObject)(overrides.OnType(OfMyOtherObject)())

Thiscouldbeusefulincaseswhereyourobjectcontainsbothentitiesandservices.Youmightwish tochangeanentity,buttheserviceisfineasis.Forexample,youcouldprocessaseriesof customersandtheirinformationfromyourdatabaseandwanttologtheprocess.Youhavethe followingclasswhereIErrorLoggerloggerandIDataAccessdbareservices. C#


classCustomer {
145

publiccustomer(System.Int32id,System.Stringname,IErrorLoggerlogger, IDataAccessdb) { } }

VisualBasic
ClassCustomer PrivateFunctioncustomer(ByValidAsSystem.Int32,ByValnameAs System.String,_ ByValloggerAsIErrorLogger,ByValdbAs IDataAccess) EndFunction EndClass

Ifyouregisterthetypeandspecifytheidandnameforacustomer,saySam,then container.Resolve<Customer>willresolvewithSameverytime.Whatyoureallywantasyou processcustomersinyourdatabaseistoresolveadifferentcustomereverytimeyouuse container.Resolve<Customer>. Usingthepluralform,ParameterOverrides,youcanoverridejusttherelevantparametersforthe constructor.Yourobjectwillhavetheservicesandyouwillhaveanewcustomertoworkwith. C#


container.Resolve<Customer>( newParameterOverrides { {"id",userform.id}, {"name","Bob"} }.OnType<Customer>() );

VisualBasic.NETlacksthedictionaryinitializationsyntaxtoaccomplishthesamething.Youmust eitherusediscreteParameterOverrideobjectsinsteadofthegroupedone,ordosomethinglikethe following: VisualBasic


DimoverridesasnewParameterOverrides Withoverrides .Add("id",userform.id) .Add("name","Bob") EndWith Dimresult=container.Resolve(Ofcustomer)(overrides.OnType(OfCustomer)))

146

UsingPropertyOverrides
PropertyOverrideenablesyoutooverridethevalueforaspecifiedproperty.Onlytheproperty valueisoverridden,notthepropertiesselected.ItsbehavioristhesameasParameterOverride.The useoftheOnTypemethodenablesyoutospecifyatypetoconstraintheoverrideto. Thefollowingcodespecifiesavalue,overrideValue,tousetooverridetheinjectedpropertyvalue, defaultObject. C#
container.RegisterType<TargetTypeForInjection>( newInjectionProperty("InjectedObject",defaultObject)); varresult1=container.Resolve<TargetTypeForInjection>( newPropertyOverride("InjectedObject",overrideValue));

VisualBasic
container.RegisterType(OfTargetTypeForInjection)(_ NewInjectionProperty("InjectedObject",defaultObject)) Dimresult1=container.Resolve(OfTargetTypeForInjection)(_ NewPropertyOverride("InjectedObject",overrideValue))

ThefollowingcodeconstrainstheoverridetotheTargetType2instancebyinvokingOnType. C#
varresult=container.Resolve<TargetTypeForInjection>( newPropertyOverride("InjectedObject",overrideObject) .OnType<TargetType2>());

VisualBasic
Dimresult=container.Resolve(OfTargetTypeForInjection)(_ NewPropertyOverride("InjectedObject",overrideObject)_ .OnType(OfTargetType2)())

Ifthepropertyisnotsetasadependencythroughanattribute,thecontainerAPI,orbya configurationfile,thentheoverridehasnoeffect. PropertyOverridesisaconvenienceformofPropertyOverridethatletsyouspecifymultiple propertyoverridesinonestatementratherthanhavingtoconstructmultipleobjects,oneforeach override.ItsbehavioristhesameasParameterOverrides.Thefollowingexampleoverridesthe valuesforthreepropertiesofMyObjectandconstrainstheoverridestoMyOtherObjectbyusing OnType. C#


returncontainer.Resolve<MyObject>( newPropertyOverrides { {"Property1",Value1}, {"Property2",Value2}, {"Property3",Value3}
147

} .OnType<MyOtherObject>() );

ForVisualBasic.NETyoumusteitherusediscretePropertyOverrideobjectsinsteadofthegrouped one,ordosomethinglikethefollowing: VisualBasic


DimoverridesasnewPropertyOverrides Withoverrides .Add("Property1",Value1) .Add("Property2",Value2) .Add("Property3",Value3) EndWith Dimresult=container.Resolve(OfMyObject)(overrides.OnType(OfMyOtherObject)())

UsingDependencyOverrides
DependencyOverrideenablesyoutospecifyanoverrideoftheregisteredvalueinjectedforthe specifieddependencytype,andenablesyoutopassinadifferentobjectthatwillbeprovidedby type.TheuseoftheOnTypemethodenablesyoutoconstraintheoverridetoaspecifiedtypewith thedependencyinsteadofbeingpropagatedthroughoutalltypeswiththedependency. DependencyOverridewillbeineffecteverywherethespecifieddependencytypeshowsupand thereisanexacttypematch. ThetwoparametersforDependencyOverride,typeToConstructanddependencyValue,specifythe Typeofthedependencytoconstructandthevaluetousefortheparameterrespectively.Overriding nameddependenciesisnotsupported.Youshouldnottrytooverrideanameddependencyifthere isadefaultregistrationforthatnameddependency. Thevaluesfordependencyoverridesareinterpretedusingthesamerulesusedforvaluesin constructor,property,andmethodinjection.TheserulesaredescribedinRegisteringInjected ParameterandPropertyValues.Sofordependencyoverridesifyouwishtosupplyaninstanceof theTypeclasstobeusedasaliteralargumentyoumustinjectanInjectionParameterwiththeType object,otherwisetheoverridetypeisresolvedinthecontainerasaninstanceofthesuppliedtype (seerule#2inRegisteringInjectionforParameters,Properties,andMethodsusing InjectionMembersfordetails). C#
classCars { publicCars(TypetypeObject) {...} }

VisualBasic
ClassCars PublicSubNew(ByValtypeObjectAsType)
148

... EndSub EndClass

InthefollowingexampletheoverridewillapplytoparametersoftypeType,replacingthe container'sconfigurationwitharesolvedinstanceoftypeint. C#
container.Resolve<Cars>(newDependencyOverride(typeof(Type),typeof(int)));

VisualBasic
container.Resolve(OfCars)(NewDependencyOverride(GetType(Type), GetType(Integer)))

Inthefollowingexample,thesuppliedinstanceoftheTypeclasswillbeusedasaliteralargument andyourintentisexplicit. C#
container.Resolve<Cars>(newDependencyOverride(typeof(Type), newInjectionParameter(typeof(int))));

VisualBasic
container.Resolve(OfCars)(NewDependencyOverride(GetType(Type),_ NewInjectionParameter(GetType(Integer))))

YoucannotusetheGenericParametersasvaluesforoverridessincetheyinheritfrom InjectionParameterValueanddonotmakesensewhenresolving.Theyonlymakesensewhen configuringanunboundgenerictypewithRegisterType. ThefollowingexamplecreatesaninstanceofDependencyOverridetooverridethegiventypewith thegivenvalue.FirstObjectisthetypetooverrideandoverrideValueisthevalueusedforthe override. C#


varcontainer=newUnityContainer() .RegisterType<ObjectDependentOnFirstObject>( newInjectionProperty("OtherObject")) .RegisterType<FirstObject>(newInjectionConstructor()); //UseanarbitraryvaluefortheoverrideValueobject varoverrideValue=newFirstObject(15); varresult=container.Resolve<ObjectDependentOnFirstObject>( newDependencyOverride<FirstObject>(overrideValue));

VisualBasic
Dimcontainer=NewUnityContainer()_ .RegisterType(OfObjectDependentOnFirstObject)(_ NewInjectionProperty("OtherObject"))_ .RegisterType(OfFirstObject)(NewInjectionConstructor())
149

'UseanarbitraryvaluefortheoverrideValueobject DimoverrideValue=NewFirstObject(15) Dimresult=container.Resolve(OfObjectDependentOnFirstObject)(_ NewDependencyOverride(OfFirstObject)(overrideValue))

WhereFirstObjectandObjectDependentOnFirstObjectaredefinedasfollows: C#
publicclassFirstObject { publicFirstObject() {} publicFirstObject(intx) { X=x; } publicintX{get;privateset;} } publicclassObjectDependentOnFirstObject { publicFirstObjectTestObject{get;set;} publicObjectDependentOnFirstObject(FirstObjecttestObject) { TestObject=testObject; } publicFirstObjectOtherObject{get;set;} }

VisualBasic
PublicClassFirstObject PublicSubNew() EndSub PublicSubNew(ByValx__1AsInteger) X=x__1 EndSub Private_XAsInteger PublicPropertyX()AsInteger Get Return_X EndGet PrivateSet(ByValvalueAsInteger) _X=value EndSet
150

EndProperty EndClass PublicClassObjectDependentOnFirstObject Private_TestObjectAsFirstObject PublicPropertyTestObject()AsFirstObject Get Return_TestObject EndGet Set(ByValvalueAsFirstObject) _TestObject=value EndSet EndProperty PublicSubNew(ByValtestObject__1AsFirstObject) TestObject=testObject__1 EndSub Private_OtherTestObjectAsFirstObject PublicPropertyOtherObject()AsFirstObject Get Return_OtherObject EndGet Set(ByValvalueAsFirstObject) _OtherObject=value EndSet EndProperty EndClass

DependencyOverridesisaconvenienceformofDependencyOverridethatletsyouspecify multipledependencyoverridesinoneshotratherthanhavingtoconstructmultipleobjects. Youmustspecifyeachtypetobeoverriddenandthevaluetousefortheoverride.The followingexamplewilloverrideFirstObjectandSecondObjectwithoverrideValue1and overrideValue2,respectively. C#


varcontainer=newUnityContainer() .RegisterType<ObjectDependentOnFirstObject>( newInjectionProperty("OtherObject")) .RegisterType<FirstObject>(newInjectionConstructor()); //UseanarbitraryvaluefortheoverrideValueobjects varoverrideValue1=newFirstObject(15); varoverrideValue2=newFirstObject(25); varresult=container.Resolve<ObjectDependentOnFirstObject>( newDependencyOverrides { {typeof(FirstObject),overrideValue1},
151

{typeof(SecondObject),overrideValue2}, } );

ForVisualBasic.NETyoumusteitherusediscreteDependencyOverrideobjectsinsteadof thegroupedone,ordosomethinglikethefollowing: VisualBasic


Dimcontainer=NewUnityContainer()_ .RegisterType(OfObjectDependentOnFirstObject)(_ NewInjectionProperty("OtherObject"))_ .RegisterType(OfFirstObject)(NewInjectionConstructor()) 'UseanarbitraryvaluefortheoverrideValueobjects DimoverrideValue1=NewFirstObject(15) DimoverrideValue2=NewFirstObject(25) DimoverridesasnewDependencyOverrides Withoverrides .Add("FirstObject",overrideValue1) .Add("SecondObject",overrideValue2) EndWith Dimresult=container.Resolve(OfObjectDependentOnFirstObject)(overrides)

DependencyOverride<T>isaconvenienceoverloadofDependencyOverridethatletsyou specifythedependencytypeusinggenericsyntax.Thefollowingexampleusesageneric versionofDependencyOverridethatspecifiesthetypetheconstructorisforasageneric parameter,typeT(whereTisagenericfortheType). C#


varresult=container.Resolve<ObjectDependentOnT>( newDependencyOverride<T>(overrideValue));

VisualBasic
Dimresult=container.Resolve(OfObjectDependentOnT)(_ NewDependencyOverride(OfT)(overrideValue))

Moreinformation
Formoreinformationaboutthetechniquesdiscussedinthistopic,seethefollowing: ResolvingObjects ConfiguringUnity UsingInjectionAttributes

DeferringtheResolutionofObjects
152

Unityprovidesatechniquetofacilitateholdingareferencetoanobjectyouneed,butdonotwant toconstructrightaway.Youwishtodeferresolutionoftheobject.Insteadofcreatingafactoryfor thetypeandinjectingthefactoryintoyourclass,thenusingittocreatethetypeyouwantyoucan usethe.NETstandardtypeFunc<T>(C#)orFunc(OfT)(VisualBasic)withtheResolvemethod.This returnsadelegatethat,wheninvoked,callsintothecontainerandreturnsaninstanceofthe specifiedtype(inthiscase,T). Youcanevencreateadelegateinthiswaywithoutcreatingaregistrationormappingforthe specifiedtypeinthecontainerifyouwish.Becausetheresolveactiononlytakesplacewhenyou invokethedelegate,subsequentregistrationsaddedtothecontainerareavailablewhenthetarget objectisresolved.Thismeansthatyoucanmanipulatetheregistrationsandmappingsinthe containeratanypointbeforeyouresolvethetargetobject(althoughyoucanobviouslyregisterthe typebeforeyoucreatethedelegateifyouprefer). Forexample,youcancreateadelegateforacomponentnamedMyClass,andthenregistera mappingforitandperformdeferredresolutionwhenrequiredusingthefollowingcode. C#
//CreateaUnitycontainer IUnityContainermyContainer=newUnityContainer(); //CreateadelegatefortheIMyClassinterfacetype varresolver=myContainer.Resolve<Func<IMyClass>>(); //...othercodehere... //RegisteramappingfortheIMyClassinterfacetotheMyClasstype myContainer.RegisterType<IMyClass,MyClass>(); //Resolvethemappedtargetobject IMyClassmyClassInstance=resolver();

VisualBasic
'CreateaUnitycontainer DimmyContainerAsIUnityContainer=NewUnityContainer() 'CreateadelegatefortheIMyClassinterfacetype Dimresolver=myContainer.Resolve(OfFunc(OfIMyClass))() '...othercodehere... 'RegisteramappingfortheIMyClassinterfacetotheMyClasstype myContainer.RegisterType(OfIMyClass,MyClass)() 'Resolvethemappedtargetobject DimmyClassInstanceAsIMyClass=resolver()

YoucanusethisapproachwhenyouresolvethetypeusingtheResolvemethod,oryoucanspecify thedelegatewhenyouconfigureconstructor,propertysetter,ormethodcallinjection.Youcanalso usenamed(nondefault)registrationsbyincludingtheregistrationnameinthecalltotheResolve methodandtheRegisterTypemethod,justasyouwouldwhenusingthesemethodsfornon deferredresolution.


153

Inaddition,youcanusethisfeaturetoperformdeferredresolutionofmultiplenamedregistrations, asanalternativetousingtheResolveAllmethod.Forexample,ifyouhavemultiplenamed registrationsfortheIMyClassinterfacetosuitableconcretetypes,youcanobtainacollectionofthe resolvedtypes.Thefollowingcodeillustratesthis. C#


//CreateaUnitycontainer IUnityContainermyContainer=newUnityContainer(); //CreateanIEnumerableresolverfortheIMyClassinterfacetype varresolver=myContainer.Resolve<Func<IEnumerable<IMyClass>>>(); //...othercodehere... //RegistermappingsfortheIMyClassinterfacetoappropriateconcretetypes myContainer.RegisterType<IMyClass,FirstClass>("First"); myContainer.RegisterType<IMyClass,SecondClass>("Second"); myContainer.RegisterType<IMyClass,ThidClass>("Third"); //Resolveacollectionofthemappedtargetobjects IEnumerable<IMyClass>myClassInstances=resolver();

VisualBasic
'CreateaUnitycontainer DimmyContainerAsIUnityContainer=NewUnityContainer() 'CreateanIEnumerableresolverfortheIMyClassinterfacetype Dimresolver=myContainer.Resolve(OfFunc(OfIEnumerable(OfIMyClass)))() '...othercodehere... 'RegistermappingsfortheIMyClassinterfacetoappropriateconcretetypes myContainer.RegisterType(OfIMyClass,FirstClass)("First") myContainer.RegisterType(OfIMyClass,SecondClass)("Second") myContainer.RegisterType(OfIMyClass,ThidClass)("Third") 'Resolveacollectionofthemappedtargetobjects DimmyClassInstancesAsIEnumerable(OfIMyClass)=resolver()

Youcanalsousethedeferredresolvertoresolveinstanceregistrations.Forexample,thefollowing codeshowshowyoucanresolveanIEnumerablecollectionofstringvalues. C#
//CreateaUnitycontainer IUnityContainermyContainer=newUnityContainer(); //CreateanIEnumerableresolverforstringinstanceregistrations varresolver=myContainer.Resolve<Func<IEnumerable<string>>>(); //...othercodehere... //RegistermappingsfortheIMyClassinterfacetoappropriateconcretetypes
154

myContainer.RegisterInstance("one","FirstString"); myContainer.RegisterInstance("two","SecondString"); myContainer.RegisterInstance("three","ThirdString"); //Resolveacollectionofthestrings IEnumerable<string>myStringInstances=resolver();

VisualBasic
'CreateaUnitycontainer DimmyContainerAsIUnityContainer=NewUnityContainer() 'CreateanIEnumerableresolverforstringinstanceregistrations Dimresolver=myContainer.Resolve(OfFunc(OfIEnumerable(OfString)))() '...othercodehere... 'RegistermappingsfortheIMyClassinterfacetoappropriateconcretetypes myContainer.RegisterInstance("one","FirstString") myContainer.RegisterInstance("two","SecondString") myContainer.RegisterInstance("three","ThirdString") 'Resolveacollectionofthestrings DimmyStringInstancesAsIEnumerable(OfString)=resolver()

RetrievingContainerRegistration Information
Youcanretrievealistofregistrationsfromacontainer,andcheckifaspecificregistrationisinthe container. Thistopiccontainsthefollowingsections: ViewingtheContainerRegistrationsandMappings CheckingfortheExistenceofaSpecificRegistration

ViewingtheContainerRegistrationsandMappings
TheUnitycontainerexposestheRegistrationspropertywhichreturnsanIEnumerablelistofthe registrationswithinthatcontainer.EachregistrationisaninstanceoftheContainerRegistration class,whichexposesinformationsuchastheregisteredtype,theregistrationname(ifany),the mappedtype(ifany),andthelifetimemanagerthattheregistrationuses. Thefollowingexampleusesthisfeaturetodisplaythecontentsofacontainer.ItqueriestheCount() extensionmethodforIEnumerable<T>,andtheniteratesthroughitdisplayingalistofthe registrationsandmappings.
155

C#
voidDisplayContainerRegistrations(IUnityContainertheContainer) { stringregName,regType,mapTo,lifetime; Console.WriteLine("Containerhas{0}Registrations:", theContainer.Registrations.Count()); foreach(ContainerRegistrationitemintheContainer.Registrations) { regType=item.RegisteredType.Name; mapTo=item.MappedToType.Name; regName=item.Name??"[default]"; lifetime=item.LifetimeManagerType.Name; if(mapTo!=regType) { mapTo=">"+mapTo; } else { mapTo=string.Empty; } lifetime=lifetime.Substring(0,lifetime.Length"LifetimeManager".Length); Console.WriteLine("+{0}{1}'{2}'{3}",regType,mapTo,regName,lifetime); } }

VisualBasic
SubDisplayContainerRegistrations(ByValtheContainerAsIUnityContainer) DimregNameAsString,regTypeAsString,_ mapToAsString,lifetimeAsString Console.WriteLine("Containerhas{0}Registrations:",_ theContainer.Registrations.Count()) ForEachitemAsContainerRegistrationIntheContainer.Registrations regType=item.RegisteredType.Name mapTo=item.MappedToType.Name regName=If(item.Name,"[default]") lifetime=item.LifetimeManagerType.Name IfmapTo<>regTypeThen mapTo=">"&mapTo Else mapTo=String.Empty EndIf lifetime=lifetime.Substring(_ 0,lifetime.Length"LifetimeManager".Length) Console.WriteLine("+{0}{1}'{2}'{3}",_ regType,mapTo,regName,lifetime) Next EndSub

TheNamepropertyofaContainerRegistrationinstancereturnsnull(C#)orNothing(VisualBasic) fordefault(unnamed)registrations.TheMappedToTypepropertyhasthesamevalueasthe RegisteredTypewhenthisisanonmappedconcretetyperegistration(ratherthanabaseclassor interfacemappedtoaconcretetype).


156

CheckingfortheExistenceofaSpecificRegistration
Youcanalsousethemethodsofthecontainertocheckifaspecificregistrationormappingexists. TheIsRegisteredmethodtakesacontainer,atype,andoptionallyaregistrationname,andreturns TrueorFalse.Forexample,tocheckifthereisaregistrationinthecontainerforthetype MyEmailService,youwouldusethefollowingcode. C#
IUnityContainercontainer=newUnityContainer(); boolresult=container.IsRegistered<MyEmailService>();

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer() DimresultAsBoolean=container.IsRegistered(OfMyEmailService)()

ThiswillreturnTrueifthereisadefault(unnamed)registrationfortheMyEmailServicetype.Ifyou wanttocheckforthepresenceofanamedregistration,yousimplyspecifythenameinthecallto theIsRegisteredmethod,asshowninthefollowingexample. C#


boolresult=IsRegistered<MyEmailService>("EMailHandler");

VisualBasic
DimresultAsBoolean=IsRegistered(OfMyEmailService)("EMailHandler")

UnderstandingLifetimeManagers
TheUnitycontainermanagesthecreationandresolutionofobjectsbasedonalifetimeyouspecify whenyouregisterthetypeofanexistingobject,andusesthedefaultlifetimeifyoudonotspecifya lifetimemanagerforyourtyperegistration. Whenyouregisteratypeinconfiguration,orbyusingtheRegisterTypemethod,thedefault behaviorisforthecontainertouseatransientlifetimemanager.Itcreatesanewinstanceofthe registered,mapped,orrequestedtypeeachtimeyoucalltheResolveorResolveAllmethodor whenthedependencymechanisminjectsinstancesintootherclasses.Thecontainerdoesnotstore areferencetotheobject.However,whenyouwantnontransientbehavior(suchasasingleton)for objectsUnitycreates,thecontainermuststoreareferencetotheseobjects.Itmustalsotakeover managementofthelifetimeoftheseobjects. UnityusesspecifictypesthatinheritfromtheLifetimeManagerbaseclass(collectivelyreferredto aslifetimemanagers)tocontrolhowitstoresreferencestoobjectinstancesandhowthecontainer disposesoftheseinstances. WhenyouregisteranexistingobjectusingtheRegisterInstancemethod,thedefaultbehaviorisfor thecontainertotakeovermanagementofthelifetimeoftheobjectyoupasstothismethodusing theContainerControlledLifetimeManager.Thismeansthatattheendofthecontainerlifetime,the existingobjectisdisposed.Youcanalsousethislifetimemanagerwhendefiningregistrationsin
157

configuration,orwhenusingtheRegisterTypemethod,tospecifythatUnityshouldmanagethe objectasasingletoninstance. UsinganondefaultlifetimemanagerwithRegisterInstancewillresultindifferentbehaviors, dependingonthecontextoftherequests. ResolverequestsinthesamecontextwheretheRegisterInstancecallwasmade,suchasthe samethreadifusingaperthreadmanager,orthesameparentcontainerwhenusingthe hierarchicalone,willreturntheregisteredinstances. Resolverequestsinothercontexts,suchasadifferentthreadifusingaperthreadmanager, orachildcontainerwhenusingthehierarchicallifetimemanager,willresultinanew instancebeingcreatedbythecontaineranditwillbemadethesingletonforthatcontext. Thecreationofaninstanceunderthesecircumstancescouldfailifthecontainercannot resolvetheinstance,forexampleifyouregisteredaninstanceforaninterfacewithno mappingstoamatchingclass. ForinformationaboutusinglifetimemanagerswiththeRegisterTypeandRegisterInstance methods,seeRegisteringTypesandTypeMappingsandCreatingInstanceRegistrationsintheRun TimeConfigurationsectionofthisdocumentation.Forinformationaboutspecifyingthelifetimeof objectsatdesigntime,seeSpecifyingTypesintheConfigurationFile,andThe<instance>Elementin theDesignTimeConfigurationsectionofthisdocumentation.

UnityBuiltInLifetimeManagers
Unityincludessixlifetimemanagersthatyoucanusedirectlyinyourcode,butyoucancreateyour ownlifetimemanagerstoimplementspecificlifetimescenarios.Unityincludesthefollowinglifetime managers: TransientLifetimeManager.ForthislifetimemanagerUnitycreatesandreturnsanew instanceoftherequestedtypeforeachcalltotheResolveorResolveAllmethod.This lifetimemanagerisusedbydefaultforalltypesregisteredusingtheRegisterType,method unlessyouspecifyadifferentlifetimemanager. ContainerControlledLifetimeManagerwhichregistersanexistingobjectasasingleton instance.ForthislifetimemanagerUnityreturnsthesameinstanceoftheregisteredtypeor objecteachtimeyoucalltheResolveorResolveAllmethodorwhenthedependency mechanisminjectsinstancesintootherclasses.Thislifetimemanagereffectivelyimplements asingletonbehaviorforobjects.Unityusesthislifetimemanagerbydefaultforthe RegisterInstancemethodifyoudonotspecifyadifferentlifetimemanager.Ifyouwant singletonbehaviorforanobjectthatUnitywillcreatewhenyouspecifyatypemappingin configurationorwhenyouusetheRegisterTypemethod,youmustexplicitlyspecifythis lifetimemanager. IfyouregisteredatypemappingusingconfigurationorusingtheRegisterTypemethod, UnitycreatesanewinstanceoftheregisteredtypeduringthefirstcalltotheResolveor ResolveAllmethodorwhenthedependencymechanisminjectsinstancesintootherclasses. Subsequentrequestsreturnthesameinstance.
158

IfyouregisteredanexistinginstanceofanobjectusingtheRegisterInstancemethod,the containerreturnsthesameinstanceforallcallstoResolveorResolveAllorwhenthe dependencymechanisminjectsinstancesintootherclasses,providedthatoneofthe followingistrue: Youhavespecifiedacontainercontrolledlifetimemanager Youhaveusedthedefaultlifetimemanager Youareresolvinginthesamecontextinwhichyouregisteredtheinstancewhenusinga differentlifetimemanager. Onceyouhaveareferencetothepropercontainer,calltheRegisterInstancemethodofthat containertoregistertheexistingobject.Specifyastheregistrationtypeaninterfacethatthe objectimplements,anobjecttypefromwhichthetargetobjectinherits,ortheconcrete typeoftheobject. Thefollowingexamplecreatesanamed(nondefault)mappingbyspecifyingthename, Emailandusesthedefaultlifetime. C#
myContainer.RegisterInstance<EmailService>("Email",myEmailService);

VisualBasic
myContainer.RegisterInstance(OfEmailService)("Email",myEmailService)

Whenthecontainerisdisposed,itcallstheDisposemethodoftheobjectandallowsittobe garbagecollected.Therefore,youmustensurethatyourcodedoesnotmaintainareference totheobject. HierarchicalLifetimeManager.Forthislifetimemanager,asforthe ContainerControlledLifetimeManager,Unityreturnsthesameinstanceoftheregistered typeorobjecteachtimeyoucalltheResolveorResolveAllmethodorwhenthedependency mechanisminjectsinstancesintootherclasses.Thedistinctionisthatwhentherearechild containers,eachchildresolvesitsowninstanceoftheobjectanddoesnotshareonewiththe parent.Whenresolvingintheparent,thebehaviorislikeacontainercontrolledlifetime; whenresolvingtheparentandthechildyouhavedifferentinstanceswitheachactingasa containercontrolledlifetime.Ifyouhavemultiplechildren,eachwillresolveitsown instance. C#
IUnityContainerParent=newUnityContainer(); IUnityContainerchild=Parent.CreateChildContainer(); MyTypenewInstance=newMyType(); Parent.RegisterInstance<MyType>(newInstance,new HierarchicalLifetimeManager());

VisualBasic
DimParentAsIUnityContainer=NewUnityContainer() DimchildAsIUnityContainer=Parent.CreateChildContainer()
159

DimnewInstanceAsNewMyType() Parent.RegisterInstance(OfMyType)(newInstance,New HierarchicalLifetimeManager())

PerResolveLifetimeManager.Forthislifetimemanagerthebehaviorislikea TransientLifetimeManager,butalsoprovidesasignaltothedefaultbuildplan,markingthe typesothatinstancesarereusedacrossthebuildupobjectgraph.Inthecaseofrecursion, thesingletonbehaviorapplieswheretheobjecthasbeenregisteredwiththe PerResolveLifetimeManager.ThefollowingexampleusesthePerResolveLifetimeManager. C#


publicvoidViewIsReusedAcrossGraph() { varcontainer=newUnityContainer() .RegisterType<IPresenter,MockPresenter>() .RegisterType<IView,View>(newPerResolveLifetimeManager()); varview=container.Resolve<IView>(); varrealPresenter=(MockPresenter)view.Presenter; }

VisualBasic
PublicSubViewIsReusedAcrossGraph() Dimcontainer=NewUnityContainer()_ .RegisterType(OfIPresenter,MockPresenter)()_ .RegisterType(OfIView,View)(NewPerResolveLifetimeManager()) Dimview=container.Resolve(OfIView)() DimrealPresenter=DirectCast(view.Presenter,MockPresenter) EndSub

Thefollowingsmallobjectgraphillustratestheperbuildbehaviorfortheexample. MockPresenterinheritsfromIPresenterandcontainsaViewandMockPresenterobject. IViewcontainsaPresenterobjectandViewclasscontainsaPresenterdependency.Viewis reusedacrossthegraphperresolvecallbecauseViewisregisteredwitha PerResolveLifetimeManager. C#


publicinterfaceIPresenter {} publicclassMockPresenter:IPresenter { publicIViewView{get;set;} publicMockPresenter(IViewview) { View=view; } } publicinterfaceIView { IPresenterPresenter{get;set;}
160

} publicclassView:IView { [Dependency] publicIPresenterPresenter{get;set;} }

VisualBasic
PublicInterfaceIPresenter EndInterface PublicClassMockPresenter ImplementsIPresenter Private_ViewAsIView PublicPropertyView()AsIView Get Return_View EndGet Set(ByValvalueAsIView) _View=value EndSet EndProperty PublicSubNew(ByValview__1AsIView) View=view__1 EndSub EndClass PublicInterfaceIView PropertyPresenter()AsIPresenter EndInterface PublicClassView ImplementsIView Private_PresenterAsIPresenter <Dependency()>_ PublicPropertyPresenter()AsIPresenter Get Return_Presenter EndGet Set(ByValvalueAsIPresenter) _Presenter=value EndSet EndProperty EndClass

PerThreadLifetimeManager.ForthislifetimemanagerUnityreturns,onaperthreadbasis, thesameinstanceoftheregisteredtypeorobjecteachtimeyoucalltheResolveor ResolveAllmethodorwhenthedependencymechanisminjectsinstancesintootherclasses.


161

Thislifetimemanagereffectivelyimplementsasingletonbehaviorforobjectsonaperthread basis.PerThreadLifetimeManagerreturnsdifferentobjectsfromthecontainerforeach thread. IfyouregisteredatypemappingusingconfigurationorusingtheRegisterTypemethod, Unitycreatesanewinstanceoftheregisteredtypethefirsttimethetypeisresolvedina specifiedthread,eithertoansweracalltotheResolveorResolveAllmethodforthe registeredtypeortofulfilladependencywhileresolvingadifferenttype.Subsequent resolutionsonthesamethreadreturnthesameinstance. PerThreadLifetimeManagerreturnstheobjectdesiredorpermitsthecontainertocreatea newinstanceifnosuchobjectiscurrentlystoredforthecurrentthread.Anewinstanceis alsocreatedifcalledonathreadotherthantheonethatsetthevalue. WhenusingthePerThreadLifetimeManager,itisrecommendedthatyouuse RegisterTypeanddonotuseRegisterInstancetoregisteranobject. WhenyouregisteraninstancewiththePerThreadLifetimeManager,theinstanceis registeredonlyfortheexecutingthread.CallstoResolveonotherthreadsresultinper threadsingletonsforcontainerbuiltinstances.Ifyourequestatyperegisteredwiththe PerThreadLifetimeManagerinanythreadotherthanthethreaditwasregisteredfor,the lifetimecontainerforthatobjectfindsthatthereisnoregisteredinstanceforthatthread and,therefore,permitsthecontainertobuildanewinstanceforthatthread. Theresultisthatforthreadsotherthantheoneregisteringtheinstance,thebehavioris thesameasifyouregisteredthecontainerlifetimewithRegisterType. Thislifetimemanagerdoesnotdisposetheinstancesitholds.Thethreadobjectisreclaimed bygarbagecollectionwhenthethreadisdisposed,butnotethattheobjectisnotdisposed inthesensethattheDisposemethodisnotinvoked. ExternallyControlledLifetimeManager.TheExternallyControlledLifetimeManagerclass providesgenericsupportforexternallymanagedlifetimes.Thislifetimemanagerallowsyou toregistertypemappingsandexistingobjectswiththecontainersothatitmaintainsonlya weakreferencetotheobjectsitcreateswhenyoucalltheResolveorResolveAllmethodor whenthedependencymechanisminjectsinstancesintootherclassesbasedonattributesor constructorparameterswithinthatclass.Thisallowsothercodetomaintaintheobjectin memoryordisposeitandenablesyoutomaintaincontrolofthelifetimeofexistingobjects orallowsomeothermechanismtocontrolthelifetime.Usingthe ExternallyControlledLifetimeManagerenablesyoutocreateyourowncustomlifetime managersforspecificscenarios.Unityreturnsthesameinstanceoftheregisteredtypeor objecteachtimeyoucalltheResolveorResolveAllmethodorwhenthedependency mechanisminjectsinstancesintootherclasses.However,sincethecontainerdoesnothold ontoastrongreferencetotheobjectafteritcreatesit,thegarbagecollectorcandisposeof theobjectifnoothercodeisholdingastrongreferencetoit.

UsingtheRegisterInstancemethodtoregisteranexistingobjectresultsinthesamebehaviorasif youjustregisteredthelifetimecontainerwithRegisterType.Therefore,itisrecommendedthat
162

youdonotusetheRegisterInstancemethodtoregisteranexistingobjectwhenusingthenon defaultlifetimemanagersexceptforthethreadinwhichtheRegisterInstancewasinvoked.

MoreInformation
CreatingLifetimeManagers. "UsingaLifetimeManagerwiththeRegisterInstanceMethod"inCreatingInstance Registrations "UsingaLifetimeManagerwiththeRegisterTypeMethod"inRegisteringTypesandType Mappings

UsingBuildUptoWireUpObjectsNot CreatedbytheContainer
UnityexposesamethodnamedBuildUpthatyoucanusetopassexistingobjectinstancesthrough thecontainerinordertoapplydependencyinjectiontothatobject.Thisisanalternativeto resolvingtheobjectusinganyoftheothertechniquesavailablewithUnity.However,remember thattheBuildUpmethodcannotinjectdependentobjectsintoconstructorparameters,becausethe objecthasalreadybeencreated;itisnotcreatedbyUnity. TheBuildUpmethodisusefulwhenyoudonothavecontroloftheconstructionofaninstance,but youstillwantpropertyormethodcallinjectionperformed.Forexample,ASP.NETpages,Windows CommunicationFoundation(WCF)applications,andXAMLcodeoftencreateinstancesofobjects andpassareferencetoyourcode.TheBuildUpmethodwillusuallyreturntheoriginalobjectafter passingitthroughthecontainer,althoughcontainerextensionsmayaddotherfeaturesthatcause themethodtoreturnadifferentobjectthatistypecompatiblewiththeexistingobject.For example,aninjectionstrategymaycreateandreturnaproxyforanobjectoraderivedobject insteadoftheactualobject. IfyouhavecreatedoraddedextensionstotheUnitycontainer,theseextensionscanaccessanduse anamethatyouspecifywhenyouexecutetheBuildUpmethod.Thisallowstheextensionsto changetheirbehavior,dependingonthevalueyouspecify.Forexample,theymayusethenameto controlhowdependenciesareresolvedortocontrolfeaturessuchaseventwiringorinterception. Theactualbehaviordependsontheindividualextension.

TheBuildUpMethodOverloads
ThefollowingtabledescribestheoverloadsoftheBuildUpmethod.TheAPIfortheUnitycontainer containsbothgenericandnongenericoverloadsofthesemethodssothatyoucanusethemwith languagesthatdonotsupportthegenericssyntax.
163

Method BuildUp<T>(T existing)

Description BuildUp Passes the existing object of type T through the container and performs all configured injection upon it. Passes the existing object of type T with the specified name through the container and performs all configured injection upon it. Passes the existing object of type t through the container and performs all configured injection upon it. Passes the existing object of type t with the specified name through the container and performs all configured injection upon it.

BuildUp<T>(T existing, string name)

BuildUp(Type t, object existing)

BuildUp(Type t, object existing, string name)

TheUnityContainerclassalsoexposestheTeardownmethod,whichtheoreticallywouldreverse thebuildupprocess.However,thebaseimplementationofthismethoddoesnothing.The implementationexistssothatcontainerextensionscanexecutetheirowncustomoverridesofthis methodifrequired.

UsingtheBuildUpMethod
ThefollowingexampleshowshowyoucanusetheBuildUpmethodtoapplydependencyinjection toexistingobjectinstancesnamedmyDataServiceandmyLoggingService,whichimplementthe interfaceIMyService.Theexamplesuseboththegenericandthenongenericoverloadsofthe containermethods. C#
IMyServicemyDataService=newDataService(); IMyServicemyLoggingService=newLoggingService(); IMyServicebuiltupDataService=myContainer.BuildUp<IMyService>(myDataService); IMyServicebuiltupLoggingService =(IMyService)myContainer.BuildUp(typeof(IMyService),myLoggingService);

VisualBasic
DimmyDataServiceAsIMyService=NewDataService() DimmyLoggingServiceAsIMyService=NewLoggingService() DimbuiltupDataServiceAsIMyService=myContainer.BuildUp(Of IMyService)(myDataService) DimbuiltupLoggingServiceAsIMyService_ =myContainer.BuildUp(GetType(IMyService),myLoggingService)

IfyouhavecreatedoraddedextensionstotheUnitycontainer,theseextensionscanaccessanduse anamethatyouspecifywhenyouexecutetheBuildUpmethod.Thisallowstheextensionsto changetheirbehaviordependingonthevalueyouspecify.Forexample,theymayusethenameto controlhowdependenciesareresolvedortocontrolfeaturessuchaseventwiringorinterception. Theactualbehaviordependsontheindividualextension. ThefollowingcodeshowshowyoucanexecutetheBuildUpmethodandprovideaname.Ituses boththegenericandthenongenericoverloadsofthecontainermethods. C#


164

IMyServicemyDataService=newDataService(); IMyServicemyLoggingService=newLoggingService(); IMyServicebuiltupDataService =myContainer.BuildUp<IMyService>(myDataService,"Data"); IMyServicebuiltupLoggingService =(IMyService)myContainer.BuildUp(typeof(IMyService),myLoggingService, "Logging");

VisualBasic
DimmyDataServiceAsIMyService=NewDataService() DimmyLoggingServiceAsIMyService=NewLoggingService() DimbuiltupDataServiceAsIMyService_ =myContainer.BuildUp(OfIMyService)(myDataService,"Data") DimbuiltupLoggingServiceAsIMyService_ =myContainer.BuildUp(GetType(IMyService),myLoggingService,"Logging")

MoreInformation
Formoreinformationaboutthetechniquesdiscussedinthisscenario,seethefollowingtopics: ConfiguringUnity AnnotatingObjectsforConstructorInjection AnnotatingObjectsforProperty(Setter)Injection

UsingInjectionAttributes
OneofthemostusefulandpowerfultechniqueswhenusingUnityistotakeadvantageof dependencyinjectionfortheparametersofclassconstructorsandmethods,andforthevaluesof properties.Thisapproachallowsyoutoresolveandpopulatetheentirehierarchyofobjectsusedin yourapplicationbasedontyperegistrationsandmappingsdefinedinthecontainer,withthe subsequentadvantagesthisoffers. Youcanspecifyconstructor,property,andmethodcallinjectioninformationinconfigurationorby addingregistrationstothecontaineratruntime.Youcanalsoapplyattributestomembersofyour classes.Whenyouresolvetheseclassesthroughthecontainer,Unitywillgenerateinstancesofthe dependentobjectsandwireupthetargetclasswiththeseinstances. Unityperformsconstructorinjectionautomaticallyonresolvedclasses,choosingthemostcomplex constructorandpopulatinganyparametersforwhichyoudonotprovidevalueswhenitconstructs theobject.YoucanalsospecifywhichconstructorUnityshouldusetoconstructtheobject.For moreinformation,seeAnnotatingObjectsforConstructorInjection. Propertyandmethodcallinjectiondonotoccurautomaticallyunlessyouhaveregisteredinjection typesinthecontaineratdesigntimeorruntime.Ifyouhavenotregisteredinjectiontypesinthe container,youcanaddattributestothemembersofyourresolvedclasstoforceinjectionof
165

dependentobjectswhenthetargetclassisresolved.Formoreinformation,seeAnnotatingObjects forProperty(Setter)InjectionandAnnotatingObjectsforMethodCallInjection. Forinformationaboutregisteringinjectiontypesintheconfigurationatdesigntimeorruntime,see ConfiguringUnity.

AnnotatingObjectsforConstructor Injection
Unitysupportsautomaticdependencyinjectionforclassconstructors.YoucanusetheUnity containertogenerateinstancesofdependentobjectsandwireupthetargetclasswiththese instances.Thistopicexplainshowtouseboththeautomaticconstructorinjectionmechanismand anattributeappliedtotheconstructorofaclasstodefinethedependencyinjectionrequirementsof thatclass.Theattributecanalsospecifyparametersthattheconstructorwillpasstothedependent objectthatthecontainergenerates. ToperforminjectionofdependentclassesintoobjectsyoucreatethroughtheUnitycontainer,you canusethefollowingtechniques: SingleConstructorAutomaticInjection.Withthistechnique,youallowtheUnitycontainerto satisfyanyconstructordependenciesdefinedinparametersoftheconstructorautomatically. Youusethistechniquewhenthereisasingleconstructorinthetargetclass. SpecifyingNamedTypeMappings.Withthistechnique,youspecifynamedmappingsfor dependenciesintheparametersofaclassconstructor.Namedmappingsallowyoutospecify morethanonemappingforaninterfaceorbaseclass,orforatyperegistration. MultipleConstructorInjectionUsinganAttribute.Withthistechnique,youapplyattributesto theclassconstructor(s)thatspecifythedependencies.Youusethistechniquewhenthereis morethanoneconstructorinthetargetclass.

Constructorinjectionisaformofmandatoryinjectionofdependentobjects,aslongasdevelopers usetheUnitycontainertogeneratethetargetobject.Thedependentobjectinstanceisgenerated whentheUnitycontainercreatesaninstanceofthetargetclassusingtheconstructor.Formore information,seeNotesonUsingConstructorInjection.

SingleConstructorAutomaticInjection
Forautomaticconstructorinjection,yousimplyspecifyasparametersoftheconstructorthe dependentobjecttypes.Youcanspecifytheconcretetype,orspecifyaninterfaceorbaseclassfor whichtheUnitycontainercontainsaregisteredmapping. Touseautomaticsingleconstructorinjectiontocreatedependentobjects
166

1. Defineaconstructorinthetargetclassthattakesasaparametertheconcretetypeofthe dependentclass.Forexample,thefollowingcodeshowsatargetclassnamedMyObject containingaconstructorthathasadependencyonaclassnamedMyDependentClass. C#


publicclassMyObject { publicMyObject(MyDependentClassmyInstance) { //workwiththedependentinstance myInstance.SomeProperty="SomeValue"; //orassignittoaclasslevelvariable } }

VisualBasic
PublicClassMyObject PublicSubNew(myInstanceAsMyDependentClass) 'workwiththedependentinstance myInstance.SomeProperty="SomeValue" 'orassignittoaclasslevelvariable EndSub EndClass

2. Inyourruntimecode,usetheResolvemethodofthecontainertocreateaninstanceofthe targetclass.TheUnitycontainerwillinstantiatethedependentconcreteclassandinjectit intothetargetclass.Forexample,thefollowingcodeshowshowyoucaninstantiatethe exampletargetclassnamedMyObjectcontainingaconstructorthathasadependencyona classnamedMyDependentClass. C#


IUnityContaineruContainer=newUnityContainer(); MyObjectmyInstance=uContainer.Resolve<MyObject>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

3. Alternatively,youcandefineatargetclassthatcontainsmorethanonedependency definedinconstructorparameters.TheUnitycontainerwillinstantiateandinjectan instanceofeachone.Forexample,thefollowingcodeshowsatargetclassnamed MyObjectcontainingaconstructorthathasdependenciesontwoclassesnamed DependentClassAandDependentClassB. C#


publicclassMyObject { publicMyObject(DependentClassAdepA,DependentClassBdepB) { //workwiththedependentinstances depA.SomeClassAProperty="SomeValue"; depB.SomeClassBProperty="AnotherValue";
167

//orassignthemtoclasslevelvariables } }

VisualBasic
PublicClassMyObject PublicSubNew(depAAsDependentClassA,depBAsDependentClassB) 'workwiththedependentinstance depA.SomeClassAProperty="SomeValue" depB.SomeClassBProperty="AnotherValue" 'orassignthemtoclasslevelvariables EndSub EndClass

4. Inyourruntimecode,usetheResolvemethodofthecontainertocreateaninstanceofthe targetclass.TheUnitycontainerwillcreateaninstanceofeachofthedependentconcrete classesandinjectthemintothetargetclass.Forexample,thefollowingcodeshowshow youcaninstantiatetheexampletargetclassnamedMyObjectcontainingaconstructorthat hasconstructordependencies. C#


IUnityContaineruContainer=newUnityContainer(); MyObjectmyInstance=uContainer.Resolve<MyObject>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

5. Inadditiontousingconcretetypesasparametersofthetargetobjectconstructor,youcan useinterfacesorbaseclasstypesandthenregistermappingsintheUnitycontainerto translatethesetypesintothecorrectconcretetypes.Defineaconstructorinthetarget classthattakesasparameterstheinterfaceorbasetypesofthedependentclass.For example,thefollowingcodeshowsatargetclassnamedMyObjectcontainingaconstructor thathasadependencyonaclassthatimplementstheinterfacenamedIMyInterfaceanda classthatinheritsfromMyBaseClass. C#


publicclassMyObject { publicMyObject(IMyInterfaceinterfaceObj,MyBaseClassbaseObj) { //workwiththeconcretedependentinstances //orassignthemtoclasslevelvariables } }

VisualBasic
PublicClassMyObject PublicSubNew(interfaceObjAsIMyInterface,baseObjAsMyBaseClass) 'workwiththedependentinstance 'orassignthemtoclasslevelvariables EndSub
168

EndClass

6. Inyourruntimecode,registerthemappingsyourequirefortheinterfaceandbaseclass types,andthenusetheResolvemethodofthecontainertocreateaninstanceofthetarget class.TheUnitycontainerwillinstantiateaninstanceofeachofthemappedconcretetypes forthedependentclassesandinjectthemintothetargetclass.Forexample,thefollowing codeshowshowyoucaninstantiatetheexampletargetclassnamedMyObjectcontaininga constructorthathasadependencyonthetwoobjectsoftypeIMyInterfaceand MyBaseClass. C#


IUnityContaineruContainer=newUnityContainer() .RegisterType<IMyInterface,FirstObject>() .RegisterType<MyBaseClass,SecondObject>(); MyObjectmyInstance=uContainer.Resolve<MyObject>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(OfIMyInterface,FirstObject)()_ .RegisterType(OfMyBaseClass,SecondObject)() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

SpecifyingNamedTypeMappings
Theprecedingexampleshowshowyoucanresolvetypesforconstructorparametersusingthe default(unnamed)mappingsinthecontainer.Ifyouregistermorethanonemappingforatype,you mustdifferentiatethembyusinganame.Inthiscase,youcanspecifywhichnamedmappingthe containerwillusetoresolveeachconstructorparametertype. Touseattributedconstructorinjectionwithnamedcontainertypemappings 1. Defineaconstructorinthetargetclassthattakesasaparametertheconcretetypeofthe dependentclass,andapplyaDependencyattributetotheparameterthatspecifiesthe nameoftheregisteredmappingtouse.Forexample,thefollowingcodeshowsatarget classnamedMyObjectcontainingaconstructorthathasadependencyonaservice registeredwiththenamemyDataService,andwhichimplementstheIMyServiceinterface. ItassumesthatthecontainercontainsamappingdefinedwiththenameDataService betweentheIMyServiceinterfaceandaconcreteimplementationofthisinterface. C#
publicclassMyObject { publicMyObject([Dependency("DataService")]IMyServicemyDataService) { //workwiththeservicehere } }

VisualBasic
169

PublicClassMyObject PublicSubNew(<Dependency("DataService")>myDataServiceAsIMyService) 'workwiththeservicehere EndSub EndClass

2. Inyourruntimecode,usetheResolvemethodofthecontainertocreateaninstanceofthe targetclass.TheUnitycontainerwillinstantiatethedependentconcreteclassdefinedinthe mappingnamedDataServiceandinjectitintothetargetclass.Forexample,thefollowing codeshowshowyoucaninstantiatetheexampletargetclassshownabove. C#


IUnityContaineruContainer=newUnityContainer(); MyObjectmyInstance=uContainer.Resolve<MyObject>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

YoucanusetheDependencyattributeonmorethanoneconstructorparameter.Youcanalsouseit whentheconstructordefinesmorethanoneparameterofthesametypetodifferentiatethe mappingsandensurethattheappropriateconcretetypeisreturnedforeachparameter. Ifyouspecifyanamedmappingandthereisnomappingregisteredforthattypeandname,the containerwillraiseanexception.

MultipleConstructorInjectionUsinganAttribute
Whenatargetclasscontainsmorethanoneconstructorwiththesamenumberofparameters,you mustapplytheInjectionConstructorattributetotheconstructorthattheUnitycontainerwilluseto indicatewhichconstructorthecontainershoulduse.Aswithautomaticconstructorinjection,you canspecifytheconstructorparametersasaconcretetype,oryoucanspecifyaninterfaceorbase classforwhichtheUnitycontainercontainsaregisteredmapping. Touseattributedconstructorinjectionwhenthereismorethanoneconstructor 1. ApplytheInjectionConstructorattributetotheconstructorinthetargetclassthatyouwant thecontainertouse.Inthesimplestcase,thetargetconstructortakesasaparameterthe concretetypeofthedependentclass.Forexample,thefollowingcodeshowsatargetclass namedMyObjectcontainingtwoconstructors,oneofwhichhasadependencyonaclass namedMyDependentClassandhastheInjectionConstructorattributeapplied. C#
publicclassMyObject { publicMyObject(SomeOtherClassmyObjA) {
170

... } [InjectionConstructor] publicMyObject(MyDependentClassmyObjB) { ... } }

VisualBasic
PublicClassMyObject PublicSubNew(myObjAAsSomeOtherClass) ... EndSub <InjectionConstructor()>_ PublicSubNew(myObjBAsMyDependentClass) ... EndSub EndClass

2. Inyourruntimecode,usetheResolvemethodofthecontainertocreateaninstanceofthe targetclass.TheUnitycontainerwillinstantiatethedependentconcreteclassdefinedinthe attributedconstructorandinjectitintothetargetclass.Forexample,thefollowingcode showshowyoucaninstantiatetheexampletargetclassnamedMyObjectcontainingan attributedconstructorthathasadependencyonaclassnamedMyDependentClass. C#


IUnityContaineruContainer=newUnityContainer(); MyObjectmyInstance=uContainer.Resolve<MyObject>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

3. Alternatively,youcandefineamultipleconstructortargetclassthatcontainsmorethan onedependencydefinedinthetargetconstructorparameters.TheUnitycontainerwill instantiateandinjectaninstanceofeachone.Forexample,thefollowingcodeshowsa targetclassnamedMyObjectcontaininganattributedconstructorthathasdependencies ontwoclasses,DependentClassAandDependentClassB. C#


publicclassMyObject { publicMyObject(SomeClassAobjA,SomeClassBobjB) { ...
171

} [InjectionConstructor] publicMyObject(DependentClassAdepA,DependentClassBdepB) { ... } }

VisualBasic
PublicClassMyObject PublicSubNew(objAAsSomeClassA,objBAsSomeClassB) ... EndSub <InjectionConstructor()>_ PublicSubNew(depAAsDependentClassA,depBAsDependentClassB) ... EndSub EndClass

4. Inyourruntimecode,usetheResolvemethodofthecontainertocreateaninstanceofthe targetclass.TheUnitycontainerwillcreateaninstanceofeachofthedependentconcrete classesdefinedintheattributedconstructorandinjectthemintothetargetclass.For example,thefollowingcodeshowshowyoucaninstantiatetheexampletargetclassnamed MyObjectcontainingaconstructorthathasconstructordependencies C#


IUnityContaineruContainer=newUnityContainer(); MyObjectmyInstance=uContainer.Resolve<MyObject>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

5. Inadditiontousingconcretetypesasparametersofthetargetobjectconstructor,youcan useinterfacesorbaseclasstypes,andthenregistermappingsintheUnitycontainerto translatethesetypesintothecorrectconcretetypes.Fordetails,seesteps5and6ofthe procedureSingleConstructorAutomaticInjection.

NotesonUsingConstructorInjection
Thefollowingnoteswillhelpyoutogetthegreatestbenefitfromusingconstructorinjectionwith Unity.

172

HowUnityResolvesTargetConstructorsandParameters
Whenatargetclasscontainsmorethanoneconstructor,Unitywillusetheonethathasthe InjectionConstructorattributeapplied.Ifthereismorethanoneconstructor,andnonecarriesthe InjectionConstructorattribute,Unitywillusetheconstructorwiththemostparameters.Ifthereis morethanoneconstructorthatisthe"longest"withthesamenumberofparameters,Unitywill raiseanexception.

ConstructorInjectionwithExistingObjects
IfyouuseconfigurationortheRegisterInstancemethodtoregisteranexistingobject,constructor injectiondoesnottakeplaceonthatobjectbecauseithasalreadybeencreatedoutsideofthe influenceoftheUnitycontainer.EvenifyoucalltheBuildUpmethodofthecontainerandpassit theexistingobject,constructorinjectionwillnevertakeplacebecausetheconstructorwillnot execute. Instead,youcanuseproperty(setter)injectionbyapplyingaDependencyattributetoapublic property.Alternatively,createanInitializemethodfortheclassthattakesthetypetoresolveasa parameterandapplytheInjectionMethodattributetothismethod.Unitywillresolvethe parameterandcallthemethod.Insidethemethod,youcanstoreareferencetotheresolvedobject foruseinyourcode.Formoredetails,seeAnnotatingObjectsforMethodCallInjection.

AvoidingCircularReferences
Dependencyinjectionmechanismscancauseapplicationerrorsiftherearecircularreferences betweenobjectsthatthecontainerwillcreate.Formoredetails,seeCircularReferenceswith DependencyInjection.

WhentoUseConstructorInjection
Youshouldconsiderusingconstructorinjectioninthefollowingsituations: Whenyouwanttoperformdependencyinjectiononnewinstancesofobjectsorclasses createdthroughtheUnitycontainer.Constructorinjectioncannotbeusedwithexisting objectinstances. Whenyouwanttoinstantiatedependentobjectsautomaticallywhenyouinstantiatethe parentobject. Whenyouwantasimpleapproachthatmakesiteasytoseeinthecodewhatthe dependenciesareforeachclass. Whentheparentobjectdoesnotrequirealargenumberofconstructorsthatforwardtoeach other. Whentheparentobjectconstructorsdonotrequirealargenumberofparameters.

173

Whenyouwanttobeabletohidefieldvaluesfromviewintheapplicationcodebynot exposingthemaspropertiesormethods. Whenyouwanttocontrolwhichobjectsareinjectedbyeditingthecodeofthedependent objectinsteadoftheparentobjectorapplication.

Ifyouarenotsurewhichtypeofinjectiontouse,therecommendationisthatyouuseconstructor injectionunlessyouareworkingwithanexistinginstanceofanobjectorclass. Youcanalsoconfigureconstructorinjectionatdesigntimeorruntime.Formoreinformation,see ConfiguringUnity.

AnnotatingObjectsforProperty (Setter)Injection
Unitysupportsdependencyinjectiontosetthevaluesorpropertiesthroughattributesappliedto membersofthetargetclass.YoucanusetheUnitycontainertogenerateinstancesofdependent objectsandwireupthetargetclasspropertieswiththeseinstances.Thistopicexplainshowtouse anattributethatisappliedtooneormorepropertydeclarationsofaclasstodefinethedependency injectionrequirementsofthatclass.Theattributecanspecifyparametersfortheattributetocontrol itsbehavior,suchasthenameofaregisteredmapping. ToperformpropertyinjectionofdependentclassesintoobjectsyoucreatethroughtheUnity container,youapplytheDependencyattributetothepropertydeclarationsofaclass.TheUnity containerwillcreateaninstanceofthedependentclasswithinthescopeofthetargetobject(the objectyouspecifyinaResolvemethodcall)andassignthisdependentobjecttotheattributed propertyofthetargetobject. Propertyinjectionisaformofoptionalinjectionofdependentobjects,aslongasdevelopersusethe Unitycontainertogeneratethetargetobject.Thedependentobjectinstanceisgeneratedbefore thecontainerreturnsthetargetobject.Inaddition,unlikeconstructorinjection,youmustapplythe appropriateattributeinthetargetclasstoinitiatepropertyinjection.Youcanalsoperformproperty injectionofoptionaldependentclassesbyapplyingtheOptionalDependencyattribute.Thissimply marksadependencyasoptional,whichmeansthatthecontainerwilltrytoresolveit,andreturn nulliftheresolutionfailsratherthanthrowanexception.Formoreinformation,seeNotesonUsing Property(Setter)Injection. Touseproperty(setter)injectiontocreatedependentobjectsforaclass 1. DefineapropertyinthetargetclassandapplytheDependencyattributetoittoindicate thatthetypedefinedandexposedbythepropertyisadependencyoftheclass.The followingcodedemonstratespropertyinjectionforaclassnamedMyObjectthatexposesas
174

apropertyareferencetoaninstanceofanotherclassnamedSomeOtherObject(not definedinthiscode). C#
publicclassMyObject { privateSomeOtherObject_dependentObject; [Dependency] publicSomeOtherObjectDependentObject { get{return_dependentObject;} set{_dependentObject=value;} } }

VisualBasic
PublicClassMyObject Private_dependentObjectAsSomeOtherObject <Dependency()>_ PublicPropertyDependentObject()AsSomeOtherObject Get Return_dependentObject EndGet Set(ByValvalueAsSomeOtherObject) _dependentObject=value EndSet EndProperty EndClass

2. Inyourruntimecode,usetheResolvemethodofthecontainertocreateaninstanceofthe targetclass,andthenreferencethepropertycontainingthedependentobject.TheUnity containerwillinstantiatethedependentconcreteclassdefinedintheattributedproperty andinjectitintothetargetclass.Forexample,thefollowingcodeshowshowyoucan instantiatetheexampletargetclassnamedMyObjectcontaininganattributedproperty thathasadependencyonaclassnamedSomeOtherObjectandthenretrievethe dependentobjectfromtheDependentObjectproperty. C#


IUnityContaineruContainer=newUnityContainer(); MyObjectmyInstance=uContainer.Resolve<MyObject>(); //nowaccessthepropertycontainingthedependency SomeOtherObjectdepObj=myInstance.DependentObject;

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)() 'nowaccessthepropertycontainingthedependency
175

DimdepObjAsSomeOtherObject=myInstance.DependentObject

3. Inadditiontousingconcretetypesforthedependenciesintargetobjectproperties,youcan useinterfacesorbaseclasstypes,andthenregistermappingsintheUnitycontainerto translatethesetypesintothecorrectconcretetypes.Defineapropertyinthetargetclassas aninterfaceorbasetype.Forexample,thefollowingcodeshowsatargetclassnamed MyObjectcontainingpropertiesnamedInterfaceObjectandBaseObjectthathave dependenciesonaclassthatimplementstheinterfacenamedIMyInterfaceandonaclass thatinheritsfromMyBaseClass. C#


publicclassMyObject { privateIMyInterface_interfaceObj; privateMyBaseClass_baseObj; [Dependency] publicIMyInterfaceInterfaceObject { get{return_interfaceObj;} set{_interfaceObj=value;} } [Dependency] publicMyBaseClassBaseObject { get{return_baseObj;} set{_baseObj=value;} } }

VisualBasic
PublicClassMyObject Private_interfaceObjAsIMyInterface Private_baseObjAsMyBaseClass <Dependency()>_ PublicPropertyInterfaceObject()AsIMyInterface Get Return_interfaceObj EndGet Set(ByValvalueAsIMyInterface) _interfaceObj=value EndSet EndProperty <Dependency()>_ PublicPropertyBaseObject()AsMyBaseClass Get
176

Return_baseObj EndGet Set(ByValvalueAsMyBaseClass) _baseObj=value EndSet EndProperty EndClass

4. Inyourruntimecode,registerthemappingsyourequirefortheinterfaceandbaseclass types,andthenusetheResolvemethodofthecontainertocreateaninstanceofthetarget class.TheUnitycontainerwillcreateaninstanceofeachofthemappedconcretetypesfor thedependentclassesandinjectthemintothetargetclass.Forexample,thefollowingcode showshowyoucaninstantiatetheexampletargetclassnamedMyObjectcontainingtwo propertiesthathavedependenciesonthetwoclassesnamedFirstObjectand SecondObject. C#


IUnityContaineruContainer=newUnityContainer() .RegisterType<IMyInterface,FirstObject>() .RegisterType<MyBaseClass,SecondObject>(); MyObjectmyInstance=uContainer.Resolve<MyObject>(); //nowaccessthepropertiescontainingthedependencies IMyInterfacedepObjA=myInstance.InterfaceObject; MyBaseClassdepObjB=myInstance.BaseObject;

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(OfIMyInterface,FirstObject)()_ .RegisterType(OfMyBaseClass,SecondObject)() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)() 'nowaccessthepropertiescontainingthedependencies DimdepObjAAsIMyInterface=myInstance.InterfaceObject DimdepObjBAsMyBaseClass=myInstance.BaseObject

5. Youcanregistermultiplenamedmappingswiththecontainerforeachdependencytype,if required,andthenuseaparameteroftheDependencyattributetospecifythemapping youwanttousetoresolvethedependentobjecttype.Forexample,thefollowingcode specifiesthemappingnamesfortheKeypropertyoftheDependencyattributefortwo propertiesofthesametype(inthiscase,aninterface)intheclassMyObject. C#


publicclassMyObject { privateIMyInterface_objA,_objB; [Dependency("MapTypeA")] publicIMyInterfaceObjectA {
177

get{return_objA;} set{_objA=value;} } [Dependency("MapTypeB")] publicIMyInterfaceObjectB { get{return_objB;} set{_objB=value;} } }

VisualBasic
PublicClassMyObject Private_objA,_objBAsIMyInterface <Dependency("MapTypeA")>_ PublicPropertyObjectA()AsIMyInterface Get Return_objA EndGet Set(ByValvalueAsIMyInterface) _objA=value EndSet EndProperty <Dependency("MapTypeB")>_ PublicPropertyObjectB()AsIMyInterface Get Return_objB EndGet Set(ByValvalueAsIMyInterface) _objB=value EndSet EndProperty EndClass

6. Inyourruntimecode,registerthenamed(nondefault)mappingsyourequireforthetwo concretetypesthatthepropertieswilldependon,andthenusetheResolvemethodofthe containertocreateaninstanceofthetargetclass.TheUnitycontainerwillinstantiatean instanceofeachofthemappedconcretetypesforthedependentclassesandinjectthem intothetargetclass.Forexample,thefollowingcodeshowshowyoucaninstantiatethe exampletargetclassnamedMyObjectcontainingtwopropertiesthathavedependencies onthetwoclassesnamedFirstObjectandSecondObject. C#


IUnityContaineruContainer=newUnityContainer() .RegisterType<IMyInterface,FirstObject>("MapTypeA") .RegisterType<IMyInterface,SecondObject>("MapTypeB");
178

MyObjectmyInstance=uContainer.Resolve<MyObject>(); //nowaccessthepropertiescontainingthedependencies IMyInterfacedepObjA=myInstance.ObjectA; IMyInterfacedepObjB=myInstance.ObjectB;

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(OfIMyInterface,FirstObject)("MapTypeA")_ .RegisterType(OfIMyInterface,SecondObject)("MapTypeB") DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)() 'nowaccessthepropertiescontainingthedependencies DimdepObjAAsIMyInterface=myInstance.ObjectA DimdepObjBAsIMyInterface=myInstance.ObjectB

UsingOptionalDependencies
Anoptionaldependencyworkslikearegulardependencywiththedifferencethatiftheoptional dependencycannotberesolved,nullisreturnedbythecontainer. C#
publicclassObjectWithOptionalProperty { [OptionalDependency] publicICarInterfaceCar { .get; .set; } }

VisualBasic
PublicClassObjectWithOptionalProperty ..<OptionalDependency>_ ..PublicPropertyCar()AsICarInterface Get EndGet Set EndSet ..EndProperty EndClass

NotesonUsingProperty(Setter)Injection
RememberthatpropertyinjectionisoptionalandthatyoumustapplytheDependencyattributeto targetclasspropertiesifyouwantpropertyinjectionofdependenttypestooccur.

179

UsingtheDependencyAttributewithConstructorandMethod Parameters
YoucanalsoapplytheDependencyattributetotheparametersofaconstructorormethodto specifythenamedmappingyouwantthecontainertouse.Ifyoudonotspecifyanamedmapping, Unityusesthedefault(unnamed)mapping.Formoredetails,seeAnnotatingObjectsfor ConstructorInjectionandAnnotatingObjectsforMethodCallInjection.

PropertyInjectionwithExistingObjects
IfyouuseconfigurationortheRegisterInstancemethodtoregisteranexistingobject,property (setter)injectiondoesnottakeplaceonthatobjectbecauseithasalreadybeencreatedoutsideof theinfluenceoftheUnitycontainer.However,youcancalltheBuildUpmethodofthecontainer andpassittheexistingobjecttoforcepropertyinjectiontotakeplaceonthatobject.

AvoidingtheUseofPublicProperties
Tousepropertyinjection,youmustexposeapublicpropertyfromyourclasstowhichyoucanapply theDependencyattribute.Iftheonlyreasonyouareexposingthispropertyistoimplement injection,andyouwouldprefernottoexposeitasapublicproperty,youcanusemethodcall injectioninstead.CreateanInitializemethodfortheclassthattakesthetypetoresolveasa parameterandapplytheInjectionMethodattributetothismethod.Unitywillresolvethe parameterandcallthemethod.Insidethemethod,youcanstoreareferencetotheresolvedobject foruseinyourcode.Formoredetails,seeAnnotatingObjectsforMethodCallInjection.

AvoidingCircularReferences
Dependencyinjectionmechanismscancauseapplicationerrorsiftherearecircularreferences betweenobjectsthatthecontainerwillcreate.Formoredetails,seeCircularReferenceswith DependencyInjection.

WhentoUseProperty(Setter)Injection
Youshouldconsiderusingpropertyinjectioninthefollowingsituations: Whenyouwanttoinstantiatedependentobjectsautomaticallywhenyouinstantiatethe parentobject. Whenyouwantasimpleapproachthatmakesiteasytoseeinthecodewhatthe dependenciesareforeachclass. Whentheparentobjectrequiresalargenumberofconstructorsthatforwardtoeachother, makingdebuggingandmaintenancedifficult. Whentheparentobjectconstructorsrequirealargenumberofparameters,especiallyifthey areofsimilartypesandtheonlywaytoidentifythemisbyposition.
180

Whenyouwanttomakeiteasierforuserstoseewhatsettingsandobjectsareavailable, whichisnotpossibleusingconstructorinjection. Whenyouwanttocontrolwhichobjectsareinjectedbyeditingthecodeofthedependent objectinsteadoftheparentobjectorapplication.

Ifyouarenotsurewhichtypeofinjectiontouse,therecommendationisthatyouuseconstructor injection.Thisislikelytosatisfyalmostallgeneralrequirementsunlessyouneedtoperform injectiononexistingobjectinstances. Youcanalsoconfigurepropertyinjectionatdesigntimeorruntime.Formoreinformation,see ConfiguringUnity.

AnnotatingObjectsforMethodCall Injection
Unitysupportsdependencyinjectiontosetthevaluesofparametersofmethodsspecifiedthrough attributesappliedtomembersofthetargetclass.YoucanusetheUnitycontainertogenerate instancesofdependentobjectsandwireupthetargetclassmethodparameterswiththese instances.Thistopicexplainshowtouseanattributethatisappliedtooneormoremethod declarationsofaclasstodefinethedependencyinjectionrequirementsofthatclass. ToperforminjectionofdependentclassesintoobjectsyoucreatethroughtheUnitycontainer,you applytheInjectionMethodattributetothemethoddeclarationsofaclass.TheUnitycontainerwill forcethetargetobject(theobjectyouspecifyinaResolvemethodcall)tocreateaninstanceofthe dependentclassandthencallthetargetmethod.Ifrequired,yourcodeinthemethodcansavethis instancebyassigningittoaclasslevelvariable. Methodcallinjectionisaformofoptionalinjectionofdependentobjectsthatyoucanuseifyouuse theUnitycontainertogeneratethetargetobject.Unityinstantiatesdependentobjectsdefinedin parametersofmethodsthatcarrytheInjectionMethodattributewithinthescopeofthetarget object.Thenitcallstheattributedmethodofthetargetobjectbeforereturningtheobjecttothe caller.YoumustapplytheInjectionMethodattributeinthetargetclasstoinitiatemethodcall injection.Formoreinformation,seeNotesonUsingMethodCallInjection. Tousemethodcallinjectiontocreatedependentobjectsforaclass 1. DefineamethodinthetargetclassandapplytheInjectionMethodattributetoittoindicate thatanytypesdefinedinparametersofthemethodaredependenciesoftheclass.The followingcodedemonstratesthemostcommonscenariosavingthedependentobject instanceinaclasslevelvariableforaclassnamedMyObjectthatexposesamethod namedInitializethattakesasaparameterareferencetoaninstanceofanotherclass namedSomeOtherObject(notdefinedinthiscode).
181

C#
publicclassMyObject { privateSomeOtherObjectdependentObject; [InjectionMethod] publicvoidInitialize(SomeOtherObjectdep) { //assignthedependentobjecttoaclasslevelvariable dependentObject=dep; } }

VisualBasic
PublicClassMyObject PrivatedependentObjectAsSomeOtherObject <InjectionMethod()>_ PublicSubInitialize(depAsSomeOtherObject) 'assignthedependentobjecttoaclasslevelvariable dependentObject=dep EndSub EndClass

2. Inyourruntimecode,usetheResolvemethodofthecontainertocreateaninstanceofthe targetclass.TheUnitycontainerwillinstantiatethedependentconcreteclassdefinedinthe attributedmethod,injectitintothetargetclass,andexecutethemethod.Forexample,the followingcodeshowshowyoucaninstantiatetheexampletargetclassnamedMyObject containinganattributedmethodthathasadependencyonaclassnamed SomeOtherObject. C#


IUnityContaineruContainer=newUnityContainer(); MyObjectmyInstance=uContainer.Resolve<MyObject>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

3. Inadditiontousingconcretetypesforthedependenciesintargetobjectmethods,youcan useinterfacesorbaseclasstypesandthenregistermappingsintheUnitycontainerto translatethesetypesintotheappropriateconcretetypes.Defineamethodinthetarget classthattakesasparametersinterfacesorbasetypes.Forexample,thefollowingcode showsatargetclassnamedMyObjectcontainingamethodnamedInitializethattakesas parametersanobjectnamedinterfaceObjthatimplementstheinterfacenamed IMyInterfaceandanobjectnamedbaseObjthatinheritsfromtheclassMyBaseClass. C#


182

publicclassMyObject { privateIMyInterfacedepObjectA; privateMyBaseClassdepObjectB; [InjectionMethod] publicvoidInitialize(IMyInterfaceinterfaceObj,MyBaseClassbaseObj) { depObjectA=interfaceObj; depObjectB=baseObj; } }

VisualBasic
PublicClassMyObject PrivatedepObjectAAsIMyInterface PrivatedepObjectBAsMyBaseClass <InjectionMethod()>_ PublicSubInitialize(interfaceObjAsIMyInterface,baseObjAs MyBaseClass) depObjectA=interfaceObj depObjectB=baseObj EndSub EndClass

4. Inyourruntimecode,registerthemappingsyourequirefortheinterfaceandbaseclass types,andthenusetheResolvemethodofthecontainertocreateaninstanceofthetarget class.TheUnitycontainerwillinstantiateaninstanceofeachofthemappedconcretetypes forthedependentclasses,andinjectthemintothetargetclass.Forexample,thefollowing codeshowshowyoucaninstantiatetheexampletargetclassnamedMyObjectcontaining anattributedmethodthathasdependenciesonthetwoclasses,FirstObjectand SecondObject. C#


IUnityContaineruContainer=newUnityContainer() .RegisterType<IMyInterface,FirstObject>() .RegisterType<MyBaseClass,SecondObject>(); MyObjectmyInstance=uContainer.Resolve<MyObject>();

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(OfIMyInterface,FirstObject)()_ .RegisterType(OfMyBaseClass,SecondObject)() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

183

SpecifyingNamedTypeMappings
Theprecedingexampleshowshowyoucanresolvetypesformethodparametersusingthedefault (unnamed)mappingsinthecontainer.Ifyouregistermorethanonemappingforatype,youmust differentiatethembyusinganame.Inthiscase,youcanspecifywhichnamedmappingthe containerwillusetoresolvethemethodparametertypes. Touseattributedmethodcallinjectionwithnamedcontainertypemappings 1. Defineamethodinthetargetclassthattakesasaparametertheconcretetypeofthe dependentclass,andapplyaDependencyattributetotheparameterthatspecifiesthe nameoftheregisteredmappingtouse.Forexample,thefollowingcodeshowsatargetclass namedMyObjectcontainingamethodnamedInitializethathasadependencyonaservice thatimplementstheIMyServiceinterface.Thecodeassumesthatthecontainercontainsa mappingdefinedwiththenameDataServicebetweentheIMyServiceinterfaceanda concreteimplementationofthatinterface. C#
publicclassMyObject { privateIMyServicemyDataService; [InjectionMethod] publicvoidInitialize([Dependency("DataService")]IMyServicetheService) { //assignthedependentobjecttoaclasslevelvariable myDataService=theService; } }

VisualBasic
PublicClassMyObject PrivatemyDataServiceAsIMyService <InjectionMethod()>_ PublicSubInitialize(<Dependency("DataService")>theServiceAs IMyService) 'assignthedependentobjecttoaclasslevelvariable myDataService=theService EndSub EndClass

2. Inyourruntimecode,usetheResolvemethodofthecontainertocreateaninstanceofthe targetclass.TheUnitycontainerwillinstantiatethedependentconcreteclassdefinedinthe attributedmethod,injectitintothetargetclass,andexecutethemethod.Forexample,the followingcodeshowshowyoucaninstantiatetheexampleclassshownabove. C#


IUnityContaineruContainer=newUnityContainer(); MyObjectmyInstance=uContainer.Resolve<MyObject>();
184

VisualBasic
DimuContainerAsIUnityContainer=NewUnityContainer() DimmyInstanceAsMyObject=uContainer.Resolve(OfMyObject)()

Ifyouspecifyanamedmappingandthereisnomappingregisteredforthattypeandname,the containerwillraiseanexception.

NotesonUsingMethodCallInjection
Thefollowingnoteswillhelpyoutogetthegreatestbenefitfromusingmethodcallinjectionwith Unity.

MethodCallInjectionwithExistingObjects
IfyouuseconfigurationortheRegisterInstancemethodtoregisteranexistingobject,methodcall injectiondoesnottakeplaceonthatobjectbecauseithasalreadybeencreatedoutsideofthe influenceoftheUnitycontainer.However,youcancalltheBuildUpmethodofthecontainerand passittheexistingobjecttoforcemethodcallinjectiontotakeplaceonthatobject.

AvoidingCircularReferences
Dependencyinjectionmechanismscancauseapplicationerrorsiftherearecircularreferences betweenobjectsthatthecontainerwillcreate.Formoredetails,seeCircularReferenceswith DependencyInjection.

WhentoUseMethodCallInjection
Youshouldconsiderusingmethodcallinjectioninthefollowingsituations: Whenyouwanttoinstantiatedependentobjectsautomaticallywhenyouinstantiatethe parentobject. Whenyouwantasimpleapproachthatmakesiteasytoseeinthecodewhatthe dependenciesareforeachclass. Whenyouwanttoavoidexposingapublicpropertyjusttoimplementinjection,andinstead useanInitializemethod. Whentheparentobjectrequiresalargenumberofconstructorsthatforwardtoeachother, makingdebuggingandmaintenancedifficult. Whentheparentobjectconstructorsrequirealargenumberofparameters,especiallyifthey areofsimilartypesandtheonlywaytoidentifythemisbyposition.
185

Whenyouwanttohidethedependentobjectsbynotexposingthemasproperties. Whenyouwanttocontrolwhichobjectsareinjectedbyeditingthecodeofthedependent objectinsteadoftheparentobjectorapplication.

Ifyouarenotsurewhichtypeofinjectiontouse,therecommendationisthatyouuseconstructor injection.Thisislikelytosatisfyalmostallgeneralrequirements,unlessyouneedtoperform injectiononexistingobjectinstances. Youcanalsoconfiguremethodcallinjectionatdesigntimeorruntime.Formoreinformation,see ConfiguringUnity.

UsingContainerHierarchies
Unitysupportsnestedcontainers,allowingyoutobuildcontainerhierarchies.Nestingcontainers enablesyoutocontrolthescopeandlifetimeofsingletonobjects,andregisterdifferentmappings forspecifictypes.Thistopiccontainsthefollowingsectionsthatdescribehowyoucancreate containerhierarchiesandusetheminyourapplications: ConstructingandDisposingUnityContainers ControllingObjectScopeandLifetime RegisteringDifferentMappingsforSpecificTypes

ConstructingandDisposingUnityContainers
ThefollowingmethodsenableyoutocreateanewdefaultUnityContainer,createachildcontainer thathasaspecifiedUnityContainerasitsparent,anddisposeanexistingcontainer.Formore informationaboutconfiguringcontainers,seeConfiguringUnity.
Method UnityContainer( ) CreateChildContainer( ) Description Creates a default UnityContainer. Returns a reference to the new container. Creates a new nested UnityContainer as a child of the current container. The current container first applies its own settings, and then it checks the parent for additional settings. Returns a reference to the new container. Disposes this container instance and any child containers. Also disposes any registered object instances whose lifetimes are managed by the container.

Dispose( )

186

ControllingObjectScopeandLifetime
Whenthecontainercreatessingletonobjects,itmanagesthelifetimeofthesesingletons.They remaininscopeuntilyou(orthegarbagecollector)disposethecontainer.Atthispoint,itdisposes theregisteredsingletoninstancesitcontains.Inaddition,ifyoudisposetheparentcontainerina nestedcontainerhierarchy,itautomaticallydisposesallchildcontainersandtheregistered singletonstheycontain. Therefore,ifyourequiretwoseparatesetsofsuchobjectsthatmusthavedifferentlifetimes,you canusehierarchicalcontainerstostoreandmanageeachset.Registerinstancesthatyouwanttobe abletodisposeseparatelyinoneormorechildcontainersthatyoucandisposewithoutdisposing theparentcontainer. Thefollowingcodedemonstratestheuseofachildcontainertomanagethelifetimeofspecific singletoninstanceswhilemaintainingthesingletoninstancesintheparentcontainer. C#
//Createparentcontainer IUnityContainerparentCtr=newUnityContainer(); //Registertypeinparentcontainer parentCtr.RegisterType<MyParentObject>(newContainerControlledLifetimeManager()); //Createnestedchildcontainerinparentcontainer IUnityContainerchildCtr=parentCtr.CreateChildContainer(); //Registertypeinchildcontainer childCtr.RegisterType<MyChildObject>(newContainerControlledLifetimeManager()); //Createinstanceoftypestoredinparentcontainer MyParentObjectparentObj=parentCtr.Resolve<MyParentObject>(); //Createinstanceoftypestoredinchildcontainer MyChildObjectchildObj=childCtr.Resolve<MyChildObject>(); //...canusebothgeneratedobjectshere... //Disposechildcontainer childCtr.Dispose(); //...canuseonlyobjectinparentcontainerhere... //Disposeparentcontainer parentCtr.Dispose();

VisualBasic
'Createparentcontainer DimparentCtrAsIUnityContainer=NewUnityContainer() 'Registertypeinparentcontainer parentCtr.RegisterType(OfMyParentObject)(New ContainerControlledLifetimeManager())
187

'Createnestedchildcontainerinparentcontainer DimchildCtrAsIUnityContainer=parentCtr.CreateChildContainer() 'Registertypeinchildcontainer childCtr.RegisterType(OfMyChildObject)(NewContainerControlledLifetimeManager()) 'Createinstanceoftypestoredinparentcontainer DimparentObjAsMyParentObject=parentCtr.Resolve(OfMyParentObject)() 'Createinstanceoftypestoredinchildcontainer DimchildObjAsMyChildObject=childCtr.Resolve(OfMyChildObject)() '...canusebothgeneratedobjectshere... 'Disposechildcontainer childCtr.Dispose() '...canuseonlyobjectinparentcontainerhere... 'Disposeparentcontainer parentCtr.Dispose()

YoucanalsospecifythelifetimeofobjectsbyusingtheLifetimeManagerparameterwhenyou registertypesorexistingobjectswiththecontainer.Formoreinformationabouthowtousethe LifetimeManagerparameter,seeUnderstandingLifetimeManagersandConfiguringUnity.For moreinformationabouthowtocreatecustomlifetimemanagers,seeCreatingLifetimeManagers.

RegisteringDifferentMappingsforSpecificTypes
Youcanusenestedcontainerswhenyouhaveslightlydifferentdependencyinjectionrequirements forspecificobjectsbutwanttoprovideafallbackfacilityforobjectsthatimplementaspecific interfaceorareofaspecifictype.Forexample,youmayhaveageneralrequirementforobjectsthat implementtheIMyObjectinterfacetomaptothetypeMyStandardObject.However,inspecific partsoftheapplicationcode,youmaywanttheIMyObjectinterfacetomaptothetype MySpecialObject. Inthiscase,youcanregisterthegeneralmappingintheparentcontainerandregisterthespecific caseinachildcontainer.Then,whenyouwanttoobtainaninstanceoftheobject,youcallthe Resolvemethodontheappropriatecontainer.Ifyoucallthemethodonthechildcontainer,it returnsanobjectoftypeMySpecialObject.Ifyoucallthemethodontheparentcontainer,itreturns anobjectoftypeMyStandardObject. However,theadvantagewithnestedcontainersisthat,ifthechildcontainercannotlocatea mappingfortherequestedinterfaceortype,itpassestherequesttoitsparentcontainerand onwardthroughthehierarchyuntilitreachestherootorbasecontainer.Therefore,forobjectsnot mappedinthechildcontainer,themappingintheparentcontainer(orinanancestorcontainer wheretherearemorethantwolevelsinthehierarchy)definestheobjecttypereturned.
188

Thefollowingcodeshowshowyoucanimplementtheprecedingscenario. C#
//Createparentcontainer IUnityContainerparentCtr=newUnityContainer(); //Registertwomappingsfortypesinparentcontainer parentCtr.RegisterType<IMyObject,MyStandardObject>(); parentCtr.RegisterType<IMyOtherObject,MyOtherObject>(); //Createnestedchildcontainerinparentcontainer IUnityContainerchildCtr=parentCtr.CreateChildContainer(); //Registermappingforspecifictypeinchildcontainer childCtr.RegisterType<IMyObject,MySpecialObject>(); //Nowretrieveinstancesofthemappedobjectsusingthechildcontainer. //Usingtheinterfaceasthetypeforthereturnedobjectsmeansthatit //doesnotmatterwhichcontainerreturnstheactualobject. //ThiscodereturnsanobjectoftypeMySpecialObjectusingthemapping //registeredinthechildcontainer: IMyObjectspecialObject=childCtr.Resolve<IMyObject>(); //ThiscodereturnsanobjectoftypeMyOtherObjectusingthemapping //registeredintheparentcontainerbecausethereisnomappingin //thechildcontainerforthistype: IMyOtherObjectotherObject=childCtr.Resolve<IMyOtherObject>(); //Nowretrieveinstanceofthestandardobjectusingtheparentcontainer. //ThiscodereturnsanobjectoftypeMyStandardObjectusingthemapping //registeredintheparentcontainer: IMyObjectstandardObject=parentCtr.Resolve<IMyObject>(); //Disposeparentcontainerandchildcontainer parentCtr.Dispose();

VisualBasic
'Createparentcontainer DimparentCtrAsIUnityContainer=NewUnityContainer() 'Registertwomappingsfortypesinparentcontainer parentCtr.RegisterType(OfIMyObject,MyStandardObject)() parentCtr.RegisterType(OfIMyOtherObject,MyOtherObject)() 'Createnestedchildcontainerinparentcontainer DimchildCtrAsIUnityContainer=parentCtr.CreateChildContainer() 'Registermappingforspecifictypeinchildcontainer childCtr.RegisterType(OfIMyObject,MySpecialObject)() 'Nowretrieveinstancesofthemappedobjectsusingthechildcontainer. 'Usingtheinterfaceasthetypeforthereturnedobjectsmeansthatit
189

'doesnotmatterwhichcontainerreturnstheactualobject. 'ThiscodereturnsanobjectoftypeMySpecialObjectusingthemapping 'registeredinthechildcontainer: DimspecialObjectAsIMyObject=childCtr.Resolve(OfIMyObject)() 'ThiscodereturnsanobjectoftypeMyOtherObjectusingthemapping 'registeredintheparentcontainerbecausethereisnomappingin 'thechildcontainerforthistype: DimotherObjectAsIMyOtherObject=childCtr.Resolve(OfIMyOtherObject)() 'Nowretrieveinstanceofthestandardobjectusingtheparentcontainer. 'ThiscodereturnsanobjectoftypeMyStandardObjectusingthemapping 'registeredintheparentcontainer: DimstandardObjectAsIMyObject=parentCtr.Resolve(OfIMyObject)() 'Disposeparentcontainerandchildcontainer parentCtr.Dispose()

CircularReferenceswithDependency Injection
Dependencyinjectionmechanismscarrytheriskofunintentionalcircularreferences,whicharenot easytodetectorprevent.Thistopicdescribesthesituationswhereyoumayinadvertentlycause circularreferencestooccur,resultinginastackoverflowandapplicationerror.Themostcommon causesofcircularreferenceswithdependencyinjectionarethefollowing: Objectsgeneratedthroughconstructorinjectionthatreferenceeachotherintheirconstructor parameters Objectsgeneratedthroughconstructorinjectionwhereaninstanceofaclassispassedasa parametertoitsownconstructor Objectsgeneratedthroughmethodcallinjectionthatreferenceeachother Objectsgeneratedthroughproperty(setter)injectionthatreferenceeachother

Forexample,thefollowingcodeshowstwoclassesthatreferenceeachotherintheirconstructors. C#
publicclassClass1 { publicClass1(Class2test2) {...} } publicclassClass2
190

{ publicClass2(Class1test1) {...} }

VisualBasic
PublicClassClass1 PublicSubNew(test2AsClass2) ... EndSub EndClass PublicClassClass2 PublicSubNew(test1AsClass1) ... EndSub EndClass

Itistheresponsibilityofthedevelopertopreventthistypeoferrorbyensuringthatthemembersof classestheyusewithdependencyinjectiondonotcontaincircularreferences. Youcoulduseconstructorinjectiontospecifyanyofaseriesofconstructorsormethodoverloads; however,youcouldinadvertentlycauseendlessrecursion.Toavoidtheendlessrecursion,specify whichconstructortocallintheRegisterTypecall. Unity'sdefaultbehavioristoresolvetheconstructorwiththemostparameters.Thiswouldcause endlessrecursioninthefollowingexample. C#


container.RegisterType<IServiceProvider,ServiceContainer>(); varsp=container.Resolve<IServiceProvider>();

VisualBasic
container.RegisterType(OfIServiceProvider,ServiceContainer)() Dimsp=container.Resolve(OfIServiceProvider)()

Toavoidtheendlessrecursion,specifywhichconstructortocallintheRegisterTypecall,asinthe followingexample: C#
container.RegisterType<IServiceProvider,ServiceContainer>(new InjectionConstructor());

VisualBasic
container.RegisterType(OfIServiceProvider,ServiceContainer)_ (NewInjectionConstructor())

Inthiscase,whencreatingtheservicecontainer,thezeroargumentconstructorisexplicitly requested.
191

DesignofUnity
Thistopicdescribesthedesigngoals,thearchitecture,andthedesignhighlightsofUnity.Youdonot havetounderstandthedesigntouseUnity;however,thistopicwillhelpyoutounderstandhowit worksandhowitinteractswiththeunderlyingObjectBuildersubsystem.

DesignGoals
Unitywasdesignedtoachievethefollowinggoals: Promotetheprinciplesofmodulardesignthroughaggressivedecoupling. Raiseawarenessoftheneedtomaximizetestabilitywhendesigningapplications. Provideafastandlightweightdependencyinjectioncontainermechanismforcreatingnew objectinstancesandmanagingexistingobjectinstances. ExposeacompactandintuitiveAPIfordeveloperstoworkwiththecontainer. Supportawiderangeofcodelanguages,withmethodoverridesthatacceptgeneric parameterswherethelanguagesupportsthese. Implementattributedriveninjectionforconstructors,propertysetters,andmethodsoftarget objects. Provideextensibilitythroughcustomandthirdpartycontainerextensions. Providetheperformancerequiredinenterpriselevellineofbusiness(LOB)applications.

Operation
ThepublicmethodsoftheUnityContainerthatdevelopersusefallintotwomaincategories: Methodsthatregistermappingsortypes.ThemethodsRegisterTypeandthe RegisterInstancecreatetheappropriateentrieswithinthecurrentcontainercontext. Methodsthatretrieveobjects.TheseincludeoverridesoftheResolve,ResolveAll,and BuildUpmethods.Thesemethodsretrievetherequiredinstancesoftheobjects.

ExtendingandModifyingUnity
192

Ifrequired,youcanextendandmodifyUnitytobettersuityourownrequirements.Youcanextend Unitybydoingthefollowing: CreatingLifetimeManagersthatcontrolhowandwhenthecontainerwilldisposeofinstances ofobjectsitresolves. CreatingandUsingContainerExtensionsthatcanchangethebehaviorofthecontainer,the instancegenerationmechanism,andthedependencyinjectionandinterceptionfeatures. CreatingPolicyInjectionMatchingRulesthatprovidesalternativetechniquesforselecting classesandclassmemberstowhichUnitywillattachahandlerpipeline. CreatingInterceptionPolicyInjectionCallHandlersthatperformthetaskspecificprocessing yourequireformethodinvocationsandpropertyaccessors. CreatingInterceptionHandlerAttributesthatcauseUnitytoaddbuiltinorcustomcall handlerstothehandlerpipeline.Ifyoucreateacustomhandler,youmayalsowanttocreate acustomattributethatdeveloperscanusetoapplyyourhandlerbyaddingtheattribute directlytoclassesorclassmemberswithinthesourcecodeofanapplication. CreatingInterceptionBehaviorsthatdescribewhattodowhenanobjectisintercepted.

CreatingLifetimeManagers
Unitysupportsseveralapproachesforregisteringclasses,interfaces,andinstancesofexisting objects.YoucanusetheRegisterTypeandRegisterInstancemethodstoregisterobjectinstancesat runtime,orspecifythemappingsandregistrationsatdesigntimeinconfiguration.Youcanalso specifyalifetimemanagerwithalloftheseapproachesthatwillcontrolhowUnityresolves instancesofthespecifiedtypesandhowitholdsreferencestotheseinstances.Thebuiltinlifetime managersallowyoutospecifyobjectsassingletons,withweakreferences,orasperthread instances.Formoredetails,seeUnderstandingLifetimeManagers. YoucancreatecustomLifetimeManagerclassesifyourequireadditionalfunctionalitynotavailable inthedefaultlifetimemanagers.DocumentationtohelpyoudothisisavailablefromtheUnity CommunityWebsiteonCodePlex.

CreatingandUsingContainer Extensions
YoucancreateyourowncustomUnitycontainerextensions,orusecontainerextensionscreatedby thirdpartieswithUnity.Unityusesdefaultcontainerextensionstoimplementitsownfunctionality.
193

Forexample,theinterceptionmechanismprovidedbyUnityisimplementedasacontainer extension. DocumentationtohelpyouunderstandObjectBuilder,andthestepsrequiredtocreatecustom containerextensions,isavailablefromtheUnityCommunityWebsiteonCodePlex.

CreatingPolicyInjectionMatching Rules
UnitydefinesaninterfacenamedIMatchingRule,whichallclassesthatimplementmatchingrules mustimplement.ThisinterfacedeclaresasinglemethodnamedMatchesthattakesaMethodBase instanceandreturnsaBooleanvalue. C#
publicinterfaceIMatchingRule { boolMatches(MethodBasemember); }

VisualBasic
PublicInterfaceIMatchingRule FunctionMatches(ByValmemberAsMethodBase)AsBoolean EndInterface

Insideaconcreteimplementationofthisinterface,acustommatchingruleclasscanaccessdetails ofthecurrentmember(methodorproperty)ofthetargetobjectanddeterminewhetherUnity shouldaddahandlerpipelinetothismember.TheMatchesmethodshouldreturnTrueifthe currentmembermatchestherequirementsofthismatchingrule;ifthecurrentmemberdoesnot matchtherequirementsofthismatchingrule,itshouldreturnFalse. Rememberthattheremaybeseveralmatchingrulesdefinedforapolicy,andeveryonemust returnTruewhenUnitycallstheirMatchesmethodinorderforUnitytoaddthehandlerpipeline tothetargetclassmember.

Example:TheTagAttributeMatchingRule
Asanexampleofamatchingrule,thisfollowingextractshowstheTagAttributeMatchingRuleclass thatimplementsthebuiltintagattributematchingrule.Thisruleexaminesthecurrenttarget objectmember,passedtotheMatchesmethodasaparameter,lookingforanyattributesoftype TagAttribute,whosevaluematchesthestringvaluepassedtotheclassconstructor. C#
[ConfigurationElementType(typeof(TagAttributeMatchingRuleData))]
194

publicclassTagAttributeMatchingRule:IMatchingRule { privatereadonlystringtagToMatch; privatereadonlyboolignoreCase; //Thisconstructortakesonlythetagvalue. publicTagAttributeMatchingRule(stringtagToMatch) :this(tagToMatch,false) {} //Thisconstructortakesthetagvalueandthecasesensitivitysetting. publicTagAttributeMatchingRule(stringtagToMatch,boolignoreCase) { this.tagToMatch=tagToMatch; this.ignoreCase=ignoreCase; } //ThereturnstrueonlyifamatchingTagAttributeexistsonthismember. publicboolMatches(MethodBasemember) { foreach(TagAttributetagAttributein ReflectionHelper.GetAllAttributes<TagAttribute>(member,true)) { if(string.Compare(tagAttribute.Tag,tagToMatch,ignoreCase)==0) { returntrue; } } returnfalse; } }

VisualBasic
<ConfigurationElementType(GetType(TagAttributeMatchingRuleData))>_ PublicClassTagAttributeMatchingRule:ImplementsIMatchingRule DimtagToMatchAsString DimignoreCaseAsBoolean 'Thisconstructortakesonlythetagvalue. PublicSubNew(ByValtagToMatchAsString) Me.New(tagToMatch,false) EndSub 'Thisconstructortakesthetagvalueandthecasesensitivitysetting. PublicSubNew(ByValtagToMatchAsString,ByValignoreCaseAsBoolean) Me.tagToMatch=tagToMatch Me.ignoreCase=ignoreCase EndSub 'ThereturnstrueonlyifamatchingTagAttributeexistsonthismember. PublicFunctionMatches(ByValmemberAsMethodBase)AsBooleanImplements IMatchingRule.Matches
195

ForEachtagAttributeAsTagAttributeIn_ ReflectionHelper.GetAllAttributes(OfTagAttribute)(member,true) Ifstring.Compare(tagAttribute.Tag,tagToMatch,ignoreCase)=0Then ReturnTrue EndIf Next ReturnFalse EndSub EndClass

WhenUnityfirstcreatesaninstanceofthetargetobject,itreadsalistofmatchingrulesfromthe configuration.Foreachruleitfinds,itcreatesaninstanceoftheappropriateclassandpassestoitas parametersthevaluesofanyattributesdefinedwithintheconfigurationforthatmatchingrule.You canseethattheconstructorsfortheTagAttributeMatchingRuleclassacceptthenameofthe attributeandacasesensitivityvalue. Internally,theTagAttributeMatchingRuleclassusesaseparatehelperclassnamed ReflectionHelperthatgetsalistofalltheattributesoftypeTagAttributeonthetargetmemberso thattheMatchesmethodcandetectanythathasthespecifiedvaluetakingintoaccountthe settingoftheignoreCasepropertyforthishandlerinstance. NoticethattheTagAttributeMatchingRuleclasshasaConfigurationElementTypeattributethat definestheclass(TagAttributeMatchingRuleData)thattheconfigurationsystemusestoexposethe datafromtheconfigurationtothematchingrule.Asanalternativeapproach,youcanalsousethe CustomMatchingRuleDataclassinthisattribute.Thiseliminatestheneedtocreateyourown configurationdataclass;however,configurationinformationwillbeprovidedasadictionaryandwill notbestronglytyped.

CreatingInterceptionPolicyInjection CallHandlers
Tocreateacallhandlerforpolicyinjection,youmustunderstandthewaythatUnitypassescalls throughthepolicypipeline.Thistopicexplainshowthepipelineexecutescallhandlers,andhowit canblockorabortexecutionwhenanerroroccurs,orondemand(suchaswhenavalidation handlerdetectsavalidationerrororanauthorizationhandlerdetectsanunauthorizeduser).This topiccontainsthefollowingsections: TheICallHandlerInterfaceandPipelineExecution OutlineImplementationofaCallHandler ExceptionsandAbortedPipelineExecution

196

TheICallHandlerInterfaceandPipelineExecution
TheUnityinterceptionmechanismdefinesaninterfacenamedICallHandler,whichallclassesthat implementhandlersforacallhandlerpipelinemustimplement.Thisinterfacedefinestwodelegates andasinglemethodnamedInvoke.Thefirstdelegate,namedInvokeHandlerDelegate,iscalledby theprevioushandlertoexecutethishandlerandthereforehasthesamesignatureastheInvoke method.Thesecond,namedGetNextHandlerDelegate,determineswhichisthenexthandlerinthe chaintoinvoke(thehandlertowhichthishandlershouldpasscontrolwhenitcompletesitsown preprocessingstage). ThesignaturefortheInvokeHandlerDelegateandtheInvokemethodcontainsaninstanceofaclass thatimplementstheIMethodInvocationinterfaceandareferencetoaninstanceofthe GetNextHandlerDelegateclass.TheIMethodInvocationimplementationinstancecontains informationaboutthecurrentmethodinvocationorpropertyaccess,includingtheparametersto passtothemethodorproperty. TheInvokemethodreturnsaninstanceofaclassthatimplementstheIMethodReturninterface. Thisclassinstancecontainsanyreturnvaluefromthemethodorpropertyaccessorandanyother informationtoreturntotheclient.Usually,thisisaconcreteinstanceoftheReturnMessageclass. ThefollowingextractshowsthecompleteICallHandlerinterface. C#
publicinterfaceICallHandler { IMethodReturnInvoke(IMethodInvocationinput,GetNextHandlerDelegategetNext); intOrder{get;set;} } publicdelegateIMethodReturnInvokeHandlerDelegate(IMethodInvocationinput, GetNextHandlerDelegategetNext); publicdelegateInvokeHandlerDelegateGetNextHandlerDelegate();

VisualBasic
PublicInterfaceICallHandler FunctionInvoke(ByValinputAsIMethodInvocation,_ ByValgetNextAsGetNextHandlerDelegate)AsIMethodReturn PropertyOrder()AsInteger EndInterface PublicDelegateFunctionInvokeHandlerDelegate(ByValinputAsIMethodInvocation, _ ByValgetNextAsGetNextHandlerDelegate)AsIMethodReturn PublicDelegateFunctionGetNextHandlerDelegate()AsInvokeHandlerDelegate

Thecallhandlerpiplineispartofthepolicyinjectionbehaviorwhich,ifused,isjustonebehaviorin thebehaviorspipelinewhenperformingInterceptionwithUnity. Thefollowingschematicshowstheprocessforinvocationthroughthecallhandlerpipelineunder normalconditions.


197

OutlineImplementationofaCallHandler
ThefollowingextractshowsthebasicoutlineoftheInvokemethodforacustomhandlerclass, indicatingwhereyoucanaddcodetoperformboththepreprocessingandpostprocessingtasksyou require.ThecodeexcludesthedefinitionoftheconstructorsandtheOrderproperty. C#
[ConfigurationElementType(typeof(CustomCallHandlerData))] publicclassExampleHandler:ICallHandler { publicIMethodReturnInvoke(IMethodInvocationinput, GetNextHandlerDelegategetNext) { //Declareanyvariablesrequiredforvaluesusedinthismethodhere. ... ... //Performanypreprocessingtasksrequiredinthecustomhandlerhere. //Thiscodeexecutesbeforecontrolpassestothenexthandler. ... ... //Usethefollowinglineofcodeinanyhandlertoinvokethenext //handlerthatUnityshouldexecute.Thiscodegets //thecurrentreturnmessagethatyoumustpassbacktothecaller: IMethodReturnmsg=getNext()(input,getNext); //Performanypostprocessingtasksrequiredinthecustomhandlerhere. //Thiscodeexecutesaftertheinvocationofthetargetobjectmethodor //propertyaccessor,andbeforecontrolpassesbacktotheprevious //handlerastheInvokecallstackunwinds.Youcanmodifythereturn //messageifrequired. ... ... //Returnthemessagetothecallingcode,whichmaybetheprevious //handleror,ifthisisthefirsthandlerinthechain,theclient. returnmsg; }
198

...otherclassmembersasrequiredhere }

VisualBasic
<ConfigurationElementType(GetType(CustomCallHandlerData))>_ PublicClassExampleHandler:ImplementsICallHandler PublicFunctionInvoke(ByValinputAsIMethodInvocation,_ ByValgetNextAsGetNextHandlerDelegate)AsIMethodReturn_ ImplementsICallHandler.Invoke 'Declareanyvariablesrequiredforvaluesusedinthismethodhere. ... ... 'Performanypreprocessingtasksrequiredinthecustomhandlerhere. 'Thiscodeexecutesbeforecontrolpassestothenexthandler. ... ... 'Usethefollowinglineofcodeinanyhandlertoinvokethenext 'handlerthatUnityshouldexecute.Thiscodegets 'thecurrentreturnmessagethatyoumustpassbacktothecaller: DimmsgAsIMethodReturn=getNext()(input,getNext) 'Performanypostprocessingtasksrequiredinthecustomhandlerhere. 'Thiscodeexecutesaftertheinvocationofthetargetobjectmethodor 'propertyaccessor,andbeforecontrolpassesbacktotheprevious 'handlerastheInvokecallstackunwinds.Youcanmodifythereturn 'messageifrequired. ... ... 'Returnthemessagetothecallingcode,whichmaybetheprevious 'handleror,ifthisisthefirsthandlerinthechain,theclient. Returnmsg EndFunction ...otherclassmembersasrequiredhere EndClass

TheInvokemethodreceivesareferencetoaninstanceofaconcreteimplementationofthe IMethodInvocationclass.Yourhandlercanaccessthepropertiesofthisinstancetogetinformation aboutthecurrentmethodorpropertyaccessorcall.Forexample,youcanaccessthetargetobject instance(Target),thenameofthetargetmethodorproperty(MethodBase.Name),acountofthe numberofinputs(Inputs.Count),andacollectionofalltheparametervalues(Arguments).

199

YourcodecanchangethevaluesofthepropertiesoftheIMethodInvocationinstance.However, beawarethatchangingthevaluesofsomepropertiesmaycauseunexpectedbehavior.Youshould avoidchanginganypropertiesthataffectthename,type,orsignatureofthetargetmember. Unityreuseshandlerinstancesindifferentpipelinestominimizethenumberofobjectsitmust create.Therefore,handlersshouldnotstoreanypercallstateinmembervariables.Inmulti threadedapplications,theactionofmultiplecallspassingthroughthesamehandlerinstanceis likelytocorrupttheinternalstate.

ExceptionsandAbortedPipelineExecution
Exceptionsmayoccurinacallhandler,oracallhandlermaywishtoabortorshortcircuitexecution sothatthesubsequenthandlersinthepipelinedonotexecuteandUnitydoesnotinvokethetarget methodorpropertyaccessor.Inthiscase,yourcodeshouldsimplyavoidcallingthenexthandler andgenerateasuitablereturnmessage.Inotherwords,youomitthecodelineshowninthe previousexamplethatcallsthegetNextmethod.Thiscausesalltheprevioushandlerstoexecute theirpostprocessingtasksastheInvokestackunwinds. Ifyourhandlerhastoabortprocessingcompletelywithoutallowingprevioushandlerstoexecute, youcancreateandraiseasuitableexceptiontypedependingonthetasksthatyourhandler carriesout.However,inmostcases,youshouldavoidthisapproachand,instead,addtothe messageanyexceptionsyouwanttoraisetotheclientsothatprevioushandlers(whichmay performloggingorprocessexceptions)canexecutetheirpostprocessingtasks. Forexample,thefollowingschematicillustratesascenariowhereahandlerinthehandlerpipeline abortsexecution.Inthisscenario,thehandlerpipelinecontainsinexecutionorderahandlerthat performslogging,ahandlerthatperformsauthorization,andahandlerthatvalidatesthevaluesin theparametersofthemethodcall.

If,asshownintheschematic,theauthorizationhandlerdetectsanauthorizationfailure,itcan returnanexceptiontotheoriginalcallerbyaddingittothemessagethatpassesalongthehandler
200

pipeline.Thisallowshandlersearlierinthepipelinetocarryouttheirpostprocessingtasks(suchas, inthisexample,creatingandwritingalogmessage)asthestackunwinds.If,insteadofpassingit backthroughthemessage,ahandlerraisesanunhandledexception,theprevioushandlerswillnot beabletoexecutetheirpostprocessingtasks. Toaddanexceptiontothemessage,youcreateanewinstanceoftheReturnMessageclassusing theconstructorthatacceptsaSystem.ExceptioninstanceorasubclassofSystem.Exception.For example,thiscodeshowshowyoucanaddanexceptiontothereturnmessagewhenthecurrent methodrequestforsomebusinessrelatedactivityoccursonaSaturdayorSunday. C#


publicIMethodReturnInvoke(IMethodInvocationinput,GetNextHandlerDelegate getNext) { GregorianCalendarcal=newGregorianCalendar(); DayOfWeekweekDay=cal.GetDayOfWeek(DateTime.Now); if((weekDay==DayOfWeek.Saturday)||(weekDay==DayOfWeek.Sunday)) { //Createtheexceptiontoreturnandthereturnmessage. Exceptionex=newException("Availableonweekdaysonly"); IMethodReturnmsg=input.CreateExceptionMethodReturn(ex); returnmsg; } else { //Donothingexceptinvokethenexthandler. returngetNext()(input,getNext); } }

VisualBasic
PublicFunctionInvoke(ByValinputAsIMethodInvocation,_ ByValgetNextAsGetNextHandlerDelegate)AsIMethodReturn_ ImplementsICallHandler.Invoke DimcalAsNewGregorianCalendar() DimweekDayAsDayOfWeek=cal.GetDayOfWeek(DateTime.Now) If(weekDay=DayOfWeek.Saturday)Or(weekDay=DayOfWeek.Sunday)Then 'Createtheexceptiontoreturnandthereturnmessage. DimexAsNewException("Availableonweekdaysonly") DimmsgAsIMethodReturn=input.CreateExceptionMethodReturn(ex) Returnmsg Else 'Donothingexceptinvokethenexthandler. returngetNext()(input,getNext) EndIf EndFunction

201

CreatingInterceptionHandler Attributes
Handlerattributesallowdeveloperstoapplyhandlerstoclassesandclassmembersdirectly,without configuringthemintheapplicationconfigurationfile.Developerscreatingcustomhandlersmay wanttoprovideanattributefortheirhandlers.Tobuildacustomhandlerattribute,youcreatea classthatderivesfromtheHandlerAttributebaseclassshownhere. C#
publicabstractclassHandlerAttribute:Attribute { ///Derivedclassesimplementthismethod.Whencalled,itcreatesa ///newcallhandlerasspecifiedintheattributeconfiguration. ///Theparameter"container"specifiestheIUnityContainer ///tousewhencreatinghandlers,ifnecessary. ///returnsanewcallhandlerobject. publicabstractICallHandlerCreateHandler(IUnityContainercontainer); privateintexecutionorder; ///<summary> ///Getsorsetstheorderinwhichthehandlerwillbeexecuted. ///</summary> publicintOrder { get{returnthis.executionorder;} set{this.order=value;} } }

VisualBasic
PublicMustInheritClassHandlerAttribute:InheritsAttribute '''Derivedclassesimplementthismethod.Whencalled,itcreatesa '''newcallhandlerasspecifiedintheattributeconfiguration. '''TheparametercontainerspecifiestheIUnityContainer '''tousewhencreatinghandlers,ifnecessary. '''Returnsanewcallhandlerobject. PublicMustOverrideFunctionCreateHandler(containerAsIUnityContainer)As ICallHandler PrivateexecutionorderAsInteger '''<summary> '''Getsorsetstheorderinwhichthehandlerwillbeexecuted. '''</summary> PublicPropertyOrderAsInteger Get ReturnMe.executionorder EndGet
202

Set Me.order=value EndSet EndProperty EndClass

Inyourcustomattributeclass,youmustimplementoneormoreconstructorsthatacceptvalues fromtheattribute,and/orimplementnamedpropertiesthatthedevelopercanusetosetthe propertiesoftheclass.ThenyousimplyoverridetheCreateHandlerabstractmethoddeclared withinthebaseclasstocreateandreturntherequiredhandlerclassasanICallHandlerinstance.

ExampleCallHandlerAttribute
Asanexample,youcouldcreateacallhandlerattributeforacallhandlersimilartothatdescribedin thetopicCreatingInterceptionPolicyInjectionCallHandlersthatpreventsinvocationofbusiness processesonweekenddays.Inthiscase,assumethatthehandlerhasapropertynamed SaturdayOKthatallowsyoutosetittoallowcallstooccuronaSaturday.Thecallhandlerhastwo constructors:onethattakesaparameterthatsetsthevalueoftheSaturdayOKpropertytothe specifiedvalue(trueorfalse),andonethattakesnoparametersandsetsthedefaultvalue(false) fortheSaturdayOKproperty.Thefollowingcodeshowsanimplementationofthe WeekdayOnlyCallHandlerAttribute. C#
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Property| AttributeTargets.Method)] publicclassWeekdayOnlyCallHandlerAttribute:HandlerAttribute { privateboolallowSaturday; publicWeekdayOnlyCallHandlerAttribute() { allowSaturday=false; } publicWeekdayOnlyCallHandlerAttribute(boolSaturdayOK) { allowSaturday=SaturdayOK; } publicoverrideICallHandlerCreateHandler(IUnityContainerignored) { returnnewWeekdayOnlyCallHandler(allowSaturday,Order); } }

VisualBasic
<AttributeUsage(AttributeTargets.ClassOrAttributeTargets.PropertyOr AttributeTargets.Method)>_ PublicClassWeekdayOnlyCallHandlerAttribute:InheritsHandlerAttribute
203

PrivateallowSaturdayAsBoolean PublicSubNew() allowSaturday=False EndSub PublicSubNew(SaturdayOKAsBoolean) allowSaturday=SaturdayOK EndSub PublicOverridesFunctionCreateHandler(ignoredAsIUnityContainer)As ICallHandler ReturnNewWeekdayOnlyCallHandler(allowSaturday,Order) EndFunction EndClass

NoticetheAttributeUsageattributethatspecifieswheredeveloperscanapplythenewcustom attribute(onaclass,aproperty,oramethod),andinthiscasetheprovisionoftwoconstructors. Thefirst(default)constructorusesthedefaultvalue(false),whilethesecondacceptsavalueforthe SaturdayOKproperty.TheCreateHandlermethodoverrideinstantiatesthe WeekdayOnlyCallHandlerclasswiththeappropriatevaluesandreturnsthisasanICallHandler reference.

CreatingInterceptionBehaviors
UnityusestheInterceptorclasstospecifyhowinterceptionhappens,andtheInterceptionBehavior classtodescribewhattodowhenanobjectisintercepted.Unityinterceptionutilizesabehavior pipelinetoforthebehaviors.TheInterceptionBehaviorPipelinemaintainsalistofinterception behaviorsandmanagesthem,callingthemintheproperorderwiththecorrectinputs. ForinformationonthedetailsaboutinterceptionbehaviorsseeInterceptionwithUnityand BehaviorsforInterception.

DeploymentandOperations
WhenyouuseUnityinyourapplications,youmustdeploytherequiredassemblieswithyour applicationorinstalltheassembliesonthetargetcomputerintheglobalassemblycache(GAC).You mustincludetheassemblynamedMicrosoft.Practices.Unity.dll.Ifyouareusinginterception,you willalsorequiretheassemblynamedMicrosoft.Practices.Unity.Interception.dll. YoucandeployanapplicationthatusesUnityinoneoftwoconfigurations:
204

Asprivateassembliesintheapplicationfolderhierarchy Assharedassembliesinanyfilesystemlocationorintheglobalassemblycache

ForadviceonusingUnitywithapplicationsthatruninpartialtrustmodes,seeUsingUnityinPartial TrustEnvironments. ForadviceonupdatingexistingversionsofUnityassemblies,seeUpdatingtheUnityAssemblies. WhenyoucompiletheinstalledversionofUnitysourcecode,theassembliesproducedwillnotbe strongnamed.Asaresult,theycannotbeinstalledintheglobalassemblycache,norwilltheyhave theotherbenefitsassociatedwithstrongnamedassemblies.TolearnhowtostrongnameUnity assemblies,seeStrongNamingtheUnityAssemblies. Unitythrows(andhandlesinternally)LockSynchronizationexceptions.LockSynchronization exceptionsmaybeobservedinthedebuggeroutputbuttheyarehandledinternallyandnoaction isrequired.

UsingXCopy
YouarenotrequiredtousestrongnamesortoinstallUnityassembliesintheglobalassemblycache. YoucancompileanddeployUnitywithoutmodifyingitinthedirectorystructureofany applicationthatusesUnity.Thissimplifiesdeploymentbecauseyoucanusethexcopycommandto installtheentireapplication,includingtheUnityassemblies,onthetargetcomputer.However,if multipleapplicationsonthesamecomputeruseUnity,youmustinstallacopyoftheassembliesin eachapplication'sfolderhierarchy.

UsingtheGlobalAssemblyCache
Alternatively,youcansignUnityassemblieswithastrongnamekey.Thiswillensurethattheir namesaregloballyuniqueandwillalsoprovideversioning.Ifyoutakethisadditionalstep,youcan deployUnityassembliesinasharedlocationandmultipleapplicationscanusethem.Forexample, youcoulddeployUnityassembliesintheglobalassemblycache.Ifyoudothis,allapplicationson thecomputercanuseUnity.TolearnhowtostrongnameUnityassemblies,seeStrongNamingthe UnityAssemblies.

InstallinganAssemblyintheGlobalAssemblyCache
Youcanuseoneofthefollowingtoolstoinstallanassemblyintheglobalassemblycache: Aninstallerprogram,suchastheMicrosoftWindowsInstallerversion2.0 Theglobalassemblycachetoolcommandlineutility(Gacutil.exe) The.NETFrameworkconfigurationtool(Mscorcfg.msc)
205

Formoreinformationaboutdeploying.NETapplications,seeDeploying.NETFrameworkbased ApplicationsonMSDN.

Versioning
AlltheassembliesprovidedwithUnityarestrongnamed,whichprovidesversioningandnaming protection.Thismeansthatthenameofthebinarycodeisguaranteedtobeuniqueandthatthe versionsbeingloadedaretheonesintendedtobeusedwiththeapplication.Becausethe assembliesarestrongnamed,youcaninstallthemintheglobalassemblycache,wheretheycanbe sharedbymultipleapplicationsonthecomputer. TheUnityinstallationpackageincludescompiledassembliesforUnity.Italsoincludesthesource codeandscriptsthatyoucanruntocreatethecompliedassemblies.Theassembliesyoucreatethis wayarenotstrongnamed.Tosignanassemblywithastrongname,youmusthaveapublic/private keypair.Formoreinformation,seeStrongNamedAssembliesandVersioningTutorial. ItisnotrecommendedthatyouuseUnitynamespacesbecauseitmakesitdifficulttoidentifythe sourceofthecode.Instead,youshouldchoosearootnamespacethatmeetsyourowncodingand versioningstandards.

UsingUnityinPartialTrust Environments
Unityusesdynamicallygeneratedmethodstoperforminjection,andthe.NETFrameworksecurity modelimposessomesecuritylimitationsthatyoushouldbeawareofifyouwanttouseUnityin applicationsthatwillruninlessthanfulltrustenvironments.ThelimitationwhenusingUnityina partialtrustenvironmentisthatyoucannotregisterandusemappingsusingtheRegisterType methodswherethetargetclassisinternal(C#),Friend(VisualBasic.NET),private(C#),orPrivate (VisualBasic.NET).

FormoreinformationaboutsecurityissueswhenusingdynamicallygeneratedMicrosoft intermediatelanguage(MSIL)code,seeSecurityIssuesinReflectionEmitfor.NET3.5andSecurity IssuesinReflectionEmitfor.NET2.0.

UpdatingtheUnityAssemblies
IfanupgradedversionofUnitybecomesavailable,youcaninstallthenewversionandhaveall applicationsusetheupdatedassembly.However,ifthenewversionintroducescompatibility problemsforcertainapplications,youcaninstallthenewversionintheglobalassemblycacheand
206

configuresomeapplicationstousetheupdatedversion,whileotherscontinuetousetheearlier version.

UpdatingPrivateAssemblies
IfaUnityassemblyhasbeendeployedasaprivateassembly,youcandeploytheupgradebyjust replacingtheearlierversionoftheDLLintheapplicationfolderhierarchywiththenewone. Youshouldkeepacopyoftheearlierversionsothatifyouexperienceanycompatibilityissues withthenewassembly,youcanreverttotheearlierversion.

UpdatingSharedAssemblies
TheeasiestwaytoupgradeaUnityassemblyinasharedconfigurationistoinstalltheupdatedDLL intheglobalassemblycache.Bydefault,thecommonlanguageruntimetriestoloadtheassembly thathasthelatestbuildandrevisionnumbers,butthesamemajorandminorversionnumbers,as theassemblytheapplicationwasbuiltwith.Therefore,ifthemajorandminorversionnumbers havenotchanged,addingthelaterversiontotheglobalassemblycacheautomaticallyupdatesall applicationsthatrefertotheassembly. Ifthemajororminorversionnumbersareincremented,orifthenewversioncausescompatibility problemswithexistingapplications,youcanoverridethedefaultversionpolicy.Tospecifythata particularversionofanassemblyisused,edittheapplication'sconfigurationfile(forindividual applications),orthemachinepolicyfile.Alternatively,youcandistributethenewversionofthe assemblywithapublisherpolicyfiletoredirectassemblyrequeststothenewversion.

StrongNamingtheUnityAssemblies
IfyoubuildUnityfromthesourcecode,youmaydecidetoapplystrongnamingtotheassemblies.A strongnameconsistsoftheassembly'sidentitythesimpletextname,versionnumber,andculture information(ifprovided)plusapublickeyandadigitalsignature.Thestrongnameisgenerated fromanassemblyfile(thefilethatcontainstheassemblymanifest,whichinturncontainsthe namesandhashesofallthefilesthatmakeuptheassembly),usingthecorrespondingprivatekey. Signinganassemblywithastrongnameensuresthatitsnameisgloballyunique.Assemblieswith thesamestrongnameareexpectedtobeidentical. Forexample,ifyouintendtoshareUnityassembliesamongseveralapplications,youcaninstall themintotheglobalassemblycache.Eachassemblyintheglobalassemblycachemusthavea globallyuniquename.Youcanuseastrongnametoensurethis.Evenifyouonlyusetheassemblies withinasingleapplication,youcanstrongnametheassembliestoensurethatyourapplicationuses thecorrectversionoftheassemblies. Strongnamessatisfythefollowingrequirements:
207

Strongnamesguaranteenameuniquenessbyrelyingonuniquekeypairs.Noonecan generatethesameassemblynamethatyoucanbecauseanassemblygeneratedwithone privatekeyhasadifferentnamethananassemblygeneratedwithanotherprivatekey. Strongnamesprotecttheversionlineageofanassembly.Astrongnamecanensurethatno onecanproduceasubsequentversionofyourassembly.Userscanbesurethataversionof theassemblytheyareloadingcomesfromthesamepublisherthatcreatedtheversion originallyprovidedwiththeapplication. Strongnamesprovideastrongintegritycheck.Passingthe.NETFrameworksecuritychecks guaranteesthatthecontentsoftheassemblyhavenotbeenchangedsinceitwasbuilt. However,notethatstrongnamesthemselvesdonotimplyaleveloftrustsuchasthelevel providedby,forexample,adigitalsignatureandsupportingcertificate.

Forinformationaboutdeployingassembliesintotheglobalassemblycache,seeWorkingwith AssembliesandtheGlobalAssemblyCache.

UsingVisualStudiotoStrongNametheUnityAssemblies
YoucanstrongnameUnityassemblieswithVisualStudio.Tosignanassemblywithastrongname, youmusthaveapublic/privatekeypair.Thispublicandprivatecryptographickeypairisusedduring compilationtocreateastrongnamedassembly.IfmanydevelopersareusingUnity,theyshouldall usethesamestrongnamedassembly.Thismeansthateveryoneshoulduseasinglekeypairtosign theassemblies.Thiskeypairshouldbestoredsecurely. Thefirstproceduredescribeshowtocreateakeypair.(Youcanalsouseanexistingkeypair.Ifyou haveanexistingkeypair,youcanskipthisprocedure.)Thesecondproceduredescribeshowto assignthepublickeytoanassembly. Tocreateakeypair

1. AttheVisualStudiocommandprompt,gotothedirectorythatwillholdthekeypair.
2. Tocreateakeypair,typesnkkeyfile.snk.

YoucanalsousetheCreateStrongNamedialogboxinVisualStudiotocreateakeypair.Toaccess thisdialogbox,selectaprojectnodeinSolutionExplorer.OntheProjectmenu,clickProperties. WhentheProjectDesignerappears,clicktheSigningtab.OntheSigningpage,selectSignthe assembly,andthenclickNewintheChooseastrongnamekeyfiledropdownlistbox. ThenextproceduredescribeshowtoassignthekeytotheUnityassembly.OpentheUnity.sln solutionfileandaddanyoftheoptionalprojectsyourequire,suchastheSecurity.Azmanproject. Followthesestepsforeachproject,includingthedesignprojects.Youmayconsiderusingabatch editor,suchasthatinVisualStudio,toupdateeachprojectastheyaredefinedinXMLfiles. Toassignthepublickeytoaprojectassembly


208

1. InVisualStudio,selecttheprojectnodeinSolutionExplorer.OntheProjectmenu,click
Properties(orrightclicktheprojectnodeinSolutionExplorer,andthenclickProperties). 2. IntheProjectDesigner,clicktheSigningtab. 3. SelecttheSigntheassemblycheckbox. 4. IntheChooseastrongnamekeyfiledropdownlistbox,clickBrowse. 5. IntheSelectFiledialogbox,navigatetothekeyfileyoucreatedorenteritspathintheFile namebox.ClickOpentoselectit.

6. ClosethePropertieswindowandsavethechanges.

UnityQuickStarts
TheinstructionsinthisQuickStarttopicaredirectedattheSilverlightsolution.Thoughthereare manysimilarities,someinstructionsinthistopic,suchasreferencestoProgram.csorProgram.vb, donotapplytotheSilverlightproject.ThefollowingQuickStartapplicationsdemonstratesomeof thekeyfeaturesofUnity: Walkthrough:TheUnityStopLightQuickStart.ThisQuickStartdemonstratesdependency injectiontechniques.ThisistheonlyQuickStartprojectintheSilverlightsolution. Walkthrough:TheUnityEventBrokerExtensionQuickStart.ThisQuickStartprovidesan exampleextensionfortheUnitycontainer.TheSilverlightsolutiondoesnoincludetheEvent BrokerQuickStart.

UnityQuickStartsareonlyavailableifyouinstallthestandaloneUnityMSI.TheUnityMSIis availableatpatterns&practicesUnityonCodePlex.

BuildingtheQuickStarts
TheQuickStartsshipassourcecode,whichmeansthatyoumustcompilethembeforeyoucanrun them.YoucanuseVisualStudio2005tobuildtheQuickStarts.IfyouopentheQuickStartsinVisual Studio2008,youwillbepromptedtoupgradetheprojectstotheVisualStudio2008format.Ifyou decidetoupgradethem,youmaywanttokeepacopyoftheoriginalVisualStudio2005projectsso thatyoucanrefertothemandusethemifrequired. TobuildtheUnityQuickStarts 1. EnsureUnitySourceCodeisinstalled. 2. OpenthesourcecodefolderinWindowsExplorerorfromtheStartmenu.
209

3. OpentheQuickStartsfolder,opentheCSfolder(forC#)orVBfolder(forVisualBasic.NET), andthenopentheStopLightorEventBrokerfolder. 4. DoubleclicktheVisualStudiosolutionfilefortheQuickStart. 5. VisualStudioopens,displayingthesolutionfile.ClicktheRunbuttononthetoolbar,or pressF5,tostarttheapplication.

Walkthrough:TheUnityStopLight QuickStart
TheStopLightQuickStartdemonstratesthewaysthatyoucanuseUnityandtheUnitycontainerin yourapplications.TheuserinterfaceisasimpleWindowsFormsapplicationthatdisplaysthethree colorsofastoplightortrafficlightitshowsred,yellow,andgreen,inturn,forspecifiedperiods. Youcanconfigurethedisplayperiodsforeachcolor.Thefollowingillustrationshowstheuser interface.

TheStopLightQuickStartdemonstratesthefollowingfeaturesofUnity: Registeringmappingsfortypeswiththecontainer ImplementingtheModelViewPresenterpatternbyinjectingapresenterintotheuser interface Injectingabusinesscomponentintoobjectsusingproperty(setter)injection Implementingaconfigurablepluggablearchitecture

210

ThefollowingdiagramshowstheclassesandarchitectureoftheStopLightQuickStartapplication.

RegisteringMappingsforTypeswiththeContainer
TheStopLightQuickStartusestwoservicesthattheUnitycontainermapsfrominterfacesto concreteserviceimplementations.Thesetwoservicesareinjectedintoclassesthatrequirethem automaticallywhenunitycreatesinstancesoftheclass. ThetwointerfacesareILogger,whichUnitymapstotheconcreteserviceclassnamedTraceLogger, andIStoplightTimer,whichUnitymapstotheconcreteserviceclassnamedRealTimeTimer.The mappingregistrationoccursintheProgramfilethatexecuteswhentheapplicationstarts.Ituses thefollowingcode. C#
IUnityContainercontainer=newUnityContainer() .RegisterType<ILogger,TraceLogger>() .RegisterType<IStoplightTimer,RealTimeTimer>();

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer()_ .RegisterType(OfILogger,TraceLogger)()_ .RegisterType(OfIStoplightTimer,RealTimeTimer)()

Thissetsuptwodefault(unnamed)mappingssothatrequeststothecontainerfortheILogger interfacewillreturnanewinstanceoftheTraceLoggercomponentandrequeststothecontainerfor theIStoplightTimerinterfacewillreturnanewinstanceoftheRealTimeTimercomponent.


211

TheTraceLoggercomponent(intheServiceImplementationsfolder)exposesasinglemethod namedWritethatwritesaspecifiedmessagetotheapplication'scurrent System.Diagnostics.Traceinstance. TheRealTimeTimercomponentisasingleshottimerimplementedinthefileRealTimeTimer(in theServiceImplementationsfolder).ItexposesapropertynamedDuration(inmilliseconds),a Startmethod,anditraisestheOnExpiredeventwhenthetimerreachesthespecifiedduration. Afterregisteringtherequiredmappings,thecodemustforcedependencyinjectiontobeappliedto thechildobjectstheapplicationuses.TheparentobjectfortheapplicationistheWindowsForms userinterfaceclassnamedStoplightForm.Toensurethatalldependentobjectsareinjected,the codeintheProgramclassinstantiatestheStoplightFormusingtheResolvemethodoftheUnity container,asshownhere. C#
Application.Run(container.Resolve<StoplightForm>());

VisualBasic
Application.Run(container.Resolve(OfStoplightForm)())

TheRunmethodoftheApplicationclassacceptsasaparameteranobjectthatistheclassto execute.TheResolvemethodoftheUnitycontainergeneratesaninstanceoftheStoplightForm class,applyingdependencyinjectiontoallchildclassestocreateorreferencetheobjectsthesechild classesrequire.

ImplementingtheModelViewPresenterPattern
Whentheprogramstarts,itloadsanddisplaystheuserinterfacetheWindowsFormnamed StoplightForm.ThisformimplementstheviewfortheModelViewPresenter(MVP)pattern,soit mustexposeapropertythatisareferencetoitsassociatedpresenter.Toobtainareferencetoits presenter,aclassnamedStoplightPresenter,theformusesproperty(setter)injectionbyapplying theDependencyattributetotheproperty,asshowinthiscode. C#
publicpartialclassStoplightForm:Form,IStoplightView { privateStoplightPresenterpresenter; [Dependency] publicStoplightPresenterPresenter { get{returnpresenter;} set { presenter=value; presenter.SetView(this);
212

} } ...

VisualBasic
PublicPartialClassStoplightForm InheritsForm ImplementsIStoplightView Private_presenterAsStoplightPresenter <Dependency()>_ PublicPropertyPresenter()AsStoplightPresenter Get Return_presenter EndGet Set(ByValvalueAsStoplightPresenter) _presenter=value _presenter.SetView(Me) EndSet EndProperty ...

ThisensuresthatUnitywillcreatethepresenterbeforeitcreatesanddisplaystheview(the StoplightFormform).Thedependentclasstypefordependencyinjectionistheconcreteclass StoplightPresenter,sotheUnitycontainercancreatethisobjectwithoutrequiringamappinginthe container. Theviewexposeseventhandlersthatthepresentercanusetomanipulatethecontrolsontheform andaccessthevalues.

InjectingaBusinessComponentusingProperty(Setter)Injection
Thepresenterfortheuserinterface,theclassnamedStoplightPresenter,requiresaninstanceof theclassnamedStoplightthatrepresentsthesetofcolorsandmethodsofarealstoplight.The Stoplightclassusesanenumerationofthethreecolors(red,yellow,andgreen),exposestheNext methodthattheapplicationcanusetochangethecolorsinapredefinedsequence,andraisesthe StoplightChangedHandlereventwhenacolorchangeoccurs.Theargumentforthiseventisan instanceoftheclassnamedLightChangedEventArgsthatexposesthecurrentcolor. Toobtainaninstanceofthisclass,theStoplightPresenterexposesitasapropertyandappliesthe Dependencyattributetotheproperty,asshowninthefollowingcode. C#
privateStoplightstoplight; [Dependency] publicStoplightStoplight { get{returnstoplight;}
213

set{stoplight=value;} }

VisualBasic
Private_stoplightAsStopLight.Logic.Stoplight <Dependency()>_ PublicPropertyStoplight()AsStopLight.Logic.Stoplight Get Return_stoplight EndGet Set(ByValvalueAsStopLight.Logic.Stoplight) _stoplight=value EndSet EndProperty

Thedependentclasstypefordependencyinjectionistheconcreteclass,Stoplight,sotheUnity containercancreatethisobjectwithoutrequiringamappinginthecontainer. ThepresenteralsohasadependencyontheStoplightScheduleclass,whichmaintainsreferencesto theStoplightTimerandILogger,exposesmethodstoupdatethedurationsforthecolorsandforcea changetothenextcolor,andrespondstotheOnTimerExpiredeventraisedbytheRealTimeTimer class. TogetareferencetoanewinstanceoftheStoplightScheduleclass,theStoplightPresenterexposes itasapropertynamedScheduleandappliestheDependencyattributetotheproperty,asshownin thefollowingcode. C#


privateStoplightScheduleschedule; [Dependency] publicStoplightScheduleSchedule { get{returnschedule;} set{schedule=value;} }

VisualBasic
Private_scheduleAsStoplightSchedule <Dependency()>_ PublicPropertySchedule()AsStoplightSchedule Get Return_schedule EndGet Set(ByValvalueAsStoplight) _schedule=value EndSet EndProperty

Again,thedependenttypeisaconcreteclass,inthiscasetheStoplightScheduleclass,andsothe Unitycontainercancreatethisobjectwithoutrequiringamappinginthecontainer.
214

ImplementingaConfigurablePluggableArchitecture
TheStoplightandStoplightScheduleclasseshavedependenciesthatarenotconcreteclasses.Both oftheseclasseshaveadependencyononeoftheconcreteimplementationsoftheILogger interfaceeithertheNullLoggerortheTraceLogger.Atruntime,thecodecanchoosewhich concreteclasstoinstantiate.ItcanuseanyclassthatimplementstheILoggerinterface,which definesjustthesinglemethodWritethattakesamessageandwritesittotheappropriateoutput. Thisisanexampleofapluggablearchitecture.Theactualclasschosenatruntime,andinjectedinto theapplication,dependsonthemappingintheUnitycontainer.TheQuickStartmapstheILogger interfacetotheconcretetypeTraceLoggerusingthemethodRegisterType<ILogger,TraceLogger>() inthemainProgramclass.Therefore,touseadifferentconcreteimplementation,thedeveloper justhastochangethemapping.Forexample,touseanewclassReallyFastLogger,thedeveloper wouldjustchangethemappingtoRegisterType<ILogger,ReallyFastLogger>(). Inaddition,byusingaconfigurationfiletopopulatetheUnitycontainerorreadingtheconfiguration informationfromanothersourcesuchasadatabase,thedeveloperallowstheusertochangethe actualconcreteloggingclasswithoutrequiringrecompilationoftheapplicationcode. TheStoplightandStoplightScheduleclassesforceinjectionofthecurrentlymappedloggerclassby exposingitasapropertynamedLogger(oftypeILogger)thathastheDependencyattributeapplied, asshowninthefollowingcode. C#
privateILoggerlogger=newNullLogger(); [Dependency] publicILoggerLogger { get{returnlogger;} set{logger=value;} }

VisualBasic
Private_loggerAsILogger=NewNullLogger() <Dependency()>_ PublicPropertyLoggerAsILogger Get Return_logger EndGet Set(ByValvalueAsILogger) _logger=value EndSet EndProperty

!!K:UnityQS1!!

215

Walkthrough:TheUnityEventBroker ExtensionQuickStart
TheEventBrokerExtensionQuickStartdemonstrateshowyoucanextendtheUnitycontainerby addingacustomextension.TheQuickStartimplementsaneventbrokerforthecontainerasa containerextensionanddemonstratesthenewextensionusingtheStopLightapplicationdiscussed inWalkthrough:TheUnityStopLightQuickStart. TheEventBrokerExtensionQuickStartcontainsfiveprojects: SimpleEventBroker.Thisprojectimplementsasimplepublishandsubscribemechanismthat supportsmultipleeventpublishersandmultiplesubscribers. EventBrokerExtension.Thisprojectimplementsthecustomcontainerextensionthatallows applicationstopublishandsubscribetoeventsusingattributesorexplicitlyusingcode. StopLight.ThisprojectisbasicallythesameasthatdescribedintheUnityStopLight QuickStart,butitusesthecustomcontainerextensiontomanagethepublishingof,and subscriptionto,twoeventswithintheapplication. Tests.EventBrokerExtension.AtestfixturefortheEventBrokerExtension. Tests.SimpleEventBroker.AtestfixturefortheSimpleEventBroker.

Forinformationabouthowyoucancreateandusecustomcontainerextensions,seeCreatingand UsingContainerExtensions. ThefollowingdiagramshowstheclassesandarchitectureoftheEventBrokerExtensionQuickStart.

216

IfyoucomparethisdiagramtothestructureoftheStopLightQuickStartshowninWalkthrough:The UnityStopLightQuickStart,youcanseethattheEventBrokerExtensionQuickStarthasthefollowing additionalfeatures: TheProgramclass,whichregistersthetypemappingsinthecontainerandcallstheResolve methodtoinstantiatethemainStopLightform,alsoaddstheSimpleEventBrokerExtension tothecontainer. TheSimpleEventBrokerExtension,whichinheritsfromtheUnityContainerExtensionbase class,createsaninstanceoftheEventBrokerclassthatimplementsthepublishandsubscribe patternfordistributedevents. TheEventBrokerclasscreatesaninstanceofthePublishedEventclassthatprovidesthe facilitiesformaintainingalistofeventsubscriptionsandraisingeventstoregistered subscribers. TheStopLightPresenter,StopLightSchedule,andRealTimeTimerclassesincludeattributes thatregistereventpublicationsandsubscriptionswiththeSimpleEventBrokerExtension class.

TheEventBrokerExtensionQuickStartdemonstratesthefollowingfeaturesofUnityandthecustom containerextensionmechanism: CreatingthecustomUnitycontainerextension AddinganextensiontotheUnitycontaineratruntime


217

UsingtheexampleEventBrokerExtension

CreatingaCustomUnityContainerExtension
AUnitycontainerextensionisacustomclassthatinheritsfromtheUnityContainerExtensionbase classandimplementsextrafunctionalitybeyondthatavailablefromthecontainer.Theextension canaccessthecontainerandreceivenotificationofregistrationstakingplacewithinthecontainer. ThissectiondescribesthesignificantfeaturesoftheEventBrokerExtensionproject. TheclassSimpleEventBrokerExtensioninheritsUnityContainerExtensionandcreatesanew instanceoftheEventBrokerclassfromtheSimpleEventBrokerproject.Itthenoverridesthe InitializemethodoftheUnityContainerExtensionbaseclass. ThecodeintheInitializemethodoftheSimpleEventBrokerExtensionclass,whichfollows,addsthe newEventBrokeritcreatestothecontainer'sLocatorsothatotherclassescanlocateandreference iteasily,andthenitaddstwostrategiestotheUnitybuildpipeline.Itaddsareflectionstrategyto thePreCreationstagethatwilldetectthetwoattributesthattheextensionuses(the PublishesAttributeandtheSubscribesToAttribute)andawireupstrategytotheInitializationstage thatregisterspublishersandsubscriberdelegateswiththeEventBroker.Finally,itexposesthenew EventBrokeritcreatedasaproperty. C#
publicclassSimpleEventBrokerExtension:UnityContainerExtension, ISimpleEventBrokerConfiguration { privatereadonlyEventBrokerbroker=newEventBroker(); protectedoverridevoidInitialize() { Context.Container.RegisterInstance( broker,newExternallyControlledLifetimeManager()); Context.Strategies.AddNew<EventBrokerReflectionStrategy>(UnityBuildStage.PreCreat ion); Context.Strategies.AddNew<EventBrokerWireupStrategy>(UnityBuildStage.Initializati on); } publicEventBrokerBroker { get{returnbroker;} } }

VisualBasic
PublicClassSimpleEventBrokerExtension InheritsUnityContainerExtension
218

ImplementsISimpleEventBrokerConfiguration Private_brokerAsNewEventBroker() ProtectedOverloadsOverridesSubInitialize() Context.Container.RegisterInstance(_ broker,NewExternallyControlledLifetimeManager()) Context.Strategies.AddNew(Of EventBrokerReflectionStrategy)(UnityBuildStage.PreCreation) Context.Strategies.AddNew(Of EventBrokerWireupStrategy)(UnityBuildStage.Initialization) EndSub PublicReadOnlyPropertyBroker()AsEventBroker_ ImplementsISimpleEventBrokerConfiguration.Broker Get Return_broker EndGet EndProperty EndClass

TheEventBrokerclassholdsaDictionarycontainingentriesthatmapeventnamestopublishersof thateventandexposesmethodstoregisterpublishersandsubscribers(namedRegisterPublisher andRegisterSubscriber).Italsoexposesmethodstounregisterpublishersandsubscribersandtoget alistofpublishersorsubscribersforaspecifiedeventname.Muchofthefunctionalityforthese methodsisinthePublishedEventclass,whichstoresandexposeslistsofallpublishersand subscribers. ThewireupstrategyaddedtoUnitybytheInitializemethodinthepreviouslistingcallsthe RegisterPublisherandRegisterSubscribermethodsoftheEventBrokerclass.Thismeansthat,when UnitydetectsaPublishesAttributeorSubscribesToAttributeinaclassthatitcreates,it automaticallyregisterstheclassormemberasapublisherorasubscriberintheEventBroker. Iftheregistrationisforapublisher,theEventBrokercallstheAddPublishermethodofthe PublishedEventclass.Thismethodaddsthenewpublishertothelistofpublishersandwiresupan eventhandlernamedOnPublisherFiringtothepublishedevent.Therefore,whenthepublisher raisestheevent,thehandlerinthePublishedEventclasscaniteratethroughthelistofsubscriber delegatesandinvokeeachone,asshowninthefollowingcode. C#
privatevoidOnPublisherFiring(Objectsender,EventArgse) { foreach(EventHandlersubscriberinsubscribers) { subscriber(sender,e); } }

VisualBasic
PrivateSubOnPublisherFiring(senderAsObject,eAsEventArgs) ForEachsubscriberAsEventHandlerin_subscribers
219

subscriber.Invoke(sender,e) Next EndSub

AddinganExtensiontotheUnityContaineratRunTime
Afteryoucreateacustomcontainerextension,youmustaddittotheUnitycontainer.Youcando thisbycompilingtheextensionandspecifyingthetypeandassemblynameintheconfigurationfile forUnity.FordetailsonhowtoconfigureUnitycontainerextensions,seeConfiguringUnity. However,theEventBrokerExtensionQuickStartaddsthecustomSimpleEventBrokerExtensionat runtimebycallingamethodoftheUnitycontainerclass.TheStopLightapplicationProgramclass thatinitializestheapplicationandloadsthemainformcreatesanewUnityContainerinstanceand registerstheconcretetypesthatmaptotheILoggerandIStoplightTimerclasses.Italsocallsthe AddNewExtensionmethod,specifyingtheSimpleEventBrokerExtensionclass,asshowninthe followingcode. C#
IUnityContainercontainer=newUnityContainer() .AddNewExtension<SimpleEventBrokerExtension>() .RegisterType<ILogger,TraceLogger>() .RegisterType<IStoplightTimer,RealTimeTimer>();

VisualBasic
DimcontainerAsIUnityContainer=NewUnityContainer()_ .AddNewExtension(OfSimpleEventBrokerExtension)()_ .RegisterType(OfILogger,TraceLogger)()_ .RegisterType(OfIStoplightTimer,RealTimeTimer)()

ThecontainerautomaticallyinstantiatestheextensionandcallstheInitializemethodthatyousaw inthesectionCreatingaCustomUnityContainerExtensionofthistopic.

UsingtheExampleEventBrokerExtension
Asshowninthepreviousdiagram,theEventBrokerExtensionQuickStartusesthecustom SimpleEventBrokerExtensioncontainerextensiontoimplementthepublishandsubscribepattern fortwoevents: TheRealTimeTimerclasspublishesaneventnamedTimerTickthatitraiseswhenthetimer reacheszero.TheStoplightScheduleclasssubscribestothisevent.Intheeventhandler,it updatesitsindextothelightTimesarray(anarrayofTimeSpanvaluesforthedurationofthe colors),setsthenewdurationforthelight,andstartsthetimerrunningagain. TheStoplightScheduleclasspublishesaneventnamedChangeLightthatitraisesbeforeit changesthetimerdurationandrestartsthetimer.TheStoplightPresenterclasssubscribesto thisevent.Intheeventhandler,itcallstheNextmethodoftheStopLightclasstochangethe colorofthelightandwriteamessagetotheTraceLogger.

220

ToindicatethatitpublishestheTimerTickevent,theRealTimeTimerclassusesthePublishes attribute,specifyingthenameoftheeventpublication,asshowninthefollowingcode. C#
[Publishes("TimerTick")] publiceventEventHandlerExpired; privatevoidOnTick(Objectsender,EventArgse) { timer.Stop(); OnExpired(this); }

VisualBasic
<Publishes("TimerTick")>_ PublicEventExpiredAsEventHandlerImplementsIStoplightTimer.Expired PrivateSubOnTick(ByValsenderAsObject,eAsEventArgs) timer.[Stop]() OnExpired(Me) EndSub

TheOnExpiredmethodsimplychecksthatthereisaneventhandlerinstanceandraisestheevent, asshownhere. C#
protectedvirtualvoidOnExpired(objectsender) { EventHandlerhandlers=Expired; if(handlers!=null) { handlers(this,EventArgs.Empty); } }

VisualBasic
ProtectedOverridableSubOnExpired(ByValsenderAsObject) DimhandlersAsEventHandler=ExpiredEvent IfNothandlersIsNothingThen RaiseEventExpired(Me,EventArgs.Empty) EndIf EndSub

TheStoplightScheduleclasssubscribestotheTimerTickeventbyapplyingtheSubscribesTo attributetoasuitableeventhandler. C#
[SubscribesTo("TimerTick")] publicvoidOnTimerExpired(Objectsender,EventArgse) { EventHandlerhandlers=ChangeLight; if(handlers!=null) { handlers(this,EventArgs.Empty); }
221

currentLight=(currentLight+1)%3; timer.Duration=lightTimes[currentLight]; timer.Start(); }

VisualBasic
<SubscribesTo("TimerTick")>_ PublicSubOnTimerExpired(ByValsenderAsObject,ByValeAsEventArgs) DimhandlersAsEventHandler=ChangeLightEvent IfNothandlersIsNothingThen RaiseEventChangeLight(Me,EventArgs.Empty) EndIf currentLight=(currentLight+1)Mod3 _timer.Duration=lightTimes(currentLight) _timer.Start() EndSub

TheprecedingcodeshowsthattheOnTimerExpiredeventhandlerraisesaneventnamed ChangeLightwhenitreceivestheTimerTickevent.ChangeLightisthelocalnameoftheevent,but theStoplightScheduleclassalsopublishestheeventusingthisname,asshowninthefollowing code. C#


[Publishes("ChangeLight")] publiceventEventHandlerChangeLight;

VisualBasic
<Publishes("ChangeLight")>_ PublicEventChangeLightAsEventHandler

Finally,theStoplightPresenterclasssubscribestheChangeLighteventusinganeventhandler namedOnScheduledLightChange.Insidetheeventhandler,itcallstheNextmethodofthe StopLightclass,asshowninthefollowingcode. C#


[SubscribesTo("ChangeLight")] publicvoidOnScheduledLightChange(Objectsender,EventArgse) { stoplight.Next(); }

VisualBasic
<SubscribesTo("ChangeLight")>_ PublicSubOnScheduledLightChange(ByValsenderAsObject,ByValeAsEventArgs)_ _stoplight.Next() EndSub

ThecodeexamplesinthissectiondemonstratehowusefulthecustomSimpleEventBrokerExtension isforworkingwithdistributedeventsandhoweasyitistopublishandsubscribetoeventswhen usingUnitytogenerateinstancesoftheclassesusedintheapplication. !!K:UnityQS2!!


222

223

You might also like