Sie sind auf Seite 1von 88

COMMUNITYPREVIEWLICENSE

Thisdocumentisapreliminaryreleasethatmaybechangedsubstantiallypriortofinalcommercial release.ThisdocumentisprovidedforinformationalpurposesonlyandMicrosoftmakesnowarranties, eitherexpressorimplied,inthisdocument.Informationinthisdocument,includingURLandother InternetWebsitereferences,issubjecttochangewithoutnotice.Theentireriskoftheuseorthe resultsfromtheuseofthisdocumentremainswiththeuser.Unlessotherwisenoted,thecompanies, organizations,products,domainnames,emailaddresses,logos,people,places,andeventsdepictedin exampleshereinarefictitious.Noassociationwithanyrealcompany,organization,product,domain name,emailaddress,logo,person,place,oreventisintendedorshouldbeinferred.Complyingwithall applicablecopyrightlawsistheresponsibilityoftheuser.Withoutlimitingtherightsundercopyright, nopartofthisdocumentmaybereproduced,storedinorintroducedintoaretrievalsystem,or transmittedinanyformorbyanymeans(electronic,mechanical,photocopying,recording,or otherwise),orforanypurpose,withouttheexpresswrittenpermissionofMicrosoftCorporation. Microsoftmayhavepatents,patentapplications,trademarks,copyrights,orotherintellectualproperty rightscoveringsubjectmatterinthisdocument.Exceptasexpresslyprovidedinanywrittenlicense agreementfromMicrosoft,thefurnishingofthisdocumentdoesnotgiveyouanylicensetothese patents,trademarks,copyrights,orotherintellectualproperty.

2009MicrosoftCorporation.Allrightsreserved.
MicrosoftaretrademarksoftheMicrosoftgroupofcompanies. Allothertrademarksarepropertyoftheirrespectiveowners.

TableofContents
Preface Chapter1 Chapter2 Chapter3 Chapter4 Chapter5 Chapter6 Chapter7 Chapter8 1 8 30 63 includedinpreview MeettheLibrarian MuchADOaboutDataAccess ErrorManagementMadeExceptionallyEasy AsEasyAsFallingOffaLog ACacheAdvanceforyourApplications BanishingValidationComplication RelievingCryptographyComplexity AnAuthenticApproachtoTokenIdentity

Preface
AboutThisGuide
Themostobviousinitialquestions,asyouidlypickupabookinyourlocalbookstoreorbrowsethe seeminglyendlesscollectionavailablefromyourfavoriteWebsite,is"Whatdoesthisbookactually cover?","WhatwillIlearnfromit?","Isthecontentlikelytobeinterestingandusefultome?",andof course"Isitactuallyanygood?".We'llhaveagoatansweringthefirstthreeofthesequestionshere. Thefinalquestionisonethatonlyyoucananswer.Andwewouldbepleasedtohearyouropinion throughourcommunityWebsiteathttp://entlib.codeplex.com/.

WhatDoesThisGuideCover?
Asyoucanprobablytellfromthetitle,thisguideconcentratesonhowyoucangetstartedwith EnterpriseLibrary.ItwillhelpyoutolearnhowtouseEnterpriseLibraryinyourapplicationstomanage yourcrosscuttingconcerns,simplifyandspeedupyourdevelopmentcycle,andtakeadvantageof provenpractices.EnterpriseLibraryisacollectionofprewrittencodecomponentsthathavebeen developedfinetunedovermanyyears.Youcanusethemofthebox,modifythemasrequired, distributethemwithyourapplications,andevenuseEnterpriseLibraryasalearningresource.It includesthesourcecodethatdemonstrates.NETprogrammingtechniques,andtheuseofcommon designpatternsthatcanimprovethedesignandmaintainabilityofyourapplications.Bytheway,ifyou arenotfamiliarwiththeterm"crosscuttingconcerns",don'tworrywe'llexplainitaswegoalong. EnterpriseLibraryisanextensivecollection,withagreatmany"movingparts".Forbeginners,itcan seemoverwhelmingandconfusing;andknowinghowtobesttakeadvantageofitisnotcompletely intuitive.Therefore,inthisguide,we'llhelpyoutounderstandwhatEnterpriseLibraryis,whatit contains,andhowyoushouldgetstartedusingit.YouwillseehoweasyitistoaddEnterpriseLibraryto yourapplications,configureittodoexactlywhatyouneed,andthenbenefitfromthesimpletouseyet extremelycompellingopportunitiesitprovidesforwritinglesscodethatachievesmore. ThefirstchapterofthisguidediscussesEnterpriseLibraryingeneral,andprovidesdetailsofthe individualpartssothatyoubecomefamiliarwiththeframeworkasawhole.Thisincludesunderstanding thebasicprinciplesofeachoftheapplicationblocksinEnterpriseLibrary,andhowyoucanchoose exactlywhichblocksandfeaturesyourequire.Thischapteralsodiscussesthefundamentalsofusingthe blocks;suchashowyouconfigurethem,howyouinstantiatethecomponents,andhowyouusethese componentsinyourcode. Theremainingsevenchaptersdiscussindetailtheapplicationblocksthatprovidethebasiccrosscutting functionalitysuchasdataaccess,caching,logging,andexceptionhandling.Thesechaptersexplainthe conceptsthatdrovedevelopmentoftheblocks,thekindsoftasksthattheycanaccomplish,andtheway thattheyhelpyoutoimplementmanywellknowndesignpatterns.And,ofcourse,theyexplainby wayofcodeextractsandsimpleexampleapplicationshowyouactuallyusetheblocksinyour

AGuidetoDevelopingwithEnterpriseLibrary5.0

applications.Afteryoureadeachchapter,youshouldbefamiliarwiththeblockandabletouseitto performarangeoffunctionsquicklyandeasily;inbothnewandexistingapplications. YoucanalsodownloadandworkthroughtheHandsOnLabsforEnterpriseLibrary,whichareavailable fromhttp://go.microsoft.com/fwlink/?LinkId=177393.

WhatThisGuideDoesNotCover
TheaimofthisguideistohelpyoulearnhowtobenefitfromthecapabilitiesofEnterpriseLibrary.It doesnotdescribethecommondesignpatternsindepth,orattempttoteachyouaboutapplication architectureingeneral.Instead,itconcentratesongettingyouuptospeedquicklyandwiththe minimumfusstouseEnterpriseLibrarytomanageyourcrosscuttingconcerns. Oneofthecoretenetsofmodernapplicationdesignisreducingthecouplingordependenciesbetween componentsandobjects,andEnterpriseLibraryinversion5.0achievesthisthroughuseofthe DependencyInjection(DI)designpattern.However,youdonothavetobeaDIexperttouseEnterprise Library;allofthecomplexityismanagedinternallybythecoremechanismswithintheframework.While wedoshowandexplainthebasicusageofDIintermsofusingEnterpriseLibrary,thisisnota fundamentalfeatureofthisguide.Instead,wediscussDIindetail,andshowhowyoucanapplythisand similardesignpatterns,inaseparateguidecalled"WhatevertheUnityBookIsCalled". EnterpriseLibraryisdesignedtobeextensible.Youcanachievethissimplybywritingcustomplugin providers,bymodifyingthecorecodeofthelibrary,orevenbycreatingentirelynewblocks.Inthis guide,weprovidepointerstohowyoucandothis,andexplainthekindsofprovidersthatyoumaybe temptedtocreate,butitisnotatopicthatwecoverindepth.Thesetopicsarediscussedmorefullyin thedocumentationinstalledwithEnterpriseLibraryandavailableonlineat http://msdn.microsoft.com/entlib,andinthemanyotherresourcesavailablefromourcommunityWeb siteathttp://www.codeplex.com/entlib.

HowWillThisGuideHelpYou?
IfyoubuildapplicationsthatrunontheMicrosoft.NETFramework,whethertheyareenterpriselevel businessapplicationsorevenrelativelymodestWindowsForms,WPF,WCF,orASP.NETapplications, youcanbenefitfromconsideringEnterpriseLibrary.Thisguidewillhelpyoutoquicklygraspwhat EnterpriseLibrarycandoforyou,seeexamplesthatshowitinaction,andmakeiteasierforyoutostart experimentingwithEnterpriseLibrary. Thesampleapplicationsareeasytoassimilate,fullycommented,andcontaincodethatdemonstratesall ofthemainfeatures.Youcancopythiscodedirectlyintoyourapplicationsifyouwish,orjustuseitasa guidewhenyouneedtoimplementthecommonfunctionalityitprovides.ThesamplesareConsole basedapplicationsthatcontainseparateproceduresforeachfunctiontheydemonstrate. Finally,andperhapsthemostimportantfeatureofthisguide,isthatitwillhopefullyallayanyfearsyou mayhaveaboutusing"otherpeople'scode"inyourapplications.Byunderstandinghowyoucanselect exactlywhichfeaturesyouneed,andinstalltheminimumrequirementstoimplementthesefeatures, youwillseehowwhatmightseemlikeahugeandcomplicatedframeworkisactuallyareallyuseful

AGuidetoDevelopingwithEnterpriseLibrary5.0

setofindividualcomponentsandfeaturesfromwhichyoucanpickandchoose.Acandystoreforthe architectanddeveloper.

WhatDoYouNeedtoGetStarted?
Theprerequisitesforusingthisguidearerelativelysimple.You'llneedtoberelativelyexperiencedin eithertheC#orVisualBasiclanguage,andunderstandgeneralobjectorientedprogramming techniques.Ifyouwanttoruntheexamples,youmusthaveatleastversion3.5ofthe.NETFramework withServicePack1installed.Tobeabletoviewanddebugthesamplesourcecode,youwillneedVisual Studio2008(anyversion)orhigher.However,ifyouwanttobeabletoviewandrunthesourcecode andunittestsforEnterpriseLibraryitself,youwillneedatleastVisualStudio2008TeamSuiteEdition. Otherthanthat,allyourequireissomesparetimetositandread,andtoplaywiththeexample programs.Hopefullyyouwillfindthecontentsinteresting(andperhapsevenentertaining),aswellasa usefulsourceforlearningaboutEnterpriseLibrary.

TheTeamWhoBroughtYouThisGuide
PrimaryAuthor
AlexHomer

Contributors
NicholasBotto,GrigoriMelnik,EricRenaud,FernandoSimonazzi,ChrisTavares

EnterpriseLibrary5.0Team
Product/ProgramManagement GrigoriMelnik Architecture/Development BobBrumfield,OlafConijn,FernandoSimonazzi,ChrisTavares Testing NicolasBotto,CarlosFarre,MeenakshiKrishnamoorthi,ManiKrishnaswami,MasashiNarumoto,Erik Renaud,LavanyaSelvaraj,RohitSharma,MagdeleneSona,SachinTah,FranoisTanguay,Ravindra Varman

AGuidetoDevelopingwithEnterpriseLibrary5.0

UserExperience HeidiAdkisson,JenAmsterlaw,BradCunningham,KellyFranznick,DamonvanVessem Documentation AlexHomer,DennisDeWitt,LennyFenster EditingandRelease RichardBurte,RoAnnCorbisier,NellyDelgado,TracyEmory

patterns&practicesLeadershipTeam
MohammadAlSabt,JohnDeVadoss,SteveElston,DavidHill,AjoyKrishnamoorthy,AdeMiller,Don Smith

AdvisoryCouncil
[Memberstobelistedinthefinalversionwithpermission]

Community
Attendeesatpatterns&practicessummits,PDC,TechReadyandTechEdconferenceswhoprovided informalfeedbackonthis. EnterpriseLibraryuserswhocommentedonthisgudieonCodeplex. Thankyou!

AGuidetoDevelopingwithEnterpriseLibrary5.0

Chapter1MeettheLibrarian

Introduction............................................................................................................................................9 WhatYouGetwithEnterpriseLibrary.................................................................................................... 9 ThingsYouCanDowithEnterpriseLibrary........................................................................................... 10 WhyShouldIUseEnterpriseLibrary? ................................................................................................... 11 SomeFundamentalsofEnterpriseLibrary ............................................................................................ 12 InstallingEnterpriseLibrary.............................................................................................................. 12 AssembliesandReferences.............................................................................................................. 12 SignedorUnsigned,GACorBin?............................................................................................. 13 UsingImports........................................................................................................................... 14 InterblockDependencies................................................................................................................. 15 ConfiguringEnterpriseLibrary.............................................................................................................. 16 EncryptingConfigurationSections.................................................................................................... 17 InstantiatingEnterpriseLibraryObjects............................................................................................... 19 HowEnterpriseLibraryUsesDependencyInjection ......................................................................... 20 ResolvingInstancesofEnterpriseLibraryObjects............................................................................ 21 InjectingInstancesofEnterpriseLibraryObjectsintoYourApplication..........................................21 InitializingtheContainer.......................................................................................................... 22 ResolvingInstancesofObjectsDirectly................................................................................... 22 InjectingInstancesofObjects.................................................................................................. 23 ConstructorInjection............................................................................................................... 26 Property(Setter)Injection....................................................................................................... 26 MethodCallInjection............................................................................................................... 27 Summary...............................................................................................................................................28

AGuidetoDevelopingwithEnterpriseLibrary5.0

1.1

Introduction

BeforewebeginourexplorationofMicrosoftEnterpriseLibrary,andthewondrousrangeofcapabilities andopportunitiesitencompasses,youneedtomeettheLibrarian.SometimeswecallhimTom, sometimeswecallhimChris,andsometimeswecallhimGrigori.But,despitethissomewhatunnerving namevariability,heincollaborationwithanadvisoryboardofexpertsfromtheindustryandother internalMicrosoftproductgroups,andaconsiderablenumberofothercommunitycontributorsisthe guardianandprotectoroftheMicrosoftpatterns&practicesEnterpriseLibrary. Sinceitsinceptionasadisparatecollectionofindividualapplicationblocks,theLibrarianhasguided, prodded,inspired,andencouragedhisteamofelvestotransformitintothecomprehensive,powerful, easytouse,andprovenlibraryofcodethatcanhelptominimizedesignpain,maximizedevelopment productivity,andreducecosts.Andnow,inversion5.0,itcontainsevenmorebuiltingoodnessthatwill hopefullymakeyourjobeasier.It'sevenpossiblethat,withthetimeandeffortyouwillsave,Enterprise Librarycanreduceyourgolfhandicap,helpyoumastertheskislopes,letyouspendmoretimewith yourkids,orjustmakeyouabetterperson.However,notethattheauthor,thepublisher,andtheir employeescannotbeheldresponsibleifyoujustendupwatchingmoreTVordiscoveringyouactually havealife. Whatareapplicationblocks?Acommondefinitionweuseis"reusablesoftwarecomponentsdesigned toassistdeveloperswithcommonenterprisedevelopmentchallenges".Applicationblockshelpaddress thecommonproblemsthatdevelopersfacefromonelineofbusinessprojecttothenext.Theirdesign encapsulatestheMicrosoftrecommendedpracticesfor.NETapplications;anddeveloperscanaddthem to.NETapplicationsquicklyandeasily.

1.2

WhatYouGetwithEnterpriseLibrary

EnterpriseLibraryismadeupofaseriesofapplicationblocks,eachaimedatmanagingspecific crosscuttingconcerns.Incasethiswordisunfamiliar,crosscuttingconcernsarethoseannoyingtasks thatyouneedtoaccomplishinseveralplacesinyourapplication,andwherethereisariskthatyoumay endupimplementingslightlydifferentspecificsolutionsateachlocation(orjustforgettingit altogether).SomegoodexamplesofthisarewritingentriestoasystemlogfileorWindowsEventLog, cachingdata,andvalidatinguserinput.Whilethereareseveralapproachestomanagingyour crosscuttingconcerns,theEnterpriseLibraryapplicationblocksmakeitawholeloteasierbyproviding genericandconfigurablefunctionalitythatyoucancentralizeandmanage. Aswellastheapplicationblocks,EnterpriseLibrarycontainsconfigurationtools,plusasetofcore functionsthatmanagetasksapplicabletoalloftheblocks.Someofthesefunctionsareexposedand availableforyoutouseinyourownapplicationsforexample,routinesforhandlingconfigurationand serialization.

AGuidetoDevelopingwithEnterpriseLibrary5.0

And,onthegroundsthatyouneedtolearnhowtouseanynewtoolthatismorecomplicatedthana hammerorscrewdriver,EnterpriseLibraryincludesarangeofsampleapplications,descriptionsofkey scenariosforeachblock,handsonlabs,andcomprehensivereferencedocumentation.Youevengetall ofthesourcecode,andtheunitteststhattheteamcreatedwhenbuildingeachblock(theteamfollows testdrivendesignpracticesbywritingtestsbeforewritingcode).Soyoucanunderstandhowitworks, seehowtheteamusesbestpracticestocreateit,andthenmodifyitifyouwantittodosomething different.

1.3

ThingsYouCanDowithEnterpriseLibrary

Ifyoulookattheinstalleddocumentation,you'llseethatEnterpriseLibrarytodayactuallycontainsnine applicationblocks.However,thereareactuallyonlysevenblocksthat"dostuff"thesearereferredto asfunctionalblocks.Theothertwoareconcernedwith"wiringupstuff"(the"wiringblocks").What thisreallymeansisthattherearesevenblocksthattargetspecificcrosscuttingconcernssuchas caching,logging,dataaccess,andvalidation.Theothertwo,theUnityDependencyInjectionMechanism andthePolicyInjectionApplicationBlock,aredesignedtohelpyouimplementmorelooselycoupled, testable,andmaintainablesystems. OK,soEnterpriseLibraryreliesonthefeaturesofUnitytocreateobjectswithintheblocks,butthatjust showshowgenerallyusefulUnityis.Inthisbook,we'llbeconcentratingonthesevenfunctionalblocks. IfyouwanttoknowmoreabouthowyoucanuseUnityandthePolicyInjectionApplicationBlock,look outforoursistertitle"WhatevertheUnityBookIsCalled".Thefollowinglistdescribesthecrosscutting scenariosyou'lllearnaboutinthisbook: Caching.TheCachingApplicationBlockletsyouincorporatealocalcacheinyourapplications thatusesaninmemorycacheand,optionally,adatabaseorisolatedstoragebackingstore.The blockprovidesallthefunctionalityneededtoretrieve,add,andremovecacheddata,and supportsconfigurableexpirationandscavengingpolicies.Youcanalsoextenditbycreating yourownpluggableprovidersorusingthirdpartyproviders;forexampletosupportdistributed cachingandotherfeatures.Cachingcangiveconsiderableimprovementsinperformanceand efficiencyinmanyapplicationscenarios. CredentialManagement.TheSecurityApplicationBlockletsyoueasilyimplementcommon authorizationrelatedfunctionality,suchascachinguser'sauthorizationandauthenticationdata andintegratingwiththeMicrosoft.NETFrameworksecurityfeatures. DataAccess.TheDataAccessApplicationBlocksimplifiesmanycommondataaccesstaskssuch asreadingdatafordisplay,passingdatathroughapplicationlayers,andsubmittingchanged databacktothedatabasesystem.Itincludessupportforbothstoredproceduresandinline SQL,canexposethedataasasequenceofobjectsforclientsidequerying,andprovidesaccess tothemostoftenusedfeaturesofADO.NETinsimpletouseclasses.

AGuidetoDevelopingwithEnterpriseLibrary5.0

10

Encryption.TheCryptographyApplicationBlockmakesiteasytoincorporatecryptographic functionalitysuchasencryptinginformation,creatingahashfromdata,andcomparinghash valuestoverifythatdatahasnotbeenaltered. ExceptionHandling.TheExceptionHandlingApplicationBlockletsyouquicklyandeasilydesign andimplementaconsistentstrategyformanagingexceptionsthatoccurinvariousarchitectural layersofyourapplication.Itcanlogexceptioninformation,hidesensitiveinformationby replacingtheoriginalexceptionwithanotherexception,andmaintaincontextualinformation foranexceptionbywrappingtheoriginalexceptioninsideanotherexception. Logging.TheLoggingApplicationBlocksimplifiestheimplementationofcommonlogging functionssuchaswritinginformationtotheWindowsEventLog,anemailmessage,adatabase, WindowsMessageQueuing,atextfile,aWMIevent,oracustomlocation. Validation.TheValidationApplicationBlockprovidesarangeoffeaturesforimplementing structuredandeasytomaintainvalidationmechanismsusingattributesandrulesets,and integratingwithmosttypesofapplicationinterfacetechnologies.

1.4

WhyShouldIUseEnterpriseLibrary?

Asyoucanseefromtheprevioussection,EnterpriseLibraryprovidesacomprehensivesetoffeatures thatcanhelpyoutomanageyourcrosscuttingconcernsthoughareusablesetofcomponentsandcore functionality.Ofcourse,likemanydevelopers,youmaysufferfromthewellknownNIH("NotInvented Here")Syndrome.But,seriously,isntitabouttimethateverydeveloperonyourteamstoppedwriting hisorherownloggingframework?It'sacommonlyacceptedfactthattheuseofstandardandproven codelibrariesandcomponentscansaveondevelopmenttimeandcost,useofprecioustestresources, andmaintenanceoveralleffort.InthewordsoftheLibrarian,Thesedaysyoucannotaffordnotto reuse. Andit'snotasthoughEnterpriseLibraryissomenewkidontheblock,whomightmorphintosomething completelydifferentnextmonth.EnterpriseLibraryasaconcepthasbeenaroundformanyyears,and haspassedthroughfivefullreleasesofthelibraryaswellasintermediateincrementalreleases. EnterpriseLibrarydoesevolvealongwiththecapabilitiesofthe.NETFramework.Asthe.NET Frameworkchangesovertime,somefeaturesthatwerepartofEnterpriseLibraryaresubsumedinto thecore,whileEnterpriseLibrarychangestotakeadvantageofthenewfeaturesavailableinboththe .NETFrameworkandtheunderlyingsystem.Examplesarenewprogramminglanguagecapabilities,and improvedperformanceandcapabilitiesinthe.NETconfigurationandIOmechanisms.Yet,evenin version5.0,thevastmajorityofthecodeisentirelybackwardscompatiblewithapplicationswrittento useEnterpriseLibrary2.0. YoucanalsouseEnterpriseLibraryaslearningmaterialnotonlytoimplementdesignpatternsinyour application,butalsotolearnhowthedevelopmentteamappliespatternswhenwritingcode.Enterprise Libraryembodiesmanydesignpatterns,anddemonstratesbestpracticearchitecturalandcoding AGuidetoDevelopingwithEnterpriseLibrary5.0 11

techniques.Thesourcecodefortheentirelibraryisprovided,andsoyoucanexplorethe implementationsandreusethetechniquesinyourownapplications. And,finally,itisfree!Orrather,itisdistributedundertheMicrosoftPublicLicensethatgrantsyoua royaltyfreelicensetobuildderivativeworks,anddistributethemfreeorevensellthem.Youmust retaintheattributionheadersinthesourcefiles,butyoucanmodifythecodeandincludeyourown customextensions.DoyouneedanyotherreasonstotryEnterpriseLibrary? You'llnoticethat,eventhoughwedidn'tput"Don'tPanic"inlargefriendlylettersonthecover,this bookdoestakealittletimetosettledownintoamoreusualdocumentationstyleandstartprovide usefulinformation.However,youcanbesurethatfromhereoninyou'llfindawholerangeof guidanceandexamplesthatwillhelpyoumasterEnterpriseLibraryquicklyandeasily.

1.5

SomeFundamentalsofEnterpriseLibrary

BeforewediveintoourtouroftheapplicationblocksandfeaturesofEnterpriseLibrary,youneedto graspsomefundamentals.Inthischapter,theLibrarianwillhelpyoutoexploretopicssuchasthe contentsofthelibrary,thebroadaimsofthelibraryandeachapplicationblock,howyouinstalland deploythelibrary,andhowyouperforminitialconfiguration.Afterthat,you'llbefreetoskiptoanyof theotherchaptersandlearnmoreaboutthewaysthateachblockhelpsyoutosimplifyyourcodeand manageyourcrosscuttingconcerns.Formoreinformationaboutthetopicscoveredhere,seethe productdocumentationinstalledwithEnterpriseLibrary,ortheonlinedocumentationavailableat http://msdn.microsoft.com/entlib/.

1.5.1 InstallingEnterpriseLibrary
ThefirststepistoobtainandinstallEnterpriseLibrary.Youcandownloadthecurrentversionfrom http://msdn.microsoft.com/entlib/.SimplyruntheMicrosoftInstaller(MSI)packagetobeginthe installation.Ifyouwanttoexaminethesourcecode,andperhapsevenmodifyittosuityourown requirements,besuretoselecttheoptiontoinstallthesourcecodewhenyouruntheinstaller.It'salso agoodideatoselecttheoptiontohavetheinstallercompilethelibraryforyousothatyouarereadyto startusingitstraightaway. Aftertheinstallationiscomplete,youwillseeaStartmenuentrycontaininglinkstotheEnterprise Librarytools,sourcecode,anddocumentation.Thetoolsincludebatchfilesthatinstallinstrumentation, databasefiles,andothersettingsforthesamples.Therearealsobatchfilesthatyoucanusetocompile theentirelibrarysourcecode,andtocopyalltheassembliestothebinfolderinthesourcecodefolders.

1.5.2 AssembliesandReferences
EnterpriseLibraryisa"pickandmix"candystore,whereyoupickjustthefeaturesyouwanttouseand simplydisregardtherest.Ofcourse,beforeyoucanchooseyourfavoritecandiesfromthetempting displaysinthecandystore,youneedtofindapaperbagtoholdthem.Youcanthinkofthisasa

AGuidetoDevelopingwithEnterpriseLibrary5.0

12

prerequisitefor"pickingandmixing",andabasicfeaturethatyouwilluseeverytimeirrespectiveof whetheryouchoosegummybears,chocolatecoveredhazelnuts,ormintimperials. Likewise,withEnterpriseLibrary,thereareprerequisitesandbasicfeatures.Themainprerequisite beforeyoustartdevelopmentistoinstallthebinariesandsupportfilesontoyourmachine.Thebasic featuresthatyouneedeverytimeyouuseEnterpriseLibraryarethecoreassembliesthatimplement accesstoconfiguration,objectcreation,andancillarycommonfeatures. It'snotuncommon,whenpeoplefirstlookatEnterpriseLibrary,toseealookofmildpanicspread acrosstheirfaces.Yes,therearealotofassembliesover100inallbutremember: Youonlyneedtousethosedirectlyconnectedwithyourownscenario. Severalarerequiredforonlyveryspecialistsituations. Manyareonlyforusebytheconfigurationtools,andyouneverusetheseassembliesinyour applications. Theyaremostlylessthan100KBinsize;andthelargestofallislessthan300KB. Inmostapplications,thetotalsizeofalltheassembliesyouwillusewillbelessthan2MB.

ThefiveassembliesyoumustaddtoanyapplicationthatusesEnterpriseLibraryarethecommon(core) assembly,theUnitydependencyinjectionmechanism,andthecontainerservicelocationassembly: Microsoft.Practices.EnterpriseLibrary.Common.dll Microsoft.Practices.Unity.dll Microsoft.Practices.Unity.Configuration.dll Microsoft.Practices.Unity.Interception.dll. Microsoft.Practices.ServiceLocation.dll

Inadditiontotherequiredassemblies,youmustreferencetheassembliesthatimplementthe EnterpriseLibraryfeaturesyouwilluseinyourapplication.Thereareseveralassembliesforeach applicationblock.Generally,thesecomprisea"main"assemblythathasthesamenameastheblock (suchasMicrosoft.Practices.EnterpriseLibrary.Caching.dll),plusadditionalassembliesthatimplement specifichandlersorcapabilitiesfortheblock.Youonlyneedtheseadditionalassembliesifyouwantto usethefeaturestheyadd.Forexample,inthecaseoftheCachingblock,thereareseparateassemblies forcachingtoadatabase(Microsoft.Practices.EnterpriseLibrary.Caching.Database.dll)andencrypting cacheddata(Microsoft.Practices.EnterpriseLibrary.Caching.Cryptography.dll).Ifyouonlycache unencrypteddatainmemory,youdonotneedtoreferencethesetwoassemblies. SignedorUnsigned,GACorBin? Alloftheassembliesareprovidedasprecompiledsignedversions,whichyoucaninstallintotheGlobal AssemblyCache(GAC)ifyouwish.However,ifyouneedtorundifferentversionsofEnterpriseLibrary

AGuidetoDevelopingwithEnterpriseLibrary5.0

13

assembliessidebyside,thismaybeproblematicandyoumayprefertolocatetheminfolderscloseto yourapplication. Youcanthenreferencethecompiledassembliesinyourprojects,whichautomaticallycopiesthemto thebinfolder.InaWebapplication,youcansimplycopythemdirectlytoyourapplication'sbinfolder. Thisapproachgivesyousimpleportabilityandeasyinstallation. Alternatively,youcaninstallthesourcecodeforEnterpriseLibraryandusethescriptsprovidedto compileunsignedversionsoftheassemblies.Thisisusefulifyoudecidetomodifythesourcecodeto suityourownspecificrequirements.Youcanstrongnameandsigntheassembliesusingyourown credentialsafterwardsifrequired. Formoreinformationaboutsidebysideoperation,andotherdeploymentissues,seeoursister publication"Whatevertheadministratorguideiscalled"orthedocumentationinstalledwithEnterprise Libraryandavailableonlineathttp://msdn.microsoft.com/entlib. UsingImports Afteryoureferencetheappropriateassembliesinyourprojects,youwillprobablywanttoadd statementstoyourprojectfilestosimplifyyourcodeandavoidspecifyingobjectsusingthefull assemblyandclassnames.MostoftheEnterpriseLibraryassembliescontainseveralnamespacesto organizethecontents.Forexample,asyoucanseethefollowingfigure,themainassemblyforthe Loggingblock(oneofthemorecomplexblocks)containsadozensubsidiarynamespaces.Ifyouuse classesfromthesenamespaces,suchasspecificfilters,listeners,orformatters,youmayneedtoadd usingorImportsstatementsforthesenamespaces(dependingonyourdevelopmentcodelanguage).

AGuidetoDevelopingwithEnterpriseLibrary5.0

14

1.5.3 InterblockDependencies
EnterpriseLibraryis,asitsnamesuggest,alibraryofcodecomponentsandobjects.Toacertainextent, thesecomponentshaveoptionaldependenciesuponeachother.Forexample,alloftheapplication blocksrelyonfeaturesintheEnterpriseLibrarycoreassembly.Therearealsooptionalpluggable dependenciesbetweentheblocks,suchastherelianceoftheExceptionHandlingblockontheLogging blockforloggingexceptioninformation.Thefollowingtableandschematicshowthefulllistofthese pluggabledependencies.
Application Block Caching Block Dependencies May use the Data Access block to cache data in a database. May use the Cryptography block to encrypt cached data. Exception Handling Block May use the Logging block to log exception information. May use the Data Access block to log exception information to a database. Logging Block Security Block May use the Data Access block to log to a database. May use the Caching block to cache credentials. May use the Data Access block to cache credentials in a database. May use the Cryptography block to encrypt cached credentials.

AGuidetoDevelopingwithEnterpriseLibrary5.0 15

Theconfigurationtoolswillautomaticallyaddtherequiredblocktoyourapplicationwiththedefault configurationwhenrequired.Forexample,whenyouaddaLogginghandlertoanExceptionHandling blockpolicy,theconfigurationtoolwilladdtheLoggingblocktotheconfigurationwiththedefault settings.

1.6

ConfiguringEnterpriseLibrary

Oneofthebiggestchallengesforuserspriortothecombiningoftheoriginalindividualapplication blocksintoEnterpriseLibrarywasconfiguration.Youhadtoeditthesectionsoftheapplication configurationfilemanually,whichprovedtobeerrorproneandjustplainannoying.InEnterprise Library,youhaveachoiceoftoolsforperformingconfiguration.Thereisastandalonetoolcalledthe configurationeditor,whichyoucanrunatanytime.Youcanevencopyit(andtheassembliesisuses)to amachinethatdoesnothaveEnterpriseLibraryinstalledifyoujustwanttoperformpostdeployment configuration.Thefollowingfigureshowstheconfigurationconsolewithalloftheapplicationblocks coveredinthisbookinstalledintotheconfiguration. [Awaitingimageofconfigurationconsole] EnterpriseLibraryalsocontainsaconfigurationtoolthatintegrateswithVisualStudio.TheVisualStudio ConfigurationEditordisplaysaverysimilarinterfacetothatshowninFigure2,butallowsyoutoedit yourconfigurationfileswithasimplerightclickinSolutionExplorer. Youcancreateanewapplicationconfigurationfile(suchasWeb.configorApp.config)bycreatinganew EnterpriseLibraryconfigurationintheconfigurationconsoleandthensavingittodisk,oryouanopen anexistingconfigurationfileandeditittoaddEnterpriseLibrarytoyourapplication.Eitherway,once youhavetheconfigurationfileopen,thegeneraltechniqueforcreatinganewconfigurationfileand configuringtheapplicationisasfollows: [Allofthefollowingprocedureneedstobeupdated] 1. RightclicktherootEnterpriseLibraryConfigurationnodeintheconfigurationconsole,pointto New,andclickApplication. 2. RightclicktheApplicationConfigurationnodethatappears,pointtoNew,andclickthename oftheapplicationblockyouwanttoaddtoyourconfiguration. Ifyouopenanexistingconfigurationfile,youwillseethefullpathandnameofthefileinstead of"ApplicationConfiguration".

AGuidetoDevelopingwithEnterpriseLibrary5.0

16

3. Seetherelevantchapterlaterinthisbookfortheapplicationblockyouchosefordetailsofhow toconfigureindividualfeaturesoftheblock. 4. Ifyouwanttousetheconfigurationconsoletoeditvaluesinthe<appSettings>sectionofyour configurationfile,rightclicktheApplicationConfigurationnode,pointtoNew,andclick ApplicationSettings.ThenrightclicktheApplicationSettingsnode,pointtoNew,andclick Setting.Youcantheneditthenameandvalueforthatsetting,andaddadditionalsettingsas required. Ifyouopenanexistingconfigurationfilethatalreadycontainsan<appSettings>section,you willseeanyexistingsettingsandyoucaneditthemhere. 5. ToenabletheEnterpriseLibrarybuiltininstrumentation,rightclicktheApplication Configurationnode,pointtoNew,andclickInstrumentation.Theneditthevaluesinthat sectiontoturnontherequiredinstrumentation.Seethedocumentationinstalledwith EnterpriseLibraryforinformationonusingtheEnterpriseLibrarybuiltininstrumentation. 6. Ifyouwanttostoreyourconfigurationinalocationotherthanafile,rightclicktheApplication Configurationnode,pointtoNew,andclickConfigurationSources.Thenaddandconfigurethe configurationsourceyouwanttouse.YoucanuseaManageableConfigurationSourceto enforceGroupPolicysettingsandexposeconfigurationinformationthroughWMI.Seethe documentationinstalledwithEnterpriseLibraryforinformationonusingalternative configurationsources. 7. Ifyouwanttoconfiguredifferentsettingsforanapplicationbasedondifferentdeployment scenariosorenvironments,rightclicktheEnvironmentsnode,pointtoNew,andclick Environment.Thisfeatureisusefulifyouhavemultipleenvironmentsthatsharethesamebasic configurationbutrequiredifferentpropertysettings.Itallowsyoutocreateabase configurationfile(.config)andanenvironmentdeltafilethatcontainsthedifferences(.dconfig). SeethedocumentationinstalledwithEnterpriseLibraryforinformationonconfiguringand mergingenvironments. 8. Whenyouhavefinishedconfiguringyourapplication,saveitasafileinyourapplicationfolder withtheappropriatename;forexample,useWeb.configforaWebapplicationandApp.config foraWindowsFormsapplication.

Youcan,ofcourse,edittheconfigurationfilesusingatextorXMLeditor,butitislikelytobeapainful processcomparedtousingtheconfigurationconsole.However,itmaybeausefulapproachforminor changestotheconfigurationwhentheapplicationisrunningonaserverwheretheconfiguration consoleisnotinstalled.

1.6.1 EncryptingConfigurationSections
Probablythemostcommonapproachforstoringconfigurationinformationforyourapplicationsthat useEnterpriseLibraryistouseanApp.configorWeb.configfilestoredintherootfolderofyour

AGuidetoDevelopingwithEnterpriseLibrary5.0

17

application.That'sfine,butyoumaybeconcernedthatanyonewhohappenstostrollpasttheserver (eitherphysically,orvirtuallyovertheInternet)willbeabletoopenthefileandseesensitivedetails. ThesemightincludeconnectionstringsfortheDataAccessblock,validationrulesfortheValidation block,orconnectioninformationusedbytheLoggingblocktocommunicatewithWindowsMessage Queuing. While,intheory,youwillprotectyourconfigurationfilesbyphysicallysecuringtheserverandnot leavingitrunningunderaloggedonadministratoraccount,youcan(andprobablyshould)addanextra layerofprotectionbyencryptingsectionsofyourconfigurationfiles.Theconfigurationtoolscandothis foryouautomaticallyallyouneedtodoissettheProtectionProviderpropertyofthespecificblockor configurationsectionthatyouwanttoencrypt. Youcanselectanyoftheencryptionprovidersthatareincludedinyoursystem'sMachine.configfile. Typically,thesearetheDataProtectionConfigurationProvider,whichusesDPAPI,andthe RsaProtectedConfigurationProvider,whichusesRSA.Thesettingsfortheseproviders,suchaswhere keysarestored,arealsointheMachine.configfile.Youcannoteditthisfilewithaconfigurationtool; instead,youmustmodifyitusingatexteditororanoperatingsystemconfigurationtool. Asanexampleoftheeffectofthisoption,thefollowingisasimpleunencryptedconfigurationforthe DataAccessblock. XML
<dataConfigurationdefaultDatabase="ConnectionString"/> <connectionStrings> <addname="ConnectionString" connectionString="Database=TheImportantOne;Server=WEHAVELIFTOFF; UserID=secret;Password=DontTellNE1" providerName="System.Data.SqlClient"/> </connectionStrings>

WhenyouspecifytheDataProtectionConfigurationProvideroption,theresultingconfigurationsection lookslikethefollowing. XML


<dataConfiguration configProtectionProvider="DataProtectionConfigurationProvider"> <EncryptedData> <CipherData> <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAc8HVTgvQB0quQI81ya0uH ... JyEadytIBvTCbmvXefuN5MWT/T</CipherValue> </CipherData> </EncryptedData> </dataConfiguration> <connectionStrings configProtectionProvider="DataProtectionConfigurationProvider"> <EncryptedData> <CipherData>

AGuidetoDevelopingwithEnterpriseLibrary5.0

18

<CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAc8HVTgvQB0quQI81ya0uH ... zBJp7SQXVsAs=</CipherValue> </CipherData> </EncryptedData> </connectionStrings>

Ifyouonlyintendtodeploytheencryptedconfigurationfiletotheserverwhereyouencryptedthefile, youcanusetheDataProtectionConfigurationProvider.However,ifyouwanttodeploytheencrypted configurationfileonadifferentserver,oronmultipleserversinaWebfarm,youshouldusethe RsaProtectedConfigurationProvider.YouwillneedtoexporttheRSAprivatekeythatisrequiredto decryptthedata.Youcanthendeploytheconfigurationfileandtheexportedkeytothetargetservers, andreimportthekeys.Formoreinformation,seeImportingandExportingProtectedConfigurationRSA KeyContainers. Ofcourse,thenextobviousquestionis"HowdoIdecrypttheconfiguration?"Thankfully,youdon't needto.Youcanopenanencryptedfileintheconfigurationtoolsaslongasitwascreatedonthat machineoryouhaveimportedtheRSAkeyfile.Inaddition,EnterpriseLibrarywillbeabletodecrypt andreadtheconfigurationautomaticallyprovidingthatthesameconditionsapply.

1.7

InstantiatingEnterpriseLibraryObjects

Asyouwillseeineachofthefollowingchapters,theEnterpriseLibraryapplicationblocksareoptimized foruseaslooselycoupledcomponentsinalmostanytypeofapplication.Ingeneral,youwillcreate instancesofthecomponentsorfaadesthatyouneedtointeractwithusingtheDependencyInjection (DI)pattern.Bydefault,EnterpriseLibraryusestheUnitydependencyinjectionmechanism(afeatureof EnterpriseLibrary)toinjecttheobjectsyouconfigureforeachblockintoyourapplications. Unityisalightweight,flexible,configurable,andextensibledependencyinjectioncontainerthat supportsconstructor,propertysetter,andmethodcallinjection(aswellasinstanceandtype interception).YoucanuseitasastandaloneDIcontainerifyouwish,althoughwedonotcoveritsuse inthisbook.However,tobeabletoworkeffectivelywithEnterpriseLibrary,youshouldbefamiliarwith thebasicapproachesforcreatingEnterpriselibraryobjects,andinjectingEnterpriseLibraryobjectsinto yourapplicationclassesandcomponents. FormoreinformationonhowyoucanuseUnitytoinjectyourowncustomobjectsandcomponents,see oursisterpublication"Whatevertheunityguideiscalled". IfyouhaveusedversionsofEnterpriseLibrarypriortoversion5.0,youmaybemorefamiliarwiththe previousapproachtocreatingobjectswithinyourapplicationcode.Earlierversionsgenerallysupported orrecommendeduseofstaticfaades,ordirectinstantiationofEnterpriseLibraryobjects.Whilethese approachesarestillsupportedinversion5.0forbackwardcompatibilitywithexistingapplications,they arenolongertherecommendedapproachandmaybedeprecatedinfuturereleases.

AGuidetoDevelopingwithEnterpriseLibrary5.0

19

1.7.1 HowEnterpriseLibraryUsesDependencyInjection
TounderstandhowyoucancreateinstancesoftheEnterpriselibraryobjectsyouwillworkwith,it's usefultoseehowEnterpriseLibraryusestheconfigurationyouspecifytogenerateindividualinstances oftheclassescontainedinthelibrary.Thefollowingschematicshowstheoverallprocess,thoughyoudo notneedtobeconcernedwiththedetailsofhowitworksifyouarehappytouseEnterpriselibraryinits defaultconfiguration.AllthishappensautomaticallyafteryouaddEnterpriseLibrarytoyourapplication.

Intheschematic,youcanseethattheconfigurationisloadedintoacontainercalledthe EnterpriseLibraryContainer.BydefaultthisisaUnityDIcontainer,thoughyoucanuseanyotherthird partyDIcontaineraslongasthereisaconfiguratoravailablethatcanloaditwiththeconfiguration informationyouspecify.Fordetailsofhowtouseralternativecontainers,seethedocumentation installedwithEnterpriseLibraryoronthecommunityWebsiteathttp://www.codeplex.com/entlib.

AGuidetoDevelopingwithEnterpriseLibrary5.0

20

1.7.2 ResolvingInstancesofEnterpriseLibraryObjects
AllyoureallyneedtoknowisthatyoucanobtainaninstanceofanyEnterpriseLibraryobject anywhereinyourcodesimplybycallingastaticmethodofthecontainer.TheCurrentpropertyofthe EnterpriseLibraryContainerexposesareferencetoaclasscalledtheServiceLocator.TheServiceLocator providesseveraloverloadsoftheGetInstancemethodthatresolveobjectsthroughthecontainer.For example,togetaninstanceoftheLogWriterclassthattheLoggingblockusestocreateandwritelog messages,yousimplyusethefollowingcodetoobtainaninstanceofthedefaultobjectofthespecified type.
//ResolvethedefaultLogWriterobjectfromthecontainer. varwriter=EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();

NoticethatthiscodeusestypeinferencethroughthevarkeywordinC#,andomittingthevariabletype nameinVisualBasic.Thevariablewillassumethetypereturnedbytheassignment;inthiscasethetype LogWriter. However,youcanconfiguremorethanoneinstanceoftypeforablock,suchasmultipleCache ManagersfortheCachingblock;andyoucanspecifyintheconfigurationwhichoneisthedefault.Each providerortypeyouconfigureinEnterpriseLibraryhasaname.Forexample,youmayconfigurea CacheManagernamedIsoStorethatusesWindowsisolatedstorage,andasecondCacheManager namedSQLDBthatusesaSQLServerdatabasetocachetheitems.Inthiscase,youspecifythenameof theobjectyouwanttoresolvewhenyoucalltheGetInstancemethod,asshownhere.


//ResolvetheCacheManagerobjectnamedIsoStoragefromthecontainer. varcacheMgr =EnterpriseLibraryContainer.Current.GetInstance<ICacheManager>("IsoStore");

Youcanalsoseeinthiscodethatweareactuallyspecifyinganinterfaceratherthantheconcreteclass wewant.However,thecontaineralwaysreturnsconcretetypes,evenifyouresolveaninterface.When youresolveanobjectoraknowninterfaceinEnterpriseLibrary,thecontainerusestheconfiguration loadedintoittodeterminewhichconcretetypetoreturn. ManyEnterpriseLibraryobjectsimplementinterfacesthatdefinethedifferentconcrete implementationsofthatinterface.TheICacheManagerinterfaceisatypicalexample.Thisallowsyouto createyourowncustomimplementationsoftheseobjectsifyouwishbyimplementingtheinterface andcompilingthemintothelibrary.Youcanthenspecifyyourowncustomtypeintheconfigurationfor thelibrary. Writingcodethatspecifiestheinterfaceinsteadofaparticularconcretetypemeansthatyoucan changetheconfigurationtospecifyadifferentconcretetypewithoutneedingtochangeyourcode.Just bearinmindthatnotalltypesinEnterpriseLibraryimplementaninterfacethatyoucanresolve.

1.7.3 InjectingInstancesofEnterpriseLibraryObjectsintoYourApplication
Whilethebasicapproachdescribedintheprevioussectionisfineformostapplications,youmaydecide totakeadvantageoftheUnitydependencyinjectionmechanism(oranalternativethirdpartyDI

AGuidetoDevelopingwithEnterpriseLibrary5.0

21

mechanism)tofurtherdecouplethecomponentsandobjectsinyourapplications.Insteadofspecifically resolvinginstancesofEnterpriseLibraryobjectsusingtheGetInstancemethod,youcanusethe containertoresolveobjectinstancesandautomaticallyinjectthemintotheparametersofconstructors ormethods,ortoautomaticallysetthevaluesofdependentpropertiesinyourclasses. Infact,youmayevendecidetohavethecontainercreateandinjectinstancesoftheappropriatetypes forallofthedependenciesdefinedinyourapplicationwhenitstartsup.Whileitmayseemtobea strangeconcept,youcanoftendothisbyresolvingthemainformorstartupclassthroughthecontainer (thoughthismaynotbepossiblewithallthirdpartycontainers).IfyouareusingUnity,youcansimply defineparametersorpropertiesinyourapplicationclassesandwherenecessarymarkthemwiththe appropriatedependencyattributes.Whenyouresolvethemainstartupclassofyourapplication,ora classthatcontainssuchparametersandattributes,throughthecontaineritwillautomaticallycreatethe appropriateinstancesoftheobjectsrequiredbyeachclassandinjectthemintotheparametersand properties. Tousethistechnique,youmustfirstinitializethecontainer.Youcanalsoholdontoareferencetothe containerforuseelsewhereinyourcodeifrequired.ThenyouusetheResolvemethodofthecontainer tocreateyourclassesandperformtheinjection.Thefollowingsectionsdescribethesestepsinmore detail.However,wedonothaveroominthisguideforafullexplanationofallthetechniquesand optionsavailable(Unityisaverypowerfulmechanismwithmanyotherfeatures),andsothefollowing sectionsdescribethebasicsyouneedtoknowtousethisapproach.Forafullexplanationofhowyou canuseUnityanddependencyinjectiontechniques,seeourrelatedguide"Whatevertheunityguideis called",orthedocumentationinstalledwithEnterpriseLibrary. InitializingtheContainer WhenusingthedefaultUnityDImechanism,allyouneedtodoisinitializethecontaineronceonyour application;andthenuseittoresolve(orobtain)instancesofEnterpriseLibraryobjectsoryourown classesandobjects.Initializingthecontainerrequiresjustthefollowingonelineofcode.
//Createandpopulatethedefaultcontainerwithapplicationconfiguration. varcontainer=newUnityContainer() .AddNewExtension<EnterpriseLibraryCoreExtension>();

YoucanstorethecontainerinaglobalvariableinaWindowsFormsorWPFapplication,inthe Application(orintheSessionifyouwanttostoreindividualcontainersforeachuser)ofanASP.NET application,orinacustomextensiontotheInstanceContextofaWCFservice.Formoreinformation abouttheseandotherapproachestostoringthecontainerreference,seethedocumentationinstalled withEnterpriseLibraryandavailableonMSDN. ResolvingInstancesofObjectsDirectly UnityexposesamethodnamedResolvethatallowsyoutoresolveobjectsthroughthecontainer directly.Thereisarangeofoverloadsthatallowyoutospecifytheactualconcretetypeyourequireif therearemultipleregistrationsforaninterfaceorabaseclass,andyoucanspecifythelifetimeofthe objectitcreatesaswellaspassinganyvaluesyourequiretotheparametersofthetargetobject

AGuidetoDevelopingwithEnterpriseLibrary5.0

22

constructor.Asanexample,thefollowingcoderesolvesaCacheManagerinstancenamedIsoStore.You canseethatthesyntaxissimilartothatoftheGetInstancemethoddiscussedearlierinthischapter.
//ResolvetheCacheManagerobjectnamedIsoStoragefromthecontainer. varcacheMgr=container.Resolve<ICacheManager>("IsoStore");

However,thisapproachoffersonlylimitedadvantagesovertheGetInstancemethodapproach,andyou willprobablyuseitmainlyifyoudecidetoregistercustommappingsinthecontainerandresolve objectsthathaveanonstandardlifetime(suchasasingletonorperthreadlifetime).Tolearnmore aboutusingthecontainerinthisway,seethedocumentationforUnityortherelatedguide"Whatever theunityguideiscalled". InjectingInstancesofObjects WherethecontainerismostusefuliswhenyouapplyDItechniquesbydefiningdependenciesinyour classesandthenhavingUnityinjectinstancesofobjectswhenthatclassininstantiated.Youcandefine dependenciesinthreeways: Asoneormoreparametersofaconstructorinthetargetclass.Unitywillcreateinstancesof theappropriatetypesandpopulatetheconstructorparameterswhenthetargetobjectis instantiated.Thisistheapproachyouwilltypicallyuse.Forexample,youcanhaveUnity automaticallycreateandpassintoyourconstructoraninstanceofaLogWriteroran ExceptionManager,storethereferenceinaclassvariableorfield,anduseitwithinthatclass. Asoneormorepropertiesofthetargetclass,witheachofthesepropertiescarryinga DependencyattributethatindicatestoUnitythatitmustcreateaninstanceofthetypedefined bytheproperty,andsetthatinstanceasthevalueoftheproperty,whentheclassisresolved throughthecontainer. Asoneormoreparametersofamethodinthetargetclass.Unitywillcreateinstancesofthe appropriatetypesandpopulatethemethodparameterswhenthetargetobjectisinstantiated, thencallthatmethod.YoumustapplytheInjectionMethodattributetoanymethodsthat requireinjection,andyoucanstorethereferencespassedintheparametersinaclassvariable orfieldforuseitwithinthatclass.ThisapproachistypicallyusedwhenyouhaveanInitializeor similarmethodthatshouldexecutewhentheclassisinstantiated.

AsUnitycreateseachobject,itinspectsitfordependenciesandautomaticallypopulatesthese.So,for example,ifyouspecifyaparameterfortheconstructororadependentpropertyofacustomclasstobe oftypeMyBusinessComponent,UnitywillcreateaninstanceofMyBusinessComponentandpopulate theconstructororproperty.However,ifMyBusinessComponentdefinesadependencyonanotherclass namedMyDataComponent,Unitywillcreateandinstanceofthatclassandpopulatethatdependency, andsoon.Ifthereisnomappinginthecontainerforthetypespecifiedintheparameterorproperty, Unitysimplycreatesanewinstanceofthespecifiedtypeandreturnsit. PerhapsMyDataComponentrequiresanEnterpriseLibraryLogWritertocreatelogmessages?Ifit containsadependentparameterorpropertyoftypeLogWriter,Unitywillpopulatethataspartofthe AGuidetoDevelopingwithEnterpriseLibrary5.0 23

instantiationprocessaswell.Thiscanapplyrightacrossthedefineddependenciesinyourapplication,as shownintheschematicbelow.

SoyoucanseefromthishoweasyitistousetheDIapproachtopopulateallofyourdependencieson EnterpriseLibraryobjectsandyourowncustomobjectswithoutneedingtocreateinstancesdirectlyin yourcode.And,ashintedatearlier,youcanevenuseUnitytocreateaninstanceofyourmainformor startupclass.Providingthatyouspecifyallthedependenciesrequiredinyourapplicationthough constructorandmethodparametersanddependentproperties,youcansimplyresolvethestartupclass usingcode.Forexample,intheMainroutineofaWindowsFormsapplicationthatusesamainform namedMyForm,youcanusecodesuchasthefollowingtopopulatealloftheapplicationdependencies atstartup.


varcontainer=newUnityContainer() .AddNewExtension<EnterpriseLibraryCoreExtension>(); Application.Run(container.Resolve<MyForm>());

ThefollowingschematicattemptstoshowsidebysidetheoverallprocessforformsbasedandWeb basedapplicationtypesthatthesimpletwolinesofcodeshownabovecanaccomplish.Youcan comparethesimilaritiesanddifferencesbetweenthetwotypesoftechnology.Thedocumentationfor EnterpriseLibrarydescribessomeadvancedapproachesforstoringareferencetothecontainerat runtimeinWebbasedapplicationsandservices.Youcanseethat,otherthatdefiningthedependencies inyourclasses,EnterpriseLibrarysavesyouaconsiderableamountofeffort!

AGuidetoDevelopingwithEnterpriseLibrary5.0

24

Thisapproachtoresolvingandpopulatingindividualclassdependencies,orevenpopulatingtheentire hierarchyofobjectsusedinyourapplicationbasedontyperegistrationsandmappingsdefinedinthe container,providesseveraladvantages.Theseinclude: Reducingcouplingbetweenclasses.Dependenciesareclearlydefinedineachclass,andthe mappingsbetweeninterfacesandbaseclasses,andtheactualconcretetypes,arestoredinthe containerandcanbeupdatedasrequiredwithoutrequiringanychangestothecode. Makingyourcodemorediscoverable.Youcaneasilytellfromthetypesoftheconstructors, properties,ormethodsofyourclasseswhatobjectstheyuseandwhatdependenciestheyhave.

AGuidetoDevelopingwithEnterpriseLibrary5.0

25

Ifyouresolveinstancesusingcodeinsidetheclassesinstead,itismoredifficulttotrace dependencies. Makingtestingeasier.Ifyouresolveobjectsusingcodewithinyourclasses,youmustprovidea suitablyconfiguredcontainerforusewhenunittestingtheseclasses.Ifyoutakeadvantageof constructor,property,andmethodcallinjection,youcancreatesimplemocktestobjectsfor yourclassestouse. Removingtherequirementtomaintainareferencetothecontainer.Ifyoupopulateallofyour dependenciesatapplicationstartuporinitialization,youdonothavetomaintainaglobal referencetothecontainerorpassreferencestoitbetweenobjects.

Thefollowingsectionsdescribethebasictechniquesfordefiningdependenciesinyourclasses. ConstructorInjection Forconstructorinjection,yousimplydefinetherequiredtypesintheparametersasshownhere.


publicclassMyNewObject { publicMyNewObject(DatabasedefaultDB) { //codetousetheresolvedDatabaseinstancehere } }

Whenyouspecifyjustthetypeinaconstructorparameter,asabove,thecontainerwillreturnthe defaultconcreteimplementationofthattypeasdefinedintheEnterpriseLibraryconfiguration.To specifyanamedregistrationwhenusingconstructorinjection,youaddtheDependencyattributetothe parameterdefinitionasshownbelow.


publicclassMyNewObject { publicMyNewObject([Dependency("CustomerDB")]Databasecustomers) { //codetousetheresolvedDatabaseinstancehere } }

Ifthetargetclasscontainsmorethanoneconstructor,Unitywillchoosetheonewiththehighest numberofparameters.However,youcanspecifywhichconstructoritshouldusebyapplyingthe InjectionConstructorattributetoitifyouwish. Property(Setter)Injection Property(setter)injectioncanpopulateoneormorepropertiesofyourcustomclassesatruntime.To specifyinjectionforaproperty,youapplytheDependencyattributetoittoindicatethatthetype definedandexposedbythepropertyisadependencyoftheclass.Thefollowingcodedemonstrates

AGuidetoDevelopingwithEnterpriseLibrary5.0

26

propertyinjectionforaclassnamedMyNewObjectthatexposesasapropertyareferencetoan instanceoftheEnterpriseLibraryCacheManagerclass.
publicclassMyNewObject { [Dependency] publicCacheManagerDefaultCache{get;set;} }

WhenyouapplytheDependencyattributewithoutspecifyinganame,thecontainerwillreturnthe defaultconcreteimplementationofthattypeasdefinedintheEnterpriseLibraryconfiguration.To specifyanamedregistrationwhenusingpropertyinjection,youincludethenameasaparameterofthe Dependencyattributeasshownbelow.


publicclassMyNewObject { [Dependency("LocalCache")] publicCacheManagerNamedCache{get;set;} }

MethodCallInjection Methodcallinjectionisalesscommonapproachthanconstructorandpropertysetterinjection,butis usefulintwospecificsituations.Constructorinjectiononlyworkswhenyouareinstantiatingnew instancesofobjects(whentheconstructorisexecuted),whereasmethodcallinjectionwillworkwith existinginstancesofobjects.Forexample,Unitywillexecutethemethodwhenitresolvesaninstance thatisregisteredasasingleton.Andwhilepropertysetterinjectionalsoworkswithexistinginstances,it requirespublicpropertiestobeexposed. Theusualapproachistoexposeapublicinitializationmethodthattakesasparameterstheobjectsyou wanttoresolveandobtainreferencesto.Unitywillpopulatetheparametersandthencallthemethod. Asthemethodexecutes,youstoretheresolvedtypesinlocalvariablesofyourclass.Youapplythe InjectionMethodattributetothemethodtoindicatethatanytypesdefinedinparametersofthe methodaredependenciesoftheclass. Thefollowingcodedemonstratesthemostcommonscenario,savingthedependentobjectinstanceina classlevelvariable,foraclassnamedMyNewObjectthatexposesamethodnamedInitializethattakes asparametersinstancesoftheEnterpriseLibraryCacheManagerandCryptographyManagerobjects.
publicclassMyNewObject { privateCacheManagermyCache; privateCryptographyManagermyCrypto; [InjectionMethod] publicvoidInitialize(CacheManagercache,CryptographyManager,crypto) { //assignthedependentobjectstoclasslevelvariables myCache=cache;

AGuidetoDevelopingwithEnterpriseLibrary5.0

27

myCrypto=crypto; } }

1.8

TheExampleApplications

TohelpyouunderstandhowyoucanuseEnterpriseLibraryandeachofthesevenapplicationblocks coveredinthisguide,weprovideaseriesofsimpleexampleapplicationsthatyoucanrunandexamine. EachisaConsolebasedapplicationwith,inmostcases,alloftherelevantcodethatusesEnterprise LibrarywithinaseriesofroutinesintheProgram.csorProgram.vbfile.Thismakesiteasytoseehowthe differentblockswork,andwhatyoucanachievewitheachone. TheexamplesusethesimplestapproachtocreatingtheEnterpriseobjectstheyuse(theGetInstance methoddescribedearlierinthechapter),andhavetheconfigurationinformationfortheblockstheyuse storedintheApp.configfile.Eachoftheoptionsintheexamplesexercisesspecificfeaturesofthe relevantblock,anddisplaystheresults.YoucanopenthesolutionsfortheseexamplesinVisualStudio, orjustruntheexecutablefileinthebin\debugfolderandviewthesourcefilesinatexteditorifyou prefer. Toobtaintheexampleapplications,goto[linktoexamplesdownload].

1.9

Summary

ThisbriefintroductiontoEnterpriseLibrarywillhelpyoutogetstartedifyouarenotfamiliarwithits capabilitiesandthebasicsofusingitinapplications.ThischapterdescribedwhatEnterpriseLibraryis, whereyoucangetit,andwhatitcandoforyouintermsofmakingitmucheasiertomanageyour crosscuttingconcerns.ThisbookconcentratesontheapplicationblocksinEnterpriseLibrarythat"do stuff"(asopposedtothosethat"wireupstuff").Theblocksweconcentrateoninthisbookinclude Caching,Cryptography,DataAccess,ExceptionHandling,Logging,Security,andValidation. ThischapteralsoaimstohelpyougetstartedwithEnterpriseLibrarybyexplaininghowyoudeployand referencetheassembliesincontains,howyouconfigureyourapplicationstouseEnterpriseLibrary,how youinstantiateEnterpriseLibraryobjects,andtheexampleapplicationsweprovide.Someofthemore advancedfeaturesandconfigurationoptionsareomittedsothatyoucanconcentrateonthe fundamentalrequirements.However,EnterpriseLibrarycontainssubstantialreferencedocumentation, samples,andotherresourcesthatwillguideyouasyouexplorethesemoreadvancedfeatures.

AGuidetoDevelopingwithEnterpriseLibrary5.0

28

Chapter2 Access
Contents

MuchADOAboutData

Introduction..........................................................................................................................................30 WhatDoestheDataAccessBlockDo?................................................................................................. 30 DataOperationsSupportedbytheDataAccessBlock..................................................................... 31 HowDoIUsetheDataAccessBlock?................................................................................................... 33 ConfiguringtheBlockandReferencingtheRequiredAssemblies....................................................33 CreatingDatabaseInstances............................................................................................................. 33 TheExampleApplication.................................................................................................................. 34 ReadingMultipleDataRows............................................................................................................. 35 ReadingRowsUsingaQuerywithNoParameters..................................................................35 ReadingRowsUsinganArrayofParameterValues .................................................................36 ReadingRowsUsingQuerieswithNamedParameters...........................................................37 RetrievingDataasObjects................................................................................................................ 39 AboutAccessors....................................................................................................................... 39 CreatingandExecutinganAccessor........................................................................................ 40 CreatingandUsingMappers.................................................................................................... 41 RetrievingXMLData......................................................................................................................... 42 RetrievingSingleScalarValues......................................................................................................... 43 RetrievingDataAsynchronously....................................................................................................... 44 PreparingforAsynchronousDataAccess................................................................................ 45 RetrievingRowSetDataAsynchronously................................................................................ 46 RetrievingDataasObjectsAsynchronously ............................................................................. 48 UpdatingData...................................................................................................................................50 ExecutinganUpdateQuery..................................................................................................... 50 WorkingwithDataSets ............................................................................................................. 52 UpdatingtheDatabasefromaDataSet................................................................................... 52 ManagingConnections..................................................................................................................... 55 AGuidetoDevelopingwithEnterpriseLibrary5.0 29

WorkingwithConnectionBasedTransactions................................................................................. 57 WorkingwithDistributedTransactions............................................................................................ 58 ExtendingtheBlocktoUseOtherDatabases....................................................................................... 61 Summary...............................................................................................................................................61

2.1

Introduction

Whendidyoulastwriteanenterpriselevelapplicationwhereyoudidn'tneedtohandledata?And there'sagoodchancethatthisdatacamefromsomekindofrelationaldatabase.Workingwith databasesisthesinglemostcommontaskmostenterpriseapplicationsneedtoaccomplish,andsoit's nosurprisethattheDataAccessApplicationBlockisthemostwidelyusedofalloftheEnterpriseLibrary blocksandnocoincidencethatwedecidedtocoveritinthefirstoftheapplicationblockchaptersin thisbook. AgreatmanyofthemillionsofEnterpriseLibraryusersaroundtheworldfirstcuttheirteethonthe DataAccessblock.Why?Becauseitmakesiteasytoimplementthemostcommonlyuseddataaccess operationswithoutneedingtowritethesamerepetitivecodeoverandoveragain,andwithouthaving toworryaboutwhichdatabasetheapplicationwilltarget.AslongasthereisaDataAccessblock provideravailableforyourtargetdatabase,youcanusethesamecodetoaccessthedata.Youdont needtoworryaboutthesyntaxforparameters,theidiosyncrasiesoftheindividualdataaccess methods,andthedifferentdatatypesthatarereturned. Thismeansthatit'salsoeasytoswitchyourapplicationtouseadifferentdatabase,withouthavingto rewritecode,recompile,andredeploy.Administratorsandoperatorscanchangethetargetdatabaseto adifferentserver;andeventoadifferentdatabase(suchasmovingfromOracletoSQLServerorthe reverse),withoutaffectingtheapplicationcode.Inthecurrentrelease,theDataAccessblockcontains providersforSQLServer,SQLServerCompactEdition,andOracledatabases.Therearealsothirdparty providersavailablefortheIBMDB2,MySql,ODP.NET,andSQLitedatabases.Formoreinformationon these,seehttp://codeplex.com/entlibcontrib.

2.2

WhatDoestheDataAccessBlockDo?

TheDataAccessApplicationBlockabstractstheactualdatabaseyouareusing,andexposesaseriesof methodsthatmakeiteasytoaccessthatdatabasetoperformcommontasks.Forexample,tofilla DataSetyousimplycreateaninstanceoftheappropriateDatabaseclass,useittogetanappropriate Commandinstance,andpassthistotheExecuteDataSetmethodoftheDatabaseclass.Youdon'tneed tocreateaDataAdapterorcalltheFillmethod.TheExecuteDataSetmethodmanagestheconnection, andcarriesoutallthetasksrequiredtopopulateyourDataSet.Inasimilarway,theDatabaseclass allowsyoutoobtainaDataReader,executecommandsdirectly,andupdatethedatabasefroma

AGuidetoDevelopingwithEnterpriseLibrary5.0

30

DataSet.Theblockalsosupportstransactionstohelpyoumanagemultipleoperationsthatcanberolled backifanerroroccurs. InadditiontothemorecommonapproachesfamiliartousersofADO.NET,theDataAccessblockalso providestechniquesforasynchronousdataaccessfordatabasesthatsupportthisfeature,andthe abilitytoreturndataasasequenceofobjectssuitableforclientsidequeryingusingtechniquessuchas LanguageIntegratedQuery(LINQ).However,theblockisnotintendedtobeanObject/Relational Mapping(O/RM)solution.Itusesmappingstorelateparametersandrelationaldatawiththeproperties ofobjects,butdoesnotimplementanO/RMmodelingsolution. ThemajoradvantagewithusingtheDataAccessblock,besidesthesimplicityachievedthroughthe encapsulationofthe"boilerplate"codethatyouwouldotherwiseneedtowrite,isthatitprovidesaway tocreateproviderindependentapplicationsthatcaneasilybemovedtouseadifferentsourcedatabase type.Inmostcases,unlessyourcodetakesadvantageofmethodsspecifictoaparticulardatabase,the onlychangerequiredistoupdatethecontentsofyourconfigurationfilewiththeappropriate connectionstring.Youdonthavetochangethewaythatyouspecifyqueries(suchasSQLstatementsor storedprocedurenames),createandpopulateparameters,orhandlereturnvalues. Thismeansthatadministratorsandoperatorscanredeployyourapplicationwithoutdraggingyouaway fromthenewandexcitingprojectyouareworkingon(or,evenworse,backfromthatexoticforeign beachwhereyouareenjoyingawellearnedholiday)justtoupdatesomedataaccesscallsinyour application.Italsomeansreducedrequirementsfortesting,andtheconfigurationchangescanevenbe accomplishedthroughGroupPolicyandWindowsManagementInstrumentation(WMI)2.0tools.

2.2.1 DataOperationsSupportedbytheDataAccessBlock
ThefollowingtablelistsbytaskthemostcommonlyusedmethodsthattheDataAccessblockexposes toretrieveandupdatedata.SomeofthemethodnameswillbefamiliartothoseusedtousingADO.NET directly.
Task Filling a DataSet and updating the database from a DataSet. Methods ExecuteDataSet. Creates, populates, and returns a DataSet. LoadDataSet. Populates and existing DataSet. UpdateDataSet. Updates the database using an existing DataSet. Reading multiple data rows. ExecuteReader. Creates and returns a provider-independent DbDataReader instance ExecuteNonQuery. Executes the command and returns the number of rows affected. Other return values (if any) appear as output parameters. ExecuteScalar. Executes the command and returns a single value. Retrieving data as a sequence of objects. ExecuteSprocAccessor. Returns data selected by a stored procedure as a sequence of objects for client-side querying. ExecuteSqlStringAccessor. Returns data selected by a SQL statement as a sequence of objects for client-side querying.

Executing a Command.

AGuidetoDevelopingwithEnterpriseLibrary5.0

31

Retrieving XML data (SQL Server only).

ExecuteXmlReader. Returns data as a series of XML elements exposed through and XmlReader. Note that this is a method is specific to the SqlDatabase class (not the underlying Database class). GetStoredProcCommand. Returns a Command object suitable for executing a stored procedure. GetSqlStringCommand. Returns a Command object suitable for executing a SQL statement (which may contain parameters).

Creating a Command.

Working with Command parameters.

AddInParameter. Creates a new input parameter and adds it to the parameter collection of a Command. AddOutParameter. Creates a new output parameter and adds it to the parameter collection of a Command. AddParameter. Creates a new parameter of the specific type and direction and adds it to the parameter collection of a Command. GetParameterValue. Returns the value of the specified parameter as an Object type. SetParameterValue. Sets the value of the specified parameter.

Working with transactions.

CreateConnection. Creates and returns a connection for the current database that allows you to initiate and manage a transaction over the connection.

YoucanseefromthistablethattheDataAccessblocksupportsalmostallofthecommonscenariosthat youwillencounterwhenworkingwithrelationaldatabases.Eachdataaccessmethodalsohasmultiple overloads,designedtosimplifyusageandintegratewhennecessarywithexistingdatatransactions. Ingeneral,youshouldchoosetheoverloadyouusebasedonthefollowingguidelines: OverloadsthatacceptanADO.NETDbCommandobjectprovidethemostflexibilityandcontrol foreachmethod. Overloadsthatacceptastoredprocedurenameandacollectionofvaluestobeusedas parametervaluesforthestoredprocedureareconvenientwhenyourapplicationcallsstored proceduresthathaveinputonlyparameters. OverloadsthatacceptaCommandTypevalueandastringthatrepresentsthecommandare convenientwhenyourapplicationexecutesinlineSQLstatements,orstoredproceduresthat requirenoparameters. Overloadsthatacceptatransactionallowexecutethemethodwithinanexistingtransaction. IfyouusetheSqlDatabasetype,youcanexecuteseveralofthecommonmethods asynchronouslybyusingtheBeginandEndversionsofthemethods. YoucanusetheDatabaseclasstocreateAccessorinstancesthatexecutedataaccess operationsbothsynchronouslyandasynchronously,andreturntheresultsasaseriesofobjects suitableforclientsidequeryingusingtechnologiessuchasLINQ.

AGuidetoDevelopingwithEnterpriseLibrary5.0

32

2.3

HowDoIUsetheDataAccessBlock?

BeforeyoustarttousetheDataAccessblock,youmustaddittoyourapplication.Youconfigurethe blocktospecifythedatabasesyouwanttoworkwith,andaddtherelevantassembliestoyourproject. Thenyoucancreateinstancesofthesedatabasesinyourcodeandusethemtoreadandwritedata.

2.3.1 ConfiguringtheBlockandReferencingtheRequiredAssemblies
ThefirststepinusingtheDataAccessblockistoconfigurethedatabasesyouwanttoaccess.Theblock makesuseofthestandard<connectionStrings>sectionoftheApp.configorWeb.configfiletostorethe individualdatabaseconnectionstrings,withtheadditionofasmallEnterpriseLibraryspecificsection thatdefineswhichoftheconfigureddatabasesisthedefault.Youcanconfigureallofthesesettings usingtheEnterpriseLibraryconfigurationconsole,asshowninthefollowingscreenshot. [Awaitingnewimage] Afteryouconfigurethedatabasesyouneed,youmustinstantiatetheminyourapplicationcode.Add referencestotheassembliesyouwillrequire,andusingstatementstoyourcodeforthenamespaces containingtheobjectsyouwilluse.InadditiontotheEnterpriseLibraryassembliesyourequireinevery EnterpriseLibraryproject(listedinChapter1),youmustreferenceoraddtoyourbinfolderthe assemblyMicrosoft.Practices.EnterpriseLibrary.Data.dll.IfyouareworkingwithaSQLServerCompact Editiondatabase,youmustalsoreferenceoraddtheassembly Microsoft.Practices.EnterpriseLibrary.Data.SqlCe.dll.IfyouareworkingwithanOracledatabase,you canusetheOracleproviderincludedwithEnterpriseLibraryandtheADO.NETOracleprovider,which requiresyoutoreferenceoraddtheassemblySystem.Data.OracleClient.dll.However,keepinmind thattheOracleClientproviderisdeprecatedinversion4.0ofthe.NETFramework,althoughitisstill supportedbytheEnterpriseLibrary.Forthefuturedevelopment,considerchoosingadifferentOracle driversuchasthatavailablefromtheEnterpriseLibraryContribsiteat http://codeplex.com/entlibcontrib.

2.3.2 CreatingDatabaseInstances
YoucanuseavarietyoftechniquestoobtainaDatabaseinstanceforthedatabaseyouwanttoaccess. Thesection"InstantiatingEnterpriseLibraryObjects"inChapter1describesthedifferentapproaches youcanuse.Theexamplesyoucandownloadforthischapterusethesimplestapproach:callingthe GetInstancemethodoftheEnterpriseLibraryContainerthroughitsstaticCurrentproperty,asshown here,andstoringtheminapplicationwidevariablessothattheycanbeaccessedfromanywhereinthe code.
staticDatabasedefaultDB=null; staticDatabasenamedDB=null; //ResolvethedefaultDatabaseobjectfromthecontainer.

AGuidetoDevelopingwithEnterpriseLibrary5.0

33

//Theactualconcretetypeisdeterminedbytheconfigurationsettings. defaultDB=EnterpriseLibraryContainer.Current.GetInstance<Database>(); //ResolveaDatabaseobjectfromthecontainerusingtheconnectionstringname. namedDB =EnterpriseLibraryContainer.Current.GetInstance<Database>("ExampleDatabase");

Thecodeaboveshowshowyoucangetaninstanceofthedefaultdatabaseandanamedinstance(using thenameintheconnectionstringssection).Usingthedefaultdatabaseisausefulapproachbecause youcanchangewhichofthedatabasesdefinedinyourconfigurationisthedefaultsimplybyeditingthe configurationfile,withoutrequiringrecompilationorredeploymentoftheapplication. NoticethatthecodeabovereferencesthedatabaseinstancesasinstancesoftheDatabasebaseclass. Thisisrequiredforcompatibilityofyouwanttobeabletochangethedatabasetypeatsomelater stage.However,itmeansthatyoucanonlyusethefeaturesavailableacrossallofthepossibledatabase types(themethodsandpropertiesdefinedintheDatabaseclass). Somefeaturesareonlyavailableintheconcretetypesforspecificdatabase.Forexample,the ExecuteXmlReadermethodisonlyavailableintheSqlDatabaseclass.Ifyouwanttousesuchfeatures, youmustcastthedatabasetypeyouinstantiatetotheappropriateconcretetype.Thefollowingcode createsaninstanceoftheSqlDatabaseclass.
staticSqlDatabasesqlServerDB=null; //ResolveaSqlDatabaseobjectfromthecontainerusingthedefaultdatabase. sqlServerDB=EnterpriseLibraryContainer.Current.GetInstance<Database>() asSqlDatabase;

Inadditiontousingconfigurationtodefinethedatabasesyouwilluse,theDataAccessblockallowsyou tocreateinstancesofconcretetypesthatinheritfromtheDatabaseclassdirectlyinyourcode,as shownhere.AllyouneeddoisprovideaconnectionstringthatspecifiestheappropriateADO.NETdata providertype(suchasSqlClient).


//AssumethemethodGetConnectionStringexistsinyourapplicationand //returnsavalidconnectionstring. stringmyConnectionString=GetConnectionString(); SqlDatabasesqlDatabase=newSqlDatabase(myConnectionString);

2.3.3 TheExampleApplication
NowthatyouhaveyournewDatabaseobjectsreadytogo,we'llshowyouhowyoucanuseitto performavarietyoftasks.Youcandownloadanexampleapplication(asimpleConsolebased application)thatdemonstratesallofthescenariosyouwillseeintheremainderofthischapter.Youcan runthisdirectlyfromthebin\debugfolder,oropenthesolutionnamedDataAccessinVisualStudioto seeallofthecodeasyouruntheexamples.

AGuidetoDevelopingwithEnterpriseLibrary5.0

34

2.3.4 ReadingMultipleDataRows
Oneofthemostcommonoperationswhenworkingwithadatabaseisreadingmultiplerowsofdata.In a.NETapplication,youusuallyaccesstheserowsasaDataReaderinstance,orstorethemina DataTable(usuallywithinaDataSetyoucreate).Inthissectionwe'lllookattheuseofthe ExecuteReadermethodthatreturnsaDataReader.YouwillseehowtouseaDataSetwiththeData Accessblockmethodslaterinthischapter. ReadingRowsUsingaQuerywithNoParameters SimplequeriesconsistingofaninlineSQLstatementorastoredprocedure,whichtakenoparameters, canbeexecutedusingtheExecuteReadermethodoverloadthatacceptsaCommandTypevalueanda SQLstatementorstoresprocedurenameasastring. Thefollowingcodeshowsthesimplestapproachforastoredprocedure,whereyoucanalsoomitthe CommandTypeparameter.ThedefaultisCommandType.StoredProcedure(unlikeADO.NET,wherethe defaultisCommandType.Text.
//CalltheExecuteReadermethodbyspecifyingjustthestoredprocedurename. using(IDataReaderreader=namedDB.ExecuteReader("MyStoredProcName")) { //Usethevaluesintherowsasrequired. }

TouseaninlineSQLstatement,youmustspecifytheappropriateCommandTypevalue,asshownhere.
//CalltheExecuteReadermethodbyspecifyingthecommandtype //asaSQLstatement,andpassingintheSQLstatement. using(IDataReaderreader=namedDB.ExecuteReader(CommandType.Text, "SELECTTOP1*FROMOrderList")) { //Usethevaluesintherowsasrequiredherewearejustdisplayingthem. DisplayRowValues(reader); }

Theexamplenamed"ReturnrowsusingaSQLstatementwithnoparameters"usesthiscodetoretrieve aDataReadercontainingthefirstorderinthesampledatabase,andthendisplaysthevaluesinthis singlerow.Itusesasimpleauxiliaryroutinethatiteratesthroughalltherowsandcolumns,writingthe valuestotheconsolescreen.


privatestaticvoidDisplayRowValues(IDataReaderreader) { while(reader.Read()) { for(inti=0;i<reader.FieldCount;i++) { Console.WriteLine("{0}={1}",reader.GetName(i),reader[i].ToString()); } Console.WriteLine(); }

AGuidetoDevelopingwithEnterpriseLibrary5.0

35

TheresultisalistofthecolumnsandtheirvaluesintheDataReader,asshownhere.
Id=1 Status=DRAFT CreatedOn=01/02/200911:12:06 Name=AdjustableRace LastName=Abbas FirstName=Syed ShipStreet=123ElmStreet ShipCity=Denver ShipZipCode=12345 ShippingOption=Twodayshipping State=Colorado

ReadingRowsUsinganArrayofParameterValues WhileyoumayusesimplenoparameterstoredproceduresandSQLstatementsinsomescenarios,it's farmorecommontousequeriesthatacceptinputparametersthatselectrowsorspecifyhowthequery willexecutewithinthedatabaseserver.Ifyouuseonlyinputparameters,youcanwrapthevaluesupas anObjectarrayandpassthemtothestoredprocedureorSQLstatement.Notethatthismeansyou mustaddthemtothearrayinthesameorderastheyareexpectedbythequery,becauseyouarenot usingnamesfortheseparametersyouareonlysupplyingtheactualvalues.Thefollowingcodeshows howyoucanexecuteastoredprocedurethattakesasinglestringparameter.


//CalltheExecuteReadermethodwiththestoredprocedure //nameandanObjectarraycontainingtheparametervalues. using(IDataReaderreader=defaultDB.ExecuteReader("ListOrdersByState", newobject[]{"Colorado"})) { //Usethevaluesintherowsasrequiredherewearejustdisplayingthem. DisplayRowValues(reader); }

Theexamplenamed"Returnrowsusingastoredprocedurewithparameters"usesthiscodetoquery thesampledatabase,andgeneratesthefollowingoutput.
Id=1 Status=DRAFT CreatedOn=01/02/200911:12:06 Name=AdjustableRace LastName=Abbas FirstName=Syed ShipStreet=123ElmStreet ShipCity=Denver ShipZipCode=12345 ShippingOption=Twodayshipping State=Colorado

AGuidetoDevelopingwithEnterpriseLibrary5.0

36

Id=2 Status=DRAFT CreatedOn=03/02/200901:12:06 Name=AllPurposeBikeStand LastName=Abel FirstName=Catherine ShipStreet=321CedarCourt ShipCity=Denver ShipZipCode=12345 ShippingOption=Onedayshipping State=Colorado

ReadingRowsUsingQuerieswithNamedParameters Thetechniqueinthepreviousexampleofsupplyingjustanarrayofparametervaluesiseasyand efficient,buthassomelimitations.Itdoesnotallowyoutospecifythedirection(suchasinputor output),orthedatatypewhichmaybeanissueifthedatatypeofaparameterdoesnotexactlymatch (orcannotbeimplicitlyconvertedinto)thecorrecttypediscoveredforastoredprocedure.Ifyoucreate anarrayofparametersforyourquery,youcanspecifymoredetailsaboutthetypesoftheparameters, andthewaytheyshouldbeused. Inaddition,somedatabasesystemsallocateparametersusedinSQLstatementsorstoredprocedures simplybyposition.However,manydatabasesystems,suchasMicrosoftSQLServer,allowyoutouse namedparameters.Thedatabasematchesthenamesoftheparameterssentwiththecommandtothe namesoftheparametersdefinedintheSQLstatementorstoredprocedure.Thismeansthatyouare notconfinedtoaddingparameterstoyourcommandinaspecificorder.However,beawarethatifyou usenamedparametersandthenchangethedatabasetypetoonethatdoesnotsupportnamed parametersanyparametersthataresuppliedoutoforderwillprobablycauseerrors(whichmaybe difficulttodetectifalloftheparametersareofthesamedatatype!). Toworkwithnamedparametersorparametersofdefinedtypes,youmustaccesstheCommandobject thatwillbeusedtoexecutethequery,andmanipulateitscollectionorparameters.TheDataAccess blockmakesiteasytocreateandaccesstheCommandobjectbyusingtwomethodsoftheDatabase class:GetSqlStringCommandandGetStoredProcCommand.Thesemethodsreturnaninstanceofthe appropriatecommandclassfortheconfigureddatabaseasaproviderindependentDbCommandtype reference. Afteryoucreatetheappropriatetypeofcommand,youcanusethemanyvariationsoftheDatabase methodstomanipulatethecollectionofparameters.Youcanaddparameterswithaspecificdirection usingtheAddInParameterorAddOutParametermethod,orbyusingtheAddParametermethodand providingavaluefortheParameterDirectionparameter.Youcanchangethevalueofexisting parametersalreadyaddedtothecommandusingtheGetParameterValueandSetParameterValue methods. Thefollowingcodeshowshoweasyitistocreateacommand,addaninputparameter,andexecute bothaSQLstatementandastoredprocedure.Noticehowthecodespecifiesthecommandtowhichthe

AGuidetoDevelopingwithEnterpriseLibrary5.0

37

Databaseclassshouldaddtheparameter(therecouldbemorethanoneconnectiondefinedforthe database),thename,thedatatype,andthevalueofthenewparameter.
//ReaddatawithaSQLstatementthatacceptsoneparameter. stringsqlStatement="SELECTTOP1*FROMOrderListWHEREStateLIKE@state"; //Createasuitablecommandtypeandaddtherequiredparameter. using(DbCommandsqlCmd=defaultDB.GetSqlStringCommand(sqlStatement)) { defaultDB.AddInParameter(sqlCmd,"state",DbType.String,"NewYork"); //CalltheExecuteReadermethodwiththecommand. using(IDataReadersqlReader=namedDB.ExecuteReader(sqlCmd)) { Console.WriteLine("ResultsfromexecutingSQLstatement:"); DisplayRowValues(sqlReader); } } //Nowreadthesamedatawithastoredprocedurethatacceptsoneparameter. stringstoredProcName="ListOrdersByState"; //Createasuitablecommandtypeandaddtherequiredparameter. using(DbCommandsprocCmd=defaultDB.GetStoredProcCommand(storedProcName)) { defaultDB.AddInParameter(sprocCmd,"state",DbType.String,"NewYork"); //CalltheExecuteReadermethodwiththecommand. using(IDataReadersprocReader=namedDB.ExecuteReader(sprocCmd)) { Console.WriteLine("Resultsfromexecutingstoredprocedure:"); DisplayRowValues(sprocReader); } }

Theexamplenamed"ReturnrowsusingaSQLstatementorstoredprocedurewithnamedparameters" usesthecodeyouseeabovetoexecuteaSQLstatementandastoredprocedureagainstthesample database.Thecodeprovidesthesameparametervaluetoeach,andbothqueriesreturnthesame singlerow;asshownhere.


Id=4 Status=DRAFT CreatedOn=07/02/200905:12:06 Name=BBBallBearing LastName=Abel FirstName=Catherine ShipStreet=888MainStreet ShipCity=NewYork ShipZipCode=54321 ShippingOption=Threedayshipping State=NewYork

AGuidetoDevelopingwithEnterpriseLibrary5.0

38

2.3.5 RetrievingDataasObjects
Modernprogrammingtechniquestypicallyconcentrateon"dataasobjects".Thisapproachisusefulif youuseDataTransferObjects(DTOs)topassdataaroundyouapplicationlayers,implementadata accesslayerusingObject/RelationalMapping(O/RM)techniques,orwanttotakeadvantageofnew clientsidedataqueryingtechniquessuchasLanguageIntegratedQuery(LINQ). TheDataAccessblockcontainsfeaturesthatallowyoutoextractdatausingaSQLstatementorastored procedureasthequery,buthavethedatareturnedtoyouasasequenceofobjectsthatimplementsthe IEnumerableinterface.Thisallowsyoutoexecutequeries,orobtainlistsorarrayofobjectsthat representtheoriginaldatainthedatabase. AboutAccessors Theblockprovidestwocoreclassesforperformingthiskindofquery:theSprocAccessorandthe SqlStringAccessor.Youcancreateandexecutetheseaccessorsinoneoperationusingthe ExecuteSprocAccessorandExecuteSprocAccessormethodsoftheDatabaseclass,orcreateanew accessordirectlyandthencallitsExecutemethod. Accessorsusetwootherobjectstomanagetheparametersyouwanttopassintotheaccessor(andon tothedatabaseasitexecutesthequery),andtomapthevaluesintherowsreturnedfromthedatabase tothepropertiesoftheobjectsitwillreturntotheclientcode.Thefollowingschematicshowsthe overallprocess.

Theaccessorwillattempttoresolvetheparametersautomaticallyusingadefaultmapperifyoudonot specifyaparametermapper.However,thisfeatureisonlyavailableforstoredproceduresexecuted AGuidetoDevelopingwithEnterpriseLibrary5.0 39

againstSQLServerandOracledatabases.ItisnotavailablewhenusingSQLstatements,orforother databasesandproviders,whereyoumustspecifyacustomparametermapperthatcanresolvethe parameters. Ifyoudonotspecifyanoutputmapper,theblockusesadefaultmapbuilderclassthatmapsthecolumn namesofthereturneddatatopropertiesoftheobjectsitcreates.Alternatively,youcancreatea custommappingtospecifythecorrelationbetweencolumnsintherowsetandthepropertiesofthe objects. Tomaximizetheefficiencyofyourdataaccesscode,reuseexistinginstancesofanymappersyou create.Asthedefaultmappermustinferthetypeswhenyoucreateit,youmayprefertobuilda custommapperandretainareferencetoitforusewitheachexecutionoftheaccessor. Forafulldescriptionofthetechniquesforusingaccessors,seetheEnterpriseLibrarydocumentationon MSDNathttp://msdn.microsoft.com/entlib,orinstalledwithEnterpriseLibrary.Thischaptercoversonly thesimplestapproachusingtheExecuteSprocAccessormethodoftheDatabaseclass. CreatingandExecutinganAccessor Thefollowingcodeshowshowyoucanuseanaccessortoexecuteastoredprocedureandthen manipulatethesequenceofobjectsthatisreturned.Youmustspecifytheobjecttypethatyouwantthe datareturnedasinthisexampleitisasimpleclassnamedProductthathasthethreepropertiesID, Name,andDescription. Thestoredproceduretakesasingleparameterthatisasearchstring,andreturnsdetailsofallproducts inthedatabasethatcontainthisstring.Therefore,thecodefirstcreatesanarrayofparametervaluesto passtotheaccessor,andthencallstheExecuteSprocAccessormethod.ItspecifiestheProductclassas thetypeofobjecttoreturn,andpassestothemethodthenameofthestoredproceduretoexecuteand thearrayofparametervalues.
//Createanobjectarrayandpopulateitwiththerequiredparametervalues object[]params=newobject[]{"%bike%"}; //Createandexecuteasprocaccessorthatusesthedefault //parameterandoutputmappings. varproductData=defaultDB.ExecuteSprocAccessor<Product>("GetProductList", params); //Performaclientsidequeryonthereturneddata.Beawarethat //theorderbyandfilteringishappeningontheclient,notinthedatabase. varresults=fromproductIteminproductData whereproductItem.Description!=null orderbyproductItem.Name selectnew{productItem.Name,productItem.Description}; //Displaytheresults foreach(variteminresults) {

AGuidetoDevelopingwithEnterpriseLibrary5.0

40

Console.WriteLine("ProductName:{0}",item.Name); Console.WriteLine("Description:{0}",item.Description); Console.WriteLine(); }

TheaccessorreturnsthedataasasequencethatthecodehandlesusingaLINQquerytoremoveall itemswherethedescriptioninempty,sortsthelistbyname,andthencreatesanewsequenceof objectsthathavejusttheNameandDescriptionproperties.FormoreinformationonusingLINQto querysequences,seehttp://msdn.microsoft.com/enus/library/bb397676.aspx. Theexample"Returndataasasequenceofobjectsusingastoredprocedure"usesthecodeyousee abovetoquerythesampledatabaseandprocesstheresultingrows.Theoutputitgeneratesisshown here.


ProductName:AllPurposeBikeStand Description:Perfectallpurposebikestandforworkingonyourbikeathome.Quick adjustingclampsandsteelconstruction. ProductName:BikeWashDissolver Description:Washesoffthetoughestroadgrime;dissolvesgrease,environmentally safe.1literbottle. ProductName:HitchRack4Bike Description:Carries4bikessecurely;steelconstruction,fits2"receiverhitch.

ForanexampleofcreatinganaccessorandthencallingtheExecutemethod,seethesection"Retrieving DataasObjectsAsynchronously"laterinthischapter. CreatingandUsingMappers Insomecases,youmayneedtocreateacustomparametermappertopassyourparameterstothe querythattheaccessorwillexecute.ThistypicallyoccurswhenyouneedtoexecuteaSQLstatement, workwithadatabasesystemthatdoesnotsupportparameterresolution,orbecauseadefaultmapping cannotbeinferredduetoamismatchinthenumberortypesoftheparameters.Theparametermapper classmustimplementtheIParameterMapperinterfaceandcontainamethodnamedAssignParameters thattakesareferencetothecurrentCommandinstanceandthearrayorparameters.Themethod simplyneedstoaddtherequiredparameterstotheCommandobject'sParameterscollection. Itismorecommontoencounterthescenariowhereyouneedtocreateacustomoutputmapper.To helpyoudothis,theblockprovidesaclasscalledMapBuilderthatyoucanusetocreatethesetof mappingsyourequirebetweenthecolumnsofthedatasetreturnedbythequeryandthepropertiesof theobjectsyouneed. Bydefault,theaccessorwillexpecttogenerateasimplesequenceofasingletypeofobject(inour earlierexample,thiswasasequenceoftheProductclass).However,youcanuseanaccessortoreturna morecomplexgraphofobjectsifyouwish.Forexample,youmightexecuteaquerythatreturnsaseries ofOrderobjectsandtherelatedOrderLinesobjectsforalloftheselectedorders.Simpleoutput mappingcannotcopewiththisscenario,andneithercantheMapBuilderclass.Inthiscase,youwould AGuidetoDevelopingwithEnterpriseLibrary5.0 41

createaresultsetmapperbyimplementingtheIResultSetMapperinterface.Yourcustomrowset mappermustcontainamethodnamedMapSetthatreceivesareferencetotheDataReaderthatwill returnallofthedata,andprocessesthistocreateandreturnthesequenceofobjectsyourequire.

2.3.6 RetrievingXMLData
Someyearsago,XMLwasthecoolestnewtechnologythatwasgoingtoruletheworldandchangethe waywethinkabout"data".Insomeways,itdidthoughtheemphasisonXMLhasrecededasthe relationaldatabasemodelcontinuestobethebasisformostenterprisesystems.However,the capabilitytoretrievedatafromarelationaldatabaseasXMLisusefulinmanyscenarios,andis supportedbytheDataAccessblock. SQLServersupportsamechanismcalledSQLXMLthatallowsyoutoextractdataasaseriesofXML elements,orinarangeofXMLdocumentformats,byexecutingspeciallyformattedSQLqueries.You canusetemplatestopreciselycontroltheoutput,andhavetheserverformatthedatainalmostany wayyourequire.ForadescriptionofthecapabilitiesofSQLXML,seehttp://msdn.microsoft.com/en us/library/aa225774(SQL.80).aspx. TheDataAccessblockprovidestheExecuteXmlReadermethodforqueryingdataasXML.IttakesaSQL statementthatcontainstheFORXMLstatementandexecutesitagainstthedatabase,returningthe resultasanXmlReader.YoucaniteratethroughtheresultingXMLelementsorworkwiththeminanyof thewayssupportedbytheXMLclassesinthe.NETFramework.However,asSQLXMLislimitedto MicrosoftSQLServer(theimplementationsofthistypeofquerydifferinotherdatabasesystems),itis onlyavailablewhenyouspecificallyusetheSqlDatabaseclassratherthantheDatabaseclasswe've useduptonow. ThismeansthatyoumustcasttheEnterpriseLibraryDatabaseinstanceyouretrievefromthecontainer totheSqlDatabasetype,orspecificallycreateaninstanceoftheSqlDatabasetypeasdemonstrated earlierinthischapter.ThefollowingcodeshowshowyoucanobtainaSqlDatabaseinstance,specifya suitableSQLXMLquery,andexecuteitusingtheExecuteXmlReadermethod.
staticSqlDatabasesqlServerDB=null; //ResolveaSqlDatabaseobjectfromthecontainerusingthedefaultdatabase. sqlServerDB =EnterpriseLibraryContainer.Current.GetInstance<Database>()asSqlDatabase;

//SpecifyaSQLquerythatreturnsXMLdata stringxmlQuery="SELECT*FROMOrderListWHEREState=@stateFORXMLAUTO"; //Createasuitablecommandtypeandaddtherequiredparameter //NB:ExecuteXmlReaderisonlyavailableforSQLServerdatabases using(DbCommandxmlCmd=sqlServerDB.GetSqlStringCommand(xmlQuery)) { xmlCmd.Parameters.Add(newSqlParameter("state","Colorado")); using(XmlReaderreader=sqlServerDB.ExecuteXmlReader(xmlCmd)) {

AGuidetoDevelopingwithEnterpriseLibrary5.0

42

while(!reader.EOF)//IteratethroughtheelementsintheXmlReader { if(reader.IsStartElement()) { Console.WriteLine(reader.ReadOuterXml()); } } } }

ThecodeabovealsoshowsasimpleapproachtoextractingtheXMLdatafromtheXmlReaderreturned fromtheExecuteXmlReadermethod.Onepointtonoteisthat,bydefault,theresultinanXML fragment,andnotavalidXMLdocument.Itis,effectively,asequenceofXMLelementsthatrepresent eachrowintheresultsset.FormoreinformationaboutusinganXmlReader,see"ReadingXMLwiththe XmlReader"intheonlineMSDNdocumentationathttp://msdn.microsoft.com/en us/library/9d83k261.aspx. Theexample"ReturndataasanXMLfragmentusingaSQLServerXMLquery"usesthecodeyousee abovetoqueryaSQLServerdatabase.ItreturnstwoXMLelementsinthedefaultformatforaFORXML AUTOquery,withthevaluesofeachcolumninthedatasetrepresentedasattributes;asshownhere.


<OrderListId="1"Status="DRAFT"CreatedOn="20090201T11:12:06"Name="Adjustable Race"LastName="Abbas"FirstName="Syed"ShipStreet="123ElmStreet"ShipCity="Denver" ShipZipCode="12345"ShippingOption="Twodayshipping"State="Colorado"/> <OrderListId="2"Status="DRAFT"CreatedOn="20090203T01:12:06"Name="AllPurpose BikeStand"LastName="Abel"FirstName="Catherine"ShipStreet="321CedarCourt" ShipCity="Denver"ShipZipCode="12345"ShippingOption="Onedayshipping" State="Colorado"/>

2.3.7 RetrievingSingleScalarValues
Acommonrequirementwhenworkingwithadatabaseistoextractasinglescalarvaluebasedona querythatselectseitherasingleroworasinglevalue.Thisistypicallythecasewhenusinglookuptables orcheckingforthepresenceoraspecificentityinthedatabase.TheDataAccessblockprovidesthe ExecuteScalarmethodtohandlethisrequirement.Itexecutesthequeryyouspecify,andthenreturns thevalueofthefirstcolumnofthefirstrowoftheresultsetasanObjecttype.Thismeansthatit providesmuchbetterperformancethantheExecuteReadermethod,becausethereisnoneedtocreate aDataReaderandstreamtheresultstotheclientasarowset.Tomaximizethisefficiency,youshould aimtouseaquerythatreturnsasinglevalue,orasinglerow. TheExecuteScalarmethodhasasimilarsetofoverloadstotheExecuteReadermethodweusedearlier inthischapter.YoucanspecifyaCommandType(thedefaultisStoredProcedure)andeitheraSQL statementorastoredprocedurename.YoucanalsopassinanarrayofObjectinstancesthatrepresent theparametersforthequery.Alternatively,youcanpasstothemethodaCommandobjectthat containsanyparametersyourequire. ThefollowingcodedemonstratespassingaCommandobjecttothemethodtoexecutebothaninline SQLstatementandastoredprocedure.ItobtainsasuitableCommandinstancefromthecurrent AGuidetoDevelopingwithEnterpriseLibrary5.0 43

DatabaseinstanceusingtheGetSqlStringCommandandGetStoredProcCommandmethods.Youcan addparameterstothecommandbeforecallingtheExecuteScalarmethodifrequired.However,to demonstratethewaythemethodworks,thecodeheresimplyextractsthecompleterowset.Theresult isasingleObjectthatyoumustcasttotheappropriatetypebeforedisplayingorconsumingitinyour code.


//CreateasuitablecommandtypeforaSQLstatement //NB:Forefficiency,aimtoreturnonlyasinglevalueorasinglerow. using(DbCommandsqlCmd =defaultDB.GetSqlStringCommand("SELECT[Name]FROMStates")) { //CalltheExecuteScalarmethodofthecommand Console.WriteLine("ResultusingaSQLstatement:{0}", defaultDB.ExecuteScalar(sqlCmd).ToString()); } //Createasuitablecommandtypeforastoredprocedure //NB:Forefficiency,aimtoreturnonlyasinglevalueorasinglerow. using(DbCommandsprocCmd=defaultDB.GetStoredProcCommand("GetStatesList")) { //CalltheExecuteScalarmethodofthecommand Console.WriteLine("Resultusingastoredprocedure:{0}", defaultDB.ExecuteScalar(sprocCmd).ToString()); }

Youcanseethecodelistedaboverunningintheexample"ReturnasinglescalarvaluefromaSQL statementorstoredprocedure".Thesomewhatunexcitingresultitproducesisshownhere.
ResultusingaSQLstatement:Alabama Resultusingastoredprocedure:Alabama

2.3.8 RetrievingDataAsynchronously
HavinglookedatallofthemainwaysyoucanextractdatausingtheDataAccessblock,we'llmoveonto lookatsomemoreexcitingscenarios(althoughmanywouldperhapsfailtoconsideranythingconnected withdataaccessascapableofbeingreferredtoas"exciting"...).Databasesaregenerallynotrenowned forbeingthefastestofcomponentsinanapplicationinfactmanypeoplewilltellyouthattheyare majorbottleneckinanyenterpriseapplication.It'snotthattheyareinefficient,it'susuallybecausethey containmanymillionsofrows,andthequeriesyouneedtoexecutearerelativelycomplex.Ofcourse,it mayjustbethatthequeryisbadlywrittenandcausespoorperformance,butthat'sadifferentstory. Onewaythatapplicationscanminimizetheperformancehotfromdataaccessistoperformit asynchronously.Thismeansthattheapplicationcodecancontinuetoexecute,andtheuserinterface canremaininteractiveduringtheprocess.Asynchronousdataaccessmaynotsuiteverysituation,butit canbeextremelyuseful. Forexample,youmightbeabletoperformmultiplequeriesconcurrentlyandcombinetheresultsto createtherequireddataset.Orquerymultipledatabases,andjustusethedatafromtheonethat

AGuidetoDevelopingwithEnterpriseLibrary5.0

44

returnedtheresultsfirst(whichcanalsoprovideakindoffailoverfeature).However,keepinmindthat asynchronousdataaccesshasaneffectonconnectionanddatastreamingperformanceovera connection.Dontexpectaquerythatreturnstenrowstoshowanyimprovementusingan asynchronousapproachitismorelikelytotakelongertoreturntheresults! TheDataAccessblockprovidesasynchronousBeginandEndversionsofmanyofthestandarddata accessmethods,includingExecuteReader,ExecuteScalar,ExecuteXmlReader,andExecuteNonQuery.It alsoprovidesasynchronousBeginandEndversionsoftheExecutemethodforaccessorsthatreturn dataasasequenceofobjects.Youwillseebothofthesetechniqueshere. PreparingforAsynchronousDataAccess Beforeyoucanexecuteaqueryasynchronously,youmustspecifytheappropriatesettinginthe connectionstringforthedatabaseyouwanttouse.Bydefault,asynchronousdataaccessisdisabledfor connections,whichpreventsthemsufferingtheperformancehitassociatedwithasynchronousdata retrievalbydefault.Touseasynchronousmethodsoveraconnection,theconnectionstringmust includeAsynchronousProcessing=true(orjustasync=true),asshowninthisextractfroma <connectionStrings>sectionofaconfigurationfile.
<connectionStrings> <addname="AsyncExampleDatabase" connectionString="AsynchronousProcessing=true;DataSource=.\SQLEXPRESS; InitialCatalog="MyDatabase";IntegratedSecurity=True;" providerName="System.Data.SqlClient"/> ... </connectionStrings>

Inaddition,asynchronousprocessingintheDataAccessblockisonlyavailableforSQLServerdatabases. TheDatabaseclassincludesapropertynamedSupportsAsyncthatyoucanquerytoseeifthecurrent Databaseinstancedoes,infact,supportasynchronousoperations.Theexampleforthischapter containsasimplecheckforthisusingthefollowingcode.


privatestaticboolSupportsAsync(Databasedb) { if(db.SupportsAsync) { Console.WriteLine("Databasesupportsasynchronousoperations"); returntrue; } Console.WriteLine("Databasedoesnotsupportasynchronousoperations"); returnfalse; }

Oneotherpointtonoteisthatasynchronousdataaccessusuallyinvolvestheuseofacallbackthatruns onadifferentthreadfromthecallingcode.Thiscallbackusuallycannotdirectlyaccesstheuserinterface inaWindowsFormsorWindowsPresentationFoundation(WPF)application.Youwill,inmostcases, needtouseadelegatetocallamethodintheoriginalUIclasstoupdatethedatareturnedbythe callback. AGuidetoDevelopingwithEnterpriseLibrary5.0 45

AcommonapproachtowritingcallbackcodeinmodernapplicationsistouseLambdaexpressions ratherthanaseparatecallbackhandlerroutine. Otherpointstonoteaboutasynchronousdataaccessarethefollowing: Youcanusethestandard.NETmethodsandclassesformtheSystem.Threadingnamespace, suchaswaithandlesandmanualresetevents,tomanageasynchronousexecutionoftheData Accessblockmethods.Youcanalsocancelapendingorexecutingcommandbycallingthe Cancelmethodofthecommandyouusedtoinitiatetheoperation.Formoreinformation,see "AsynchronousCommandExecutioninADO.NET2.0"onMSDNat http://msdn.microsoft.com/enus/library/ms379553(VS.80).aspx. TheBeginExecuteReadermethoddoesnotacceptaCommandBehaviorparameter.Bydefault, themethodwillautomaticallysettheCommandBehaviorpropertyontheunderlyingreaderto CloseConnectionunlessyouspecifyatransactionwhenyoucallthemethod.Ifyoudospecifya transaction,itdoesnotsettheCommandBehaviorproperty. UsingasynchronousdataaccesswiththeMultipleActiveResultsSet(MARS)featureof ADO.NETmayproduceunexpectedbehavior,andshouldgenerallybeavoided. AsynchronousdataaccessisonlyavailableifthedatabaseisSQLServer7.0orlater.ForSQL Server7.0andSQLServer2000,thedatabaseconnectionmustuseTCP.Itcannotuseshared memory.ToensurethatTCPisusedforSQLServer7.0andSQLServer2000,uselocalhost, tcp:server_name,ortcp:ip_addressfortheservernameintheconnectionstring.

RetrievingRowSetDataAsynchronously Thefollowingcodeshowshowyoucanperformasynchronousdataaccesstoretrievearowsetfroma SQLServerdatabase.ThecodecreatesaCommandinstanceandaddstwoparameters,andthencalls theBeginExecuteReadermethodoftheDatabaseclasstostarttheprocess.Itpassestothismethoda referencetothecommandtoexecute(withitsparametersalreadyadded),aLambdaexpressionto executewhenthedataretrievalprocesscompletes,andanullvaluefortheAsyncStateparameter.


DbCommandcmd=asyncDB.GetStoredProcCommand("ListOrdersSlowly"); asyncDB.AddInParameter(cmd,"state",DbType.String,"Colorado"); asyncDB.AddInParameter(cmd,"status",DbType.String,"DRAFT"); //Executethequeryasynchronouslyspecifyingthecommandandthe //expressiontoexecutewhenthedataaccessprocesscompletes. asyncDB.BeginExecuteReader(cmd, asyncResult=> { //Lambdaexpressionexecutedwhenthedataaccesscompletes. try { using(IDataReaderreader=asyncDB.EndExecuteReader(asyncResult)) {

AGuidetoDevelopingwithEnterpriseLibrary5.0

46

Console.WriteLine(); DisplayRowValues(reader); } } catch(Exceptionex) { Console.WriteLine("Errorafterdataaccesscompleted:{0}",ex.Message); } },null);

TheLambdaexpressionthencallstheEndExecuteReadermethodtoobtaintheresultsofexecutingthe query.Atthispointyoucanconsumetherowsetinyourapplicationor,asthecodeabovedoes,just displaythevalues.Noticethatthecallbackexpressionshouldhandleanyerrorsthatmayoccurduring theasynchronousoperation. TheAsyncStateparametercanbeusedtopassstateinformationintothecallback,andisusuallyusedto passanyrequiredinformationtothecallbackroutine.Forexample,whenyouuseaseparatecallback, youwouldpassareferencetothecurrentDatabaseinstanceastheAsyncStateparametersothatthe callbackcodecancalltheEndExecuteReader(orotherappropriateEndmethod)toobtainstheresults. WhenyouuseaLambdaexpression,thecurrentDatabaseinstanceisavailablewithintheexpression and,therefore,youdonotneedtopopulatetheAsyncStateparameter. ForanexampleofhowtouseaseparatecallbackroutineinsteadofaLambdaexpressionwhen performingasynchronousdataaccess,seethedocumentationinstalledwithEnterpriseLibrary,oronline athttp://msdn.microsoft.com/entlib. Theexample"Executeacommandthatretrievesdataasynchronously"usesthecodeshownaboveto fetchtworowsfromthedatabaseanddisplaythecontents.Aswellasthecodeabove,itusesasimple routinethatdisplaysa"Waiting..."messageeverysecondasthecodeexecutes.Theresultisshown here.
Databasesupportsasynchronousoperations Waiting...Waiting...Waiting...Waiting...Waiting... Id=1 Status=DRAFT CreatedOn=01/02/200911:12:06 Name=AdjustableRace LastName=Abbas FirstName=Syed ShipStreet=123ElmStreet ShipCity=Denver ShipZipCode=12345 ShippingOption=Twodayshipping State=Colorado Id=2

AGuidetoDevelopingwithEnterpriseLibrary5.0

47

Status=DRAFT CreatedOn=03/02/200901:12:06 Name=AllPurposeBikeStand LastName=Abel FirstName=Catherine ShipStreet=321CedarCourt ShipCity=Denver ShipZipCode=12345 ShippingOption=Onedayshipping State=Colorado

Ofcourse,aswedon'thaveamultimillionrowdatabasehandytoquery,theexampleusesastored procedurethatcontainsa"WAIT"statementtosimulatealongrunningdataaccessoperation.Italso usesManualResetEventobjectstomanagethethreadssothatyoucanseetheresultsmoreclearly. OpenthesampleinVisualStudio,orviewtheProgramfile,toseethewaythisisdone. RetrievingDataasObjectsAsynchronously Asanotherexampleofasynchronousdataaccess,thefollowingcodeshowshowyoucanexecuteadata accessorasynchronouslybyusingitsBeginExecuteandEndExecutemethods.Inthiscase,youmustpass intotheBeginExecutemethodthecallbacktoexecutewhentheasynchronousdataaccessprocess completes,theAsyncState,andanarrayofObjectinstancesthatrepresenttheparameterstoapplyto thestoredprocedureorSQLstatementyouareexecuting. ThefollowingcodecreatesanObjectarraycontainingthesingleparameterrequiredbyourstored procedure,andthencreatesaninstanceofaSprocAccessorthatwillexecutetheGetProductsSlowly storedproceduretoreturnasequenceofProductinstances.ItthencallstheBeginExecutemethod, passingtoitaLambdaexpressiontoexecuteafterthedataisretrieved,areferencetotheaccessoras theAsyncState,andthearrayofparameters(youcanseetheseonthelastlineofthecodeafterthe declarationoftheLambdaexpression). C#
object[]paramArray=newobject[]{"%bike%",20}; //Createtheaccessor.Thisexampleusesthesimplestoverload. varaccessor=asyncDB.CreateSprocAccessor<Product>("GetProductsSlowly"); //Executetheaccessorasynchronouslyspecifyingthecallbackexpression, //theexistingaccessorastheAsyncState,andtheparametervaluesarray. accessor.BeginExecute( asyncResult=> {//Lambdaexpressionexecutedwhenthedataaccesscompletes. try { //AccessorisavailableviatheasyncResultparameter varacc=(IDataAccessor<Product>)asyncResult.AsyncState; //Obtaintheresultsfromtheaccessor.

AGuidetoDevelopingwithEnterpriseLibrary5.0

48

varproductData=acc.EndExecute(asyncResult); //Performaclientsidequeryonthereturneddata. //Beawarethattheorderbyandfilteringishappening //ontheclient,notinsidethedatabase. varresults=fromproductIteminproductData whereproductItem.Description!=null orderbyproductItem.Name selectnew{productItem.Name,productItem.Description}; //Displaytheresults Console.WriteLine(); foreach(variteminresults) { Console.WriteLine("ProductName:{0}",item.Name); Console.WriteLine("Description:{0}",item.Description); Console.WriteLine(); } } catch(Exceptionex) { Console.WriteLine("Errorafterdataaccesscompleted:{0}",ex.Message); } },accessor,paramArray);

TheLambdaexpressionfirstobtainsthereferencetotheaccessorthatwasexecutedfromthe AsyncState(castingittoaninstanceoftheIDataAccessorinterfacesothatthecodewillworkwithany accessorimplementation),andthencallstheEndExecutemethodtoobtainareferencetothesequence ofobjectstheaccessorretrievedfromthedatabase.ItthenperformsthesameclientsideLINQquery yousawearlierinthischapter(inthesection"CreatingandExecutinganAccessor")toobtaina sequenceofProductinstancescontainingthenameanddescriptionoftheretrievedproducts.Finally,it displaysthislist. Thefollowingshowstheresultsgeneratedbytheexample"Executeacommandthatretrievesdataas objectsasynchronously",whichusescodesimilartothatshownabove.


Databasesupportsasynchronousoperations Waiting...Waiting...Waiting...Waiting... ProductName:AllPurposeBikeStand Description:Perfectallpurposebikestandforworkingonyourbikeathome.Quick adjustingclampsandsteelconstruction. ProductName:BikeWashDissolver Description:Washesoffthetoughestroadgrime;dissolvesgrease,environmentally safe.1literbottle.

AGuidetoDevelopingwithEnterpriseLibrary5.0

49

2.3.9 UpdatingData
Sofar,we'velookedatretrievingdatafromadatabaseusingtheclassesandmethodsoftheData Accessblock.Ofcourse,whilethisistypicallythemajorfocusofmanyapplications,youwilloftenneed toupdatedatainyourdatabase.TheDataAccessblockprovidesfeaturesthatsupportdataupdates. Youcanexecuteupdatequeries(suchasINSERT,DELETE,andUPDATEstatements)directlyagainsta databaseusingtheExecuteNonQuerymethod.Inaddition,youcanusetheExecuteDataSet, LoadDataSet,andUpdateDataSetmethodstopopulateaDataSetandpushchangestotherowsback intothedatabase.We'lllookatbothoftheseapproacheshere. ExecutinganUpdateQuery TheDataAccessblockmakesiteasytoexecuteupdatequeriesagainstadatabase.By"update"queries, wemeaninlineSQLstatements,orSQLstatementswithinstoredprocedures,whichusetheUPDATE, DELETE,orINSERTkeywords.YoucanexecutethesekindsofqueriesusingtheExecuteNonQuery methodoftheDatabaseclass. LiketheExecuteReadermethodweusedearlierinthischapter,theExecuteNonQuerymethodhasa broadsetofoverloads.YoucanspecifyaCommandType(thedefaultisStoredProcedure)andeithera SQLstatementorastoredprocedurename.YoucanalsopassinanarrayofObjectinstancesthat representtheparametersforthequery.Alternatively,youcanpasstothemethodaCommandobject thatcontainsanyparametersyourequire.TherearealsoBeginandEndversionsthatallowyouto executeupdatequeriesasynchronously. Thefollowingcodefromtheexampleapplicationforthischaptershowshowyoucanusethe ExecuteNonQuerymethodtoupdatearowinatableinthedatabase.ItupdatestheDescription columnofasinglerowintheProductstable,checksthattheupdatesucceeded,andthenupdatesit againtoreturnittotheoriginalvalue(sothatyoucanruntheexampleagain!).Thefirststepistocreate thecommandandaddtherequiredparameters,asyou'veseeninearlierexamples,andthencallthe ExecuteNonQuerymethodwiththecommandasthesingleparameter.Next,thecodechangesthe valueofthecommandparameternamed"description"totheoriginalvalueinthedatabase,andthen executesthecompensatingupdate.
stringoldDescription ="Carries4bikessecurely;steelconstruction,fits2\"receiverhitch."; stringnewDescription="Bikestendtofalloffafterafewmiles."; //Createcommandtoexecutethestoredprocedureandaddtheparameters. DbCommandcmd=defaultDB.GetStoredProcCommand("UpdateProductsTable"); defaultDB.AddInParameter(cmd,"productID",DbType.Int32,84); defaultDB.AddInParameter(cmd,"description",DbType.String,newDescription); //Executethequeryandcheckifonerowwasupdated. if(defaultDB.ExecuteNonQuery(cmd)==1) { //Updatesucceeded. }

AGuidetoDevelopingwithEnterpriseLibrary5.0

50

else { Console.WriteLine("ERROR:Couldnotupdatejustonerow."); } //Changethevalueofthesecondparameter defaultDB.SetParameterValue(cmd,"description",oldDescription); //Executequeryandcheckifonerowwasupdated if(defaultDB.ExecuteNonQuery(cmd)==1) { //Updatesucceeded. } else { Console.WriteLine("ERROR:Couldnotupdatejustonerow."); }

Noticethepatternusedtoexecutethequeryandcheckthatissucceeded.TheExecuteNonQuery methodreturnsanintegervaluethatisthenumberofrowsupdated(or,tousethemoreaccurateterm, affected)bythequery.Inthisexample,wearespecifyingasinglerowasthetargetfortheupdateby selectingontheuniqueIDcolumn.Therefore,weexpectonlyonerowtobeupdatedanyothervalue meanstherewasaproblem. Ifyouareexpectingtoupdatemultiplerows,youwouldcheckforanonzeroreturnedvalue.Typically,if youneedtoensureintegrityinthedatabase,youcouldperformtheupdatewithinaconnectionbased transaction,androllitbackiftheresultwasnotwhatyouexpected.Welookathowyoucanuse transactionswiththeDataAccessblockmethodsinthesection"WorkingwithConnectionBased Transactions"laterinthischapter. Theexample"UpdatedatausingaCommandobject",whichusesthecodeyouseeabove,producesthe followingoutput.
Contentsofrowbeforeupdate: Id=84 Name=HitchRack4Bike Description=Carries4bikessecurely;steelconstruction,fits2"receiverhitch. Contentsofrowafterfirstupdate: Id=84 Name=HitchRack4Bike Description=Bikestendtofalloffafterafewmiles. Contentsofrowaftersecondupdate: Id=84 Name=HitchRack4Bike Description=Carries4bikessecurely;steelconstruction,fits2"receiverhitch.

AGuidetoDevelopingwithEnterpriseLibrary5.0

51

WorkingwithDataSets Ifyouneedtoretrievedataandstoreitinawaythatallowsyoutopushchangesbackintothedatabase, youwillusuallyuseaDataSet.TheDataAccessblocksupportssimpleoperationsona"normal"(non typed)DataSet,includingthecapabilitytofillaDataSetandthenupdatetheoriginaldatabasetable fromtheDataSet. TofillaDataSet,youusetheExecuteDataSetmethod,whichreturnsanewinstanceoftheDataSet classpopulatedwithatablecontainingthedataforeachrowsetreturnedbythequery(whichmaybea multiplestatementbatchquery).ThetablesinthisDataSetwillhavedefaultnamessuchasTable, Table1,andTable2. IfyouwanttoloaddataintoanexistingDataSet,youusetheLoadDataSetmethod.Thisallowsyouto specifythename(s)orthetargettable(s)intheDataSet,andletsyouaddadditionaltablestoanexisting DataSetorrefreshthecontentsofspecifictablesintheDataSet. Bothofthesemethods,ExecuteDataSetandLoadDataSet,haveasimilarabroadsetofoverloadstothe ExecuteReaderandothermethodsyou'veseenearliertinthischapter.YoucanspecifyaCommandType (thedefaultisStoredProcedure)andeitheraSQLstatementorastoredprocedurename.Youcanalso passinanarrayofObjectinstancesthatrepresenttheparametersforthequery.Alternatively,youcan passtothemethodaCommandobjectthatcontainsanyparametersyourequire. Forexample,thefollowingcodelinesshowhowyoucanusetheExecuteDataSetmethodwithaSQL statementorastoredprocedurewithaparameterarray;andwithacommandprepopulatedwith parameters.ThecodeassumesyouhavecreatedtheDataAccessblockDatabaseinstancenameddb.
DataSetproductDataSet; //UsingaSQLstatementandaparameterarray. productDataSet=db.ExecuteDataSet(CommandType.Text,"GetProductsByCategory", newObject[]{"%bike%"}); //Usingastoredprocedureandaparameterarray. productDataSet=db.ExecuteDataSet("GetProductsByCategory", newObject[]{"%bike%"}); //Usingastoredprocedureandanamedparameter. DbCommandcmd=db.GetStoredProcCommand("GetProductsByCategory"); db.AddInParameter(cmd,"CategoryID",DbType.Int32,7); productDataSet=db.ExecuteDataSet(cmd);

UpdatingtheDatabasefromaDataSet ToupdatedatainadatabasefromaDataSet,youusetheUpdateDataSetmethod,whichreturnsatotal countofthenumberofrowsaffectedbytheupdate,delete,andinsertoperations.Theoverloadsofthis methodallowyoutospecifythesourceDataSetcontainingtheupdatedrows,thenameofthetablein thedatabasetoupdate,andreferencestothethreeCommandinstancesthatthemethodwillexecute toperformUPDATE,DELETE,andINSERToperationsonthespecifieddatabasetable.

AGuidetoDevelopingwithEnterpriseLibrary5.0

52

Inaddition,youcanspecifyavaluefortheUpdateBehavior,whichdetermineshowthemethodwill applytheupdatestothetargettablerows.Youcanspecifyoneofthefollowingvaluesforthis parameter: Standard.IftheunderlyingADO.NETupdateprocessencountersanerror,theupdatestopsand nosubsequentupdatesareappliedtothetargettable. Continue.IftheunderlyingADO.NETupdateprocessencountersanerror,theupdatewill continueandattempttoapplyanysubsequentupdates. Transactional.IftheunderlyingADO.NETupdateprocessencountersanerror,alltheupdates madetoallrowswillberolledback.

Finally,youcanifyouwishprovideavaluefortheUpdateBatchSizeparameterofthe UpdateDataSetmethod.Thisforcesthemethodtoattempttoperformupdatesinbatchesinsteadof sendingeachonetothedatabaseindividually.Thisismoreefficient,butthereturnvalueforthe methodwillshowonlythenumberofupdatesmadeinthefinalbatch,andnotthetotalnumberforall batches. Theexamplesforthischapterincludeonenamed"FillaDataSetandupdatethesourcedata"that demonstratestheExecuteDataSetandUpdateDataSetmethods.Itusesthesimpleoverloadsofthe ExecuteDataSetandLoadDataSetmethodstofilltwoDataSetinstances,usingaseparateroutine namedDisplayTableNames(notshownhere)todisplaythetablenamesandacountofthenumberof rowsinthesetables.Thisshowsoneofthedifferencesbetweenthesetwomethods.Notethatthe LoadDataSetmethodrequiresareferencetoanexistingDataSetinstance,andanarraycontainingthe namesofthetablestopopulate.
stringselectSQL="SELECTId,Name,DescriptionFROMProductsWHEREId>90"; //FillaDataSetfromtheProductstableusingthesimpleapproach DataSetsimpleDS=defaultDB.ExecuteDataSet(CommandType.Text,selectSQL); DisplayTableNames(simpleDS,"ExecuteDataSet"); //FillaDataSetfromtheProductstableusingtheLoadDataSetmethod //Thisallowsyoutospecifythename(s)forthetable(s)intheDataSet DataSetloadedDS=newDataSet("ProductsDataSet"); defaultDB.LoadDataSet(CommandType.Text,selectSQL,loadedDS, newstring[]{"Products"}); DisplayTableNames(loadedDS,"LoadDataSet");

Thisproducesthefollowingresult.
TablesintheDataSetobtainedusingtheExecuteDataSetmethod: Tablenamed'Table'contains10rows. TablesintheDataSetobtainedusingtheLoadDataSetmethod: Tablenamed'Products'contains10rows.

AGuidetoDevelopingwithEnterpriseLibrary5.0

53

TheexamplethenaccessestherowsinDataSettodeletearow,addanewrow,andchangethe Descriptioncolumninanotherrow.Afterthis,itdisplaystheupdatedcontentsoftheDataSettable.
//getareferencetotheProductstableintheDataSet. DataTabledt=loadedDS.Tables["Products"]; //DeletearowintheDataSettable. dt.Rows[0].Delete(); //AddanewrowtotheDataSettable. object[]rowData=newobject[]{1,"ANewRow","Addedtothetableat" +DateTime.Now.ToShortTimeString()}; dt.Rows.Add(rowData); //UpdatethedescriptionofarowintheDataSettable. rowData=dt.Rows[1].ItemArray; rowData[2]="Anewdescriptionat"+DateTime.Now.ToShortTimeString(); dt.Rows[1].ItemArray=rowData; //DisplaythecontentsoftheDatSet. DisplayRowValues(dt);

Thisproducesthefollowingoutput.Tomakeiteasiertoseethechanges,we'veomittedtheunchanged rowsfromthelisting.Ofcourse,thedeletedrowdoesnotshowinthelisting,andthenewrowhasthe defaultIDof1thatwespecifiedinthecodeabove.


Rowsinthetablenamed'Products': Id=91 Name=HLMountainFrameBlack,44 Description=Anewdescriptionat14:25 ... Id=1 Name=ANewRow Description=Addedtothetableat14:25

ThenextstageistocreatethecommandsthattheUpdateDataSetmethodwillusetoupdatethetarget tableinthedatabase.ThecodedeclaresthreesuitableSQLstatements,andthenbuildsthecommands andaddstherequisiteparameterstothem.Notethateachparametermaybeappliedtomultiplerows inthetargettable,andsotheactualvaluemustbedynamicallysetbasedonthecontentsofthe DataSetrowwhoseupdatesarecurrentlybeingappliedtothetargettable. Thismeansthatyoumustspecify,inadditiontotheparameternameanddatatype,thenameandthe version(CurrentorOriginal)oftherowintheDataSettotakethevaluefrom.ForanINSERTcommand, youneedtocurrentversionoftherowthatcontainsthenewvalues.ForaDELETEcommand,youneed theoriginalvalueoftheIDtolocatetherowinthetablethatwillbedeleted.ForanUPDATEcommand, youneedtheoriginalvalueoftheIDtolocatetherowinthetablethatwillbeupdated,andthecurrent versionofthevalueswithwhichtoupdatetheremainingcolumnsinthetargettablerow.

AGuidetoDevelopingwithEnterpriseLibrary5.0

54

stringaddSQL="INSERTINTOProducts(Name,Description)VALUES(@name, @description);"; stringupdateSQL="UPDATEProductsSETName=@name,Description=@description WHEREId=@id"; stringdeleteSQL="DELETEFROMProductsWHEREId=@id"; //Createthecommandstoupdatetheoriginaltableinthedatabase DbCommandinsertCommand=defaultDB.GetSqlStringCommand(addSQL); defaultDB.AddInParameter(insertCommand,"name",DbType.String,"Name", DataRowVersion.Current); defaultDB.AddInParameter(insertCommand,"description",DbType.String, "Description",DataRowVersion.Current); DbCommandupdateCommand=defaultDB.GetSqlStringCommand(updateSQL); defaultDB.AddInParameter(updateCommand,"name",DbType.String,"Name", DataRowVersion.Current); defaultDB.AddInParameter(updateCommand,"description",DbType.String, "Description",DataRowVersion.Current); defaultDB.AddInParameter(updateCommand,"id",DbType.String,"Id", DataRowVersion.Original); DbCommanddeleteCommand=defaultDB.GetSqlStringCommand(deleteSQL); defaultDB.AddInParameter(deleteCommand,"id",DbType.Int32,"Id", DataRowVersion.Original);

Finally,youcanapplythechangesbycallingtheUpdateDataSetmethod,asshownhere.
//ApplytheupdatesintheDataSettotheoriginaltableinthedatabase introwsAffected=defaultDB.UpdateDataSet(loadedDS,"Products", insertCommand,updateCommand,deleteCommand, UpdateBehavior.Standard); Console.WriteLine("Updatedatotalof{0}rowsinthedatabase.",rowsAffected);

Thecodecapturesanddisplaysthenumberofrowsaffectedbytheupdates.Asexpected,thisisthree, asshowninthefinalsectionoftheoutputfromtheexample.
Updatedatotalof3rowsinthedatabase.

2.3.10

ManagingConnections

Formanyyears,developershavefrettedabouttheidealwaytomanageconnectionsindataaccess code.Connectionsarescarce,expensiveintermsofresourceusage,andcancauseabigperformancehit ifnotmanagedcorrectly.Youmustobviouslyopenaconnectionbeforeyoucanaccessdata,andyou shouldmakesureitisclosedafteryourhavefinishedwithit.However,iftheoperatingsystemdid actuallycreateanewconnection,andthencloseanddestroyiteverytime,theflowofexecutioninyour applicationswouldtendtoexhibitsimilarcharacteristicstotreacle. Instead,ADO.NETholdsapoolofopenconnectionsthatithandsouttoapplicationsthatrequirethem. Dataaccesscodemuststillgothroughthemotionsofcallingthemethodstocreate,open,andclose connections,butADO.NETautomaticallyretrievesconnectionsfromthepoolwhenpossible,and AGuidetoDevelopingwithEnterpriseLibrary5.0 55

decideswhenandwhethertoactuallyclosetheunderlyingconnectionanddisposeit.Themainissues arisewhenyouhavetodecidewhenandhowyourcodeshouldcalltheClosemethod.TheDataAccess blockhelpstoresolvetheseissuesbyautomaticallymanagingconnectionsasfarasisreasonably possible. WhenyouusetheDataAccessblocktoretrieveaDatSet,theExecuteDataSetmethodautomatically opensandclosestheconnectiontothedatabase.Ifanerroroccurs,itwillensurethattheconnectionis closed.Ifyouwanttokeepaconnectionopen,perhapstoperformmultipleoperationsoverthat connection,youcanaccesstheActiveConnectionpropertyofyourDbCommandobjectandopenit beforecallingtheExecuteDataSetmethod.TheExecuteDataSetmethodwillleavetheconnectionopen whenitcompletes,andsoyoumustensurethatyourcodeclosesitafterwards. Incontrast,whenyouretrieveaDataReader,theExecuteReadermethodmustleavetheconnection opensothatyoucanreadtherows(ortheXMLdatainthecaseoftheExecuteXmlReadermethod).The ExecuteReadermethodsetstheCommandBehaviorpropertyofthereadertoCloseConnectionsothat theconnectionisclosedwhenyoudisposethereader.Commonly,youwilluseausingconstructto ensurethatthereaderisdisposed,asshownhere:
using(IDataReaderreader=db.ExecuteReader(cmd) { //usethereaderhere }

Thiscode,andcodelaterinthissection,assumesyouhavecreatedtheDataAccessblockDatabase instancenameddbandaDbCommandinstancenamedcmd. However,ifyouusetheExecuteXmlReadermethod,youmustexplicitlyclosetheconnectionafteryou disposethereader.ThisisbecausetheunderlyingXmlReaderclassdoesnotexposea CommandBehaviorproperty.Therefore,youshouldusethetraditionalapproachofatry...catch...finally constructandensurethatyouclosetheconnectioninthecatchandfinallysectionsafteryouhave finishedreadingthedatafromthereader.Youshouldalsocheckthatthereisnocurrenttransactionin progressbeforeclosingtheconnection,asdescribedinthefollowingsection"Integrationwith Transactions". Finally,ifyouwanttobeabletoaccesstheconnectionyourcodeisusing,perhapstocreateconnection basedtransactionsinyourcode(asdescribedinthefollowingsection"IntegrationwithTransactions"), youcanusetheDataAccessblockmethodstoexplicitlycreateaconnectionforyourdataaccess methodstouse.Thismeansthatyoumustmanagetheconnectionyourself;commonlythroughausing statementasshownbelow,whichautomaticallyclosesanddisposestheconnection:
using(DbConnectionconn=db.CreateConnection()) { conn.Open(); try { //performdataaccesshere }

AGuidetoDevelopingwithEnterpriseLibrary5.0

56

catch { //handleanyerrorshere } }

2.3.11

WorkingwithConnectionBasedTransactions

Acommonrequirementinmanyapplicationsistoperformmultipleupdatestodatainsuchawaythat theyallsucceed,orcanallbeundone(rolledback)toleavethedatabasesinavalidstatethatis consistentwiththeoriginalcontent.Thetraditionalexampleiswhenyourbankcarriesoutamonetary transactionthatrequiresthemtosubtractapaymentfromoneaccountandaddthesameamountto anotheraccount(orperhapsslightlyless,withthecommissiongoingintotheirownaccount). Transactionsshouldfollowthefour"ACID"principles.TheseareAtomicity(allofthetasksofa transactionareperformedornoneofthemare),Consistency(thedatabaseremainsinaconsistentstate beforeandafterthetransaction),Isolation(otheroperationscannotaccessorseethedatainan intermediatestateduringatransaction),andDurability(theresultsofthetransactionarepersistedand willsurvivesystemfailure). Youcanexecutetransactionswhenalloftheupdatesoccurinasingledatabasebyusingthefeaturesof yourdatabasesystem(byincludingtherelevantcommandssuchasBEGINTRANSACTIONandROLLBACK TRANSACTIONinyourstoredprocedures).ADO.NETalsoprovidesfeaturesthatallowyoutoperform connectionbasedtransactionsoverasingleconnection.Thisallowsyoutoperformmultipleactionson differenttablesinthesamedatabase,andmanagethecommitorrollbackinyourdataaccesscode. AllofthemethodsoftheDataAccessblockthatretrieveorupdatedatahaveoverloadsthataccepta referencetoanexistingtransactionasaDbTransactiontype.Asanexampleoftheiruse,thefollowing codeexplicitlycreatesatransactionoveraconnection.ItassumesyouhavecreatedtheDataAccess blockDatabaseinstancenameddbandtwoDbCommandinstancesnamedcmdAandcmdB.
using(DbConnectionconn=db.CreateConnection()) { conn.Open(); DbTransactiontrans=conn.BeginTransaction(); try { //executecommands,passinginthecurrenttransactiontoeachone db.ExecuteNonQuery(cmdA,trans); db.ExecuteNonQuery(cmdB,trans); trans.Commit();//committhetransaction } catch { trans.Rollback();//rollbackthetransaction } }

AGuidetoDevelopingwithEnterpriseLibrary5.0

57

Theexamplesforthischaptercontainonenamed"Useaconnectionbasedtransaction"that demonstratestheapproachshownabove.ItstartsbydisplayingthevaluesoftworowsintheProducts table,andthenusestheExecuteNonQuerymethodtwicetoupdatetheDescriptioncolumnoftworows inthedatabasewithinthecontextofaconnectionbasedtransaction.Asitdoesso,itdisplaysthenew descriptionfortheserows.Finally,itrollsbackthetransaction,whichrestorestheoriginalvalues,and thendisplaysthesevaluestoprovethatitworked.


Contentsofrowsbeforeupdate: Id=53 Name=HalfFingerGloves,L Description=Fullpadding,improvedfingerflex,durablepalm,adjustableclosure. Id=84 Name=HitchRack4Bike Description=Carries4bikessecurely;steelconstruction,fits2"receiverhitch. UpdatedrowwithID=53to'Thirdandlittlefingerstendtogetcold.'. UpdatedrowwithID=84to'Bikestendtofalloffafterafewmiles.'. Contentsofrowafterrollingbacktransaction: Id=53 Name=HalfFingerGloves,L Description=Fullpadding,improvedfingerflex,durablepalm,adjustableclosure. Id=84 Name=HitchRack4Bike Description=Carries4bikessecurely;steelconstruction,fits2"receiverhitch.

2.3.12

WorkingwithDistributedTransactions

Ifyouneedtoaccessdifferentdatabasesaspartofthesametransaction(includingdatabaseson separateservers),ofifyouneedtoincludeotherdatasourcessuchasMessageQueuinginyour transaction,youmustuseadistributedtransactioncoordinator(DTC)mechanismsuchasWindows ComponentServices.Inthiscase,youjustperformtheusualdataaccessactions,andconfigureyour componentstousetheDTC.Commonly,thisisdonethroughattributesaddedtotheclassesthat performthedataaccess.However,youcan However,ADO.NETsupportstheconceptof"automatic"or"lightweight"transactionsthroughthe TransactionScopeclass.Youcanspecifythataseriesofactionsrequiretransactionalsupport,but ADO.NETwillnotgenerateanexpensivedistributedtransactionuntilyouactuallyopenmorethanone connectionwithinthetransactionscope.Thismeansthatyoucanperformmultipletransactedupdates todifferenttablesinthesamedatabaseoverasingleconnection.Assoonasyouopenanew connection,ADO.NETautomaticallycreatesadistributedtransaction(usingWindowsComponent

AGuidetoDevelopingwithEnterpriseLibrary5.0

58

Services),andenrollstheoriginalconnectionsandallnewconnectionscreatedwithinthetransaction scopeintothatdistributedtransaction.Youthencallmethodsonthetransactionscopetoeithercommit allupdates,ortorollback(undo)allofthem. Therefore,onceyoucreatethetransactionscopeorexplicitlycreateatransaction,youusetheData Accessblockmethodsinexactlythesamewayasyouwouldoutsideofatransaction.Youdonotneedto passthetransactionscopetothemethodsasyouwouldwhenusingADO.NETmethodsdirectly.For example,themethodsoftheDataAccessBlock(withtheexceptionoftheExecuteXmlReadermethod) automaticallydetectiftheyarebeingexecutedwithinthescopeofatransaction.Iftheyare,theyenlist inthetransactionscopeandreusetheexistingconnection(becauseopeninganewonewouldforce ComponentServicestostartadistributedtransaction),anddonotclosetheconnectionwhenthey complete.Thetransactionscopewithcloseanddisposetheconnectionwhenitisdisposed. Typically,youwillusetheTransactionScopeclassinthefollowingway:
using(TransactionScopescope =newTransactionScope(TransactionScopeOption.RequiresNew)) { //performdataaccesshere }

OnepointtonoteifyouusetheExecuteXmlReadermethodisthatyouareresponsibleformanaging theconnection,asdiscussedintheprecedingsection"ManagingConnections".Inmostcases,you mustclosetheconnectionafteryouhavefinishedworkingwiththeXmlReader.However,whendoing so,youshouldtesttoseeifthereisacurrenttransactionscope,becauseifyouclosethesingle connectionwithinthetransactionscopethatothermethodsareusingthesemethodswilleitherfail orwillopenanewconnectionthatmayconvertthetransactionintoadistributedtransaction.Youcan testforatransactionbycheckingoftheTransaction.Currentpropertyisnull.Youwillseeanexample ofthislaterinthischapter. Theexamplesforthischaptercontainonenamed"UseaTransactionScopeforadistributedtransaction" thatdemonstratestheuseofaTransactionScopewiththeDataAccessblock.Itperformsthesame updatestotheProductstableinthedatabaseasyousawinthepreviousexampleofusingaconnection basedtransaction.However,therearesubtledifferencesinthewaythisexampleworks. Inaddition,asisusestheWindowsDistributedTransactionCoordinator(DTC)service,youmustensure thatthisisrunningbeforeyouexecutetheexampledependingonyouroperatingsystemitmaynotbe settostartautomatically.Tostarttheservice,opentheServicesappletfromyourAdministrativeTools menu,rightclickontheDistributedTransactionCoordinatorservice,andclickStart.Toseetheeffects oftheTransactionScopeandthewaythatitpromotesatransaction,opentheComponentServices appletfromyourAdministrativeToolsmenuandexpandtheComponentServicesnodeuntilyoucan seetheTransactionListinthecentralpaneoftheapplet. Whenyouexecutetheexample,itcreatesanewTransactionScopeandexecutestheExecuteNonQuery methodtwicetoupdatetworowsinthedatabasetable.Atthispoint,thecodestopsuntilyoupressa

AGuidetoDevelopingwithEnterpriseLibrary5.0

59

key.Thisgivesyoutheopportunitytoconfirmthatthereisnodistributedtransactionasyoucanseeif youlookintheTransactionListintheComponentServicesapplet. Afteryoupressakey,theapplicationcreatesanewconnectiontothedatabase(whenweuseda connectionbasedtransactioninthepreviousexample,wejustupdatedtheparametervaluesand executedthesamecommandsoverthesameconnection).Thisnewconnection,whichiswithinthe scopeoftheexistingTransactionScopeinstance,causestheDTCtostartanewdistributedtransaction andenrolltheexistinglightweighttransactionintoit;asshowninthefollowingscreenshot.

Thecodethenwaitsuntilyoupressakeyagain,atwhichpointitexitsfromtheusingclausethatcreated theTransactionScope,andthetransactionisnolongerinscope.AsthecodedidnotcalltheComplete methodoftheTransactionScopetopreservethechangesinthedatabase,theyarerolledback automatically.Toprovethatthisisthecase,thecodedisplaysthevaluesoftherowsinthedatabase again.Thisisthecompleteoutputfromtheexample.


Contentsofrowsbeforeupdate: Id=53 Name=HalfFingerGloves,L Description=Fullpadding,improvedfingerflex,durablepalm,adjustableclosure. Id=84 Name=HitchRack4Bike Description=Carries4bikessecurely;steelconstruction,fits2"receiverhitch. UpdatedrowwithID=53to'Thirdandlittlefingerstendtogetcold.'. Nodistributedtransaction.Pressanykeytocontinue... UpdatedrowwithID=84to'Bikestendtofalloffafterafewmiles.'.

AGuidetoDevelopingwithEnterpriseLibrary5.0

60

Newdistributedtransactioncreated.Pressanykeytocontinue... ContentsofrowafterdisposingTransactionScope: Id=53 Name=HalfFingerGloves,L Description=Fullpadding,improvedfingerflex,durablepalm,adjustableclosure. Id=84 Name=HitchRack4Bike Description=Carries4bikessecurely;steelconstruction,fits2"receiverhitch.

ThisdefaultbehavioroftheTransactionScopeensuresthatanerrorofproblemthatstopsthecode fromcompletingthetransactionwillautomaticallyrollbackchanges.Ifyourcodedoesnotseemtobe updatingthedatabase,checkthatyourememberedtocalltheCompletemethod!

2.4

ExtendingtheBlocktoUseOtherDatabases

TheDataAccessblockcontainsprovidersforSQLServer,Oracle,andSQLServerCompactEdition. However,youcanextendtheblocktouseotherdatabasesifyouwish.Writinganewproviderisnota trivialtask,andyoumayfindthatthereisalreadyathirdpartyprovideravailableforyourdatabase.For example,atthetimeofwriting,theEnterpriseLibraryCommunityContributionsitelistedprovidersfor MySqlandSQLitedatabases.Formoreinformation,visittheEntLibContribProjectsiteat http://codeplex.com/entlibcontrib/. Ifyoudecidetocreateanewprovider,youcancreateanewclassderivedfromtheEnterpriseLibrary Databaseclassandoverrideitsmethodstoimplementtheappropriatefunctionality.Onelimitingfactor isthattheremustbeanADO.NETprovideravailableforyourdatabase.TheDatabaseclassinEnterprise Libraryreliesonthistoperformdataaccessoperations. Youmustalsobeawareofthedifferencesbetweendatabasefunctionality,andmanagethese differencesinyourcode.Forexample,youmusthandlereturnvalues,parameterprefixes(suchas"@"), datatypeconversions,andotherrelevantfactors.However,youcanaddadditionalmethodstoyour providertotakeadvantageoffeaturesofyourtargetdatabasethatarenotavailableforotherdatabase types.Forexample,theSQLServerproviderintheDataAccessblockexposesamethodthatusesthe SQLXMLfunctionalityinSQLServertoextractdatainXMLformat. FormoreinformationoncreatingadditionaldatabaseprovidersfortheDataAccessblock,seethe EnterpriseLibraryonlinehelpfilesathttp://msdn.microsoft.com/entlib/ortheinstalleddocumentation.

2.5

Summary

ThischapterdiscussestheDataAccessApplicationBlock;oneofthemostcommonlyusedblocksin EnterpriseLibrary.TheDataAccessblockprovidestwokeyadvantagesfordevelopersand

AGuidetoDevelopingwithEnterpriseLibrary5.0

61

administrators.Firstly,itabstractsthedatabasesothatdevelopersandadministratorscanswitchthe applicationfromonetypeofdatabasetoanotherwithonlychangestotheconfigurationfilesrequired. Secondly,ithelpsdevelopersbymakingiteasiertowritethemostcommonlyusedsectionsofdata accesscodewithlesseffort,andithidessomeofthecomplexityofworkingdirectlywithADO.NET. Intermsofabstractingthedatabase,theblockallowsdeveloperstowritecodeinsuchawaythat(for mostfunctions)theydonotneedtoworrywhichdatabase(suchasSQLServer,SQLCE,orOracle)their applicationswilluse.Theywritethesamecodeforallofthem,andconfiguretheapplicationtospecify theactualdatabaseatruntime.Thismeansthatadministratorsandoperationsstaffcanchangethe targeteddatabase;withoutrequiringchangestothecode,recompilation,retesting,andredeployment. Intermsofsimplifyingdataaccesscode,theblockprovidesasmallnumberofmethodsthatencompass mostdataaccessrequirements,suchasretrievingaDataSet,aDataReader,ascalar(single)value,one ormorevaluesasoutputparameters,oraseriesofXMLelements.Italsoprovidesmethodsforupdating adatabasefromaDataSet,andintegrateswiththeADO.NETTransactionScopeclasstoallowarangeof optionsforworkingwithtransactions.However,theblockdoesnotlimityouroptionstousemore advancedADO.NETtechniques,asitallowsyoutoaccesstheunderlyingobjectssuchastheconnection andtheDataAdapter. Thechapteralsodescribedgeneralissuessuchasmanagingconnectionsandintegrationwith transactionsaswellexploringtheactualcapabilitiesoftheblockinmoredepth.Finally,welooked brieflyathowyoucanusetheblockwithotherdatabases,includingthosesupportedbythirdparty providers.

AGuidetoDevelopingwithEnterpriseLibrary5.0

62

Chapter3 ErrorManagementMade ExceptionallyEasy


Contents
Introduction..........................................................................................................................................64 WhenShouldIUsetheExceptionHandlingBlock?.............................................................................. 65 HowDoIUsetheExceptionHandlingBlock?....................................................................................... 65 WhatExceptionPoliciesDoINeed?..................................................................................................... 65 AllowingExceptionstoPropagate.................................................................................................... 66 AboutExceptionHandlingPolicies................................................................................................... 66 ChoosinganExceptionHandlingStrategy........................................................................................ 67 ProcessorHandleException?............................................................................................................ 68 DivinginwithaSimpleSample............................................................................................................. 69 ApplyingExceptionShielding............................................................................................................ 70 WrappinganException......................................................................................................................... 71 ConfiguringtheWrapHandlerPolicy............................................................................................... 71 InitializingtheExceptionHandlingBlock.......................................................................................... 72 EditingtheApplicationCodetoUsetheNewPolicy........................................................................ 72 ReplacinganException......................................................................................................................... 74 LogginganException............................................................................................................................ 75 AvoidingDuplicateLogging............................................................................................................... 77 ShieldingExceptionsatWCFServiceBoundaries................................................................................. 78 CreatingaFaultContract.................................................................................................................. 78 ConfiguringtheExceptionHandlingPolicy....................................................................................... 78 EditingtheServiceCodetoUsetheNewPolicy............................................................................... 79 WhattheFaultContractExceptionHandlerDoes............................................................................ 79 HandlingSpecificExceptionTypes........................................................................................................ 81 ExecutingCodearoundExceptionHandling......................................................................................... 81 AssistingAdministrators....................................................................................................................... 84 ExtendingyourExceptionHandling...................................................................................................... 86 AGuidetoDevelopingwithEnterpriseLibrary5.0 63

Summary...............................................................................................................................................86

3.1

Introduction

Let'sfaceitexceptionsaren'tthemostexcitingpartofwritingapplicationcode.Infact,youcould probablysaythatmanagingexceptionsisoneofthose"needtodoit"tasksthatabsorbeffortwithout addinganythingusefultoyourexcitingnewapplication.Sowhywouldyouworryaboutspendingtime andeffortactuallydesigningastrategyformanagingexceptions?Surelytherearemuchmoreimportant thingsyoucouldbedoing? Infact,arobustandwellplannedexceptionhandlingisavitalfeatureofyourapplicationdesignand implementation.Itshouldnotbeanafterthought.Ifyoudon'thaveaplan,youcanfindyourselftrying totrackdownallkindsofstrangeeffectsandunexpectedbehaviorinyourcode.And,worsethanthat, youmayevenbesacrificingsecurityandleavingyourapplicationandsystemsopentoattackfor example,afailuremayexposeerrormessagescontainingsensitiveinformation:"Hi,theapplicationjust failed,butheresthenameoftheserverandthedatabaseconnectionstringitwasusingatthetime". Notagreatplan. Thegeneralexpectationsforexceptionhandlingaretopresentaclearandappropriatemessageto users;andtoprovideassistanceforoperators,administrators,andsupportstaffwhomustresolve problemsthatarise.Forexample,thefollowingactionsareusuallypartofacomprehensiveexception handlingstrategy: Notifytheuserwithafriendlymessage Storedetailsoftheexceptioninaproductionlogorotherrepository Alertthecustomerserviceteamtotheerror Assistsupportstaffincrossreferencingtheexceptionandtracingthecause

So,havingdecidedthatyouprobablyshouldimplementsomekindofstructuredexceptionhandling strategyinyourcode,howdoyougoaboutit?Agoodstartingpoint,asusual,istoseeifthereareany recommendationsintheformofwellknownpatternsthatyoucanimplement.Inthiscase,thereare. TheprimarypatternthathelpsyoutobuildsecureapplicationsiscalledExceptionShielding.Exception shieldingistheprocessofensuringthatyourapplicationdoesnotleaksensitiveinformation,nomatter whatruntimeorsystemeventmayoccurtointerruptnormaloperation.Andonamoregranularlevel,it canpreventyourassetsfrombeingrevealedacrosslayer,tier,process,orserviceboundaries. TwomoreexceptionhandlingpatternsthatyoushouldconsiderimplementingaretheException LoggingpatternandtheExceptionTranslationpattern.TheExceptionLoggingpatterncanhelpyouto helpdiagnoseandtroubleshooterrors,audituseractions,andtrackmaliciousactivityandsecurity issues.TheExceptionTranslationpatterndescribeswrappingexceptionswithinotherexceptionsspecific toalayertoensurethattheyactuallyreflectuserorcodeactionswithinthelayeratthattime,andnot somemiscellaneousdetailsthatmaynotbeuseful. AGuidetoDevelopingwithEnterpriseLibrary5.0 64

Inthischapter,youwillseehowtheEnterpriseLibraryExceptionHandlingBlockcanhelpyouto implementthesepatterns,aswellasprovidingotherfeaturesrequiredtoimplementacomprehensive exceptionmanagementstrategy.You'llseehowtoreplace,wrap,andlogexceptions;andhowto modifyexceptionmessagestomakethemmoreuseful.And,asabonus,howyoucaneasilyimplement exceptionshieldingforWindowsCommunicationFoundation(WCF)Webservices.

3.2

WhenShouldIUsetheExceptionHandlingBlock?

TheExceptionHandlingBlockallowsyoutoconfigurehowyouwanttomanageexceptions,and centralizeyourexceptionhandlingcode.Itprovidesaselectionofpluginexceptionhandlersand formattersthatyoucanuse,andyoucanevencreateyourowncustomimplementations.Youcanuse theblockwhenyouwanttoimplementexceptionshielding,modifyexceptionsinarangeofways,or chainexceptions(forexample,byloggingandexceptionandthenpassingittoanotherlayerofyour application). Theconfigurableapproachmeansthatadministratorscanchangethebehavioroftheexception managementmechanismsimplybyeditingtheapplicationconfiguration,withoutrequiringanychanges tothecode,recompilation,andredeployment. NotethattheExceptionHandlingblockwasneverintendedforuseeverywherethatyoucatch exceptions.Theblockisprimarilydesignedtosimplifyexceptionhandlingandexceptionmanagement atyourapplicationorlayerboundaries.

3.3

HowDoIUsetheExceptionHandlingBlock?

LikealloftheEnterpriseLibraryapplicationblocks,youstartbyconfiguringyourapplicationtousethe block,asdemonstratedinChapter1.ThenyouaddoneormoreExceptionPoliciesand,foreachpolicy, specifythetypeofexceptionitappliesto.Finally,youaddoneormoreexceptionhandlerstoeach policy.ThesimplestapproachisapolicythatspecifiesthebasetypeException,andusesoneofthe handlersprovidedwiththeblock.However,you'llseethevarioushandlers,andotheroptions, demonstratedintheexamplesinthischapter.

3.4

WhatExceptionPoliciesDoINeed?

Thekeytohandlingexceptionsistoapplytheappropriatepoliciestoeachtypeofexception.Youcan pretendyouareplayingthewellknownTVquizgamethatjustmightmakeyouintoamillionaire: Question:HowshouldIhandleexceptions? A:Wrapthem C:Logandrethrowthem B:Replacethem D:Allowthemtopropagate

AGuidetoDevelopingwithEnterpriseLibrary5.0

65

Youcan,ofcourse,phoneafriendorasktheaudienceifyouthinkitwillhelp.However,unlikemostquiz games,alloftheanswersareactuallycorrect(whichiswhywedon'tofferprizes).Therefore,ifyou answered"A","B",or"C",youcanmoveontothenextsection"AboutExceptionHandlingPolicies". However,ifyouanswered"D:Allowthemtopropagate",youcoulddecidetostopreadingnowbecause youdon'tactuallyneedtheExceptionHandlingblockifyoujustwanttoignoreexceptions.Yourcode candothisallbyitself.However,atsomepoint,you'llstillneedtohandletheexception.

3.4.1 AllowingExceptionstoPropagate
Ifyoucannotdoanythingusefulwhenanexceptionoccurs,suchasloggingexceptioninformation, modifyingtheexceptiondetails,orretryingthefailedprocess,thereisnopointincatchingthe exceptioninthefirstplace.Instead,youjustallowittopropagateupthroughthecallstack,andcatchit elsewhereinyourcodeeithertoresolvetheissueortodisplayerrormessages.Ofcourse,atthis point,youcanapplyanexceptionpolicy;andsoyoucomebacktohowyoushouldchooseand implementanappropriateexceptionhandlingstrategy.

3.4.2 AboutExceptionHandlingPolicies
EachpolicyyouconfigurefortheExceptionHandlingblockcanspecifyoneormoreexceptiontypes, suchasDivideByZeroException,SqlException,InvalidCastException,thebaseclassException,orany customexceptiontypeyoucreatethatinheritsfromSystem.Exception.Theblockcomparesexceptions thatithandleswitheachofthesetypes,andchoosestheonethatismostspecificintheclasshierarchy. Foreachpolicy,youconfigure: Oneormoreexceptionhandlersthattheblockwillexecutewhenamatchingexceptionoccurs. Youcanchoosefromfour"outofthebox"handlers:theReplacehandler,theWraphandler, theLogginghandler,andtheFaultContracthandler.Alternatively,youcancreatecustom exceptionhandlersandchoosethese(see"NextStepsforExceptionHandling"neartheendof thischapterformoreinformation). AposthandlingactionvaluethatspecifieswhathappensaftertheExceptionHandlingblock executesthehandlersyouspecify.Effectively,thissettingtellsthecallingcodewhetherto continueexecuting.Youcanchoosefrom: None.Returnsfalsetothecallingcodetoindicatethatitshouldcontinueexecuting. NotifyRethrow.Returntruetothecallingcodetoindicateitshouldthrowanexception, whichmaybetheonethatwasactuallycaughtortheonegeneratedbythepolicy. ThrowNewException.TheExceptionHandlingblockwillthrowtheexceptionthatresults fromexecutingallofthehandlers.

ThefollowingfigureshowsanexamplepolicynamedMyTestExceptionPolicyintheEnterpriseLibrary configurationconsole.ThispolicyhandlesthethreeexceptiontypesDivideByZeroException,Exception, andInvalidCastException,andcontainsamixofhandlersforeachexceptiontype.

AGuidetoDevelopingwithEnterpriseLibrary5.0

66

[Awaitingnewimage] Noticehowyoucanspecifythepropertiesforeachtypeofexceptionhandler.Forexample,inFigure1, youcanseethattheReplaceHandlerhaspropertiesfortheexceptionmessageandthetypeof exceptionyouwanttousetoreplacetheoriginalexception.Also,noticethatyoucanlocalizeyour policybyspecifyingthenameandtypeoftheresourcecontainingthelocalizedmessagestring.

3.4.3 ChoosinganExceptionHandlingStrategy
So,comingbacktotheanswersforourquizquestion,"HowshouldIhandleexceptions?"Youshouldbe abletoseefromtheoptionsavailableforexceptionhandlingpolicieshowyoucanimplementthe commonstrategiesforhandlingexceptions: Replacetheexceptionwithadifferentoneandthrowthenewexception.Thisisan implementationoftheExceptionShieldingpattern.Inyourexceptionhandlingcode,youcan cleanupresourcesorperformanyotherrelevantprocessing.YouuseaReplacehandlerinyour exceptionhandlingpolicytoreplacetheexceptionwithadifferentexceptioncontaining sanitizedornewinformationthatdoesnotrevealsensitivedetailsaboutthesourceofthe error,theapplication,ortheoperatingsystem.AddaLogginghandlertotheexceptionpolicyif youwanttologtheexception.PlaceitbeforetheReplacehandlertologtheoriginalexception, orafterittologthereplacementexception(ifyoulogsensitiveinformation,makesureyourlog filesareproperlysecured).SettheposthandlingactiontoThrowNewExceptionsothatthe blockwillthrowthenewexception.

AGuidetoDevelopingwithEnterpriseLibrary5.0

67

Wraptheexceptiontopreservethecontentandthenthrowthenewexception.Thisisan implementationoftheExceptionTranslationpattern.Inyourexceptionhandlingcode,youcan cleanupresourcesorperformanyotherrelevantprocessing.YouuseaWraphandlerinyour exceptionhandlingpolicytowraptheexceptionwithinanotherexceptionthatismorerelevant tothecallerandthenthrowthenewexceptionsothatcodehigherinthecodestackcanhandle it.Thisapproachisusefulwhenyouwanttokeeptheoriginalexceptionanditsinformation intact,and/orprovideadditionalinformationtothecodethatwillhandletheexception.Adda Logginghandlertotheexceptionpolicyifyouwanttologtheexception.Placeitbeforethe Wraphandlertologtheoriginalexception,orafterittologtheenclosingexception.Setthe posthandlingactiontoThrowNewExceptionsothattheblockwillthrowthenewexception. Logand,optionally,rethrowtheoriginalexception.Inyourexceptionhandlingcode,youcan cleanupresourcesorperformanyotherrelevantprocessing.YouuseaLogginghandlerinyour exceptionhandlingpolicytowritedetailsoftheexceptiontotheconfiguredloggingstoresuch asWindowsEventLogorafile(animplementationoftheExceptionLoggingpattern).Ifthe exceptiondoesnotrequireanyfurtheractionbycodeelsewhereintheapplication(for example,ifaretryactionsucceeds),settheposthandlingactiontoNone.Otherwise,setthe posthandlingactiontoNotifyRethrow.Youreventhandlercodecanthentodecidewhetherto throwtheexception.Alternatively,youcansetittoThrowNewExceptionifyoualwayswantthe ExceptionHandlingblocktothrowtheexceptionforyou.

RememberthatthewholeideaofusingtheExceptionHandlingblockistoimplementastrategymade upofconfigurablepoliciesthatyoucanchangewithouthavingtoedit,recompile,andredeploythe application.Forexample,theblockallowsyou(oranadministrator)to: Add,remove,andchangethetypesofhandlers(suchastheWrap,Replace,andLogging handlers)thatyouuseforeachexceptionpolicy;andchangetheorderinwhichtheyexecute. Add,remove,andchangetheexceptiontypesthateachpolicywillhandle,andthetypesof exceptionsusedtowraporreplacetheoriginalexceptions. Modifythetargetandstyleoflogging,includingmodifyingthelogmessages,foreachtypeof exceptionyoudecidetolog.Thisisuseful,forexample,whentestinganddebugging applications. Decidewhattodoaftertheblockhandlestheexception.Providingthattheexceptionhandling codeyouwritechecksthereturnvaluefromthecalltotheExceptionHandlingblock,thepost handlingactionwillallowyouoranadministratortospecifywhethertheexceptionshouldbe thrown.Again,thisisextremelyusefulwhentestinganddebuggingapplications.

3.4.4 ProcessorHandleException?
TheExceptionHandlingblockprovidestwowaysforyoutomanageexceptions.YoucanusetheProcess methodtoexecuteanymethodinyourapplication,andhavetheExceptionHandlingblock

AGuidetoDevelopingwithEnterpriseLibrary5.0

68

automaticallyperformmanagementandthrowingoftheexception.Alternatively,ifyouwanttoapply moregranularcontrolovertheprocess,youcanusetheHandleExceptionmethod.Thefollowingwill helpyoutounderstandwhichapproachtochoose. TheProcessmethodisthemostcommonapproach,andisusefulinthemajorityofcases.You specifyeitheradelegate(theaddressofamethod)oralambdaexpressionthatyouwantto execute.TheExceptionHandlingblockexecutesthemethodorexpression,andautomatically managesanyexceptionthatoccurs.YouwillgenerallyspecifyaPostHandlingActionof ThrowNewExceptionsothattheblockautomaticallythrowstheexceptionthatresultsfrom executingtheexceptionhandlingpolicy.However,ifyouwantthecodetocontinuetoexecute (insteadofthrowingtheexception),youcansetthePostHandlingActionofyourexception handlingpolicytoNone. TheHandleExceptionmethodisusefulifyouwanttobeabletodetecttheresultofexecuting theexceptionhandlingpolicy.Forexample,ifyousetthePostHandlingActionofapolicyto NotifyRethrow,youcanusethereturnvalueoftheHandleExceptionmethodtodetermine whetherornottothrowtheexception.YoucanalsousetheHandleExceptionmethodtopass anexceptiontotheblockandhaveitreturntheexceptionthatresultsfromexecutingthe policywhichmightbetheoriginalexception,areplacementexception,ortheoriginal exceptionwrappedinsideanewexception.

Youwillseebothtechniquesdescribedinthefollowingexamples,althoughmostofthemusethe Processmethod. TheProcessmethodisoptimizedforusewithLambdaexpressions,whicharesupportedinC#3.0on version3.5ofthe.NETFrameworkandinVisualStudio2008onwards.DivinginwithaSimpleSample Toseehowyoucanapplyexceptionhandlingstrategiesandconfigureexceptionhandlingpolicies,we'll startwithasimpleapplicationthatcausesanexceptionwhenitexecutes.First,weneedaclassthatwe cancallfromourmainroutinesuchasthefollowing.


publicDecimalGetWeeklySalary(StringemployeeId,Int16weeks) { StringconnString=string.Empty; StringemployeeName=String.Empty; Decimalsalary=0; try { connString=ConfigurationManager.ConnectionStrings ["EmployeeDatabase"].ConnectionString; //Accessdatabasetogetsalaryforemployeehere... //Inthisexample,justassumeit'ssomelargenumber. employeeName="JohnSmith"; salary=1000000; returnsalary/weeks; }

AGuidetoDevelopingwithEnterpriseLibrary5.0

69

catch(Exceptionex) { //provideerrorinformationfordebugging stringtemplate="Errorcalculatingsalaryfor{0}." +"Salary:{1}.Weeks:{2}\n" +"Dataconnection:{3}\n{4}"; ExceptioninformationException=newException( string.Format(template,employeeName,salary,weeks, connString,ex.Message)); throwinformationException; } }

YoucanseethatacalltotheGetWeeklySalarymethodwillcauseanexceptionoftype DivideByZeroExceptionwhencalledwithavalueofzeroforthe"numberofweeks"parameter.The exceptionmessagecontainsthevaluesofthevariablesusedinthecalculation,andotherinformation usefultoadministratorswhendebuggingtheapplication.Unfortunately,thecurrentcodehasseveral issues.Ittrashestheoriginalexceptionandlosesthestacktrace,preventingmeaningfuldebugging. Evenworse,theglobalexceptionhandlerfortheapplicationhelpfullypresentsanyuserofthe applicationwithallofthesensitiveinformationwhenanerroroccurs. Ifyouruntheexampleforthischapter,andselectoption[A]"TypicalDefaultBehaviorwithout ExceptionShielding",youwillseethisresultgeneratedbythecodeinthecatchstatement:


ExceptiontypeSystem.Exceptionwasthrown. Message:'ErrorcalculatingsalaryforJohnSmith. Salary:1000000.Weeks:0 Connection:Database=Employees;Server=CorpHQ; UserID=admin;Password=2g$tXD76qrAttemptedtodividebyzero.' Source:'ExceptionHandlingExample'

3.4.5 ApplyingExceptionShielding
It'sclearthattheapplicationasitstandshasaseveresecurityholethatallowsittorevealsensitive information.Ofcourse,wecouldpreventthisbynotaddingthesensitiveinformationtotheexception message.However,theinformationwillbeusefultoadministratorsanddevelopersiftheyneedto debugtheapplication.Forexample,ifthedataconnectionhadfailedorthedatabasecontainedinvalid data,theywouldhaveseenthisthroughmissingvaluesfortheemployeenameorsalary;andtheycould seeifconfigurationfilecontainsthecorrectdatabaseconnectionstring.Alternatively,inthiscaseshown here,theycanimmediatelytellthatthedatabasereturnedtherequiredvaluesfortheoperation,but theuserinterfaceallowedtheusertoenterthevaluezeroforthenumberofweeks. Toprovidethisextrainformation,yetapplyexceptionshielding,youmayconsiderimplementing configurationsettingsandcustomcodetoallowadministratorstospecifywhentheyneedtheadditional information.However,thisisexactlywheretheExceptionHandlingblockcomesin.Youcansetupan exceptionhandlingpolicythatadministratorscanmodifyasrequired,withoutneedingtowritecustom codeorsetupcustomconfigurationsettings.

AGuidetoDevelopingwithEnterpriseLibrary5.0

70

Thefirststepistocreateanexceptionhandlingpolicythatspecifiestheeventswewanttohandle,and containsahandlerthatwilleitherwrap(hide)orreplace(remove)theexceptioncontainingallofthe debugginginformationwithonethatcontainsasimpleerrormessagesuitablefordisplaytousersor propagationthroughthelayersoftheapplication.You'llseetheseoptionsimplementedinthefollowing sections.Youwillalsoseehowyoucanlogtheoriginalexceptionbeforereplacingit,howyoucan handlespecifictypesofexceptions,andhowyoucanapplyexceptionshieldingtoWindows CommunicationFoundation(WCF)services.

3.5

WrappinganException

Ifyouwanttoretaintheoriginalexception,andtheinformationitcontains,youcanwraptheexception inanotherexceptionandspecifyasanitizeduserfriendlyerrormessageforthecontainingexception. Thisistheerrormessagethattheglobalerrorhandlerwilldisplay.However,codeelsewhereinthe application(suchascodeinacallinglayerthatneedstoaccessandlogtheexceptiondetails)canaccess thecontainedexceptionandretrievetheinformationitrequiresbeforepassingtheexceptiononto anotherlayerortotheglobalexceptionhandler.Thisintermediatecodecouldalternativelyremovethe containedexceptionoruseanExceptionHandlingblockpolicytoreplaceitatthatpointinthe application.

3.5.1 ConfiguringtheWrapHandlerPolicy
So,thefirststageistoconfiguretheexceptionhandlingpolicyyourequire.Youneedtoaddapolicythat specifiesthetypeofexceptionreturnedfromyourcode(inthiscase,we'llspecifythebaseclass Exception),andsetthePostHandlingActionpropertyforthisexceptiontypetoThrowNewExceptionso thattheExceptionHandlingblockwillautomaticallythrowthenewexceptionthatwrapstheoriginal exception.ThenaddaWraphandlertothepolicy,andspecifytheexceptionmessageandthetypeof exceptionyouwanttousetowraptheoriginalexception(wechoseExceptionhereagain).The followingfigureshowsthecompletedconfiguration. [Policyname:"ExceptionShielding"]

[Awaitingnewimage]

AGuidetoDevelopingwithEnterpriseLibrary5.0

71

3.5.2 InitializingtheExceptionHandlingBlock
NowyoumustedityourcodetousetheExceptionHandlingblock.You'llneedtoaddreferencestothe appropriateEnterpriseLibraryassembliesandnamespaces.Theexamplesinthischapterdemonstrate loggingexceptioninformationandhandlingexceptionsinaWindowsCommunicationFoundation(WCF) application,aswellasthebasicprocessesofwrappingandreplacingexceptions,sowe'lladdreferences toalloftheassembliesandnamespacesrequiredforthesetasks. Theassembliesyoumustaddtoyourproject(inadditiontotheassembliesrequiredforallEnterprise Libraryprojects)are: Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.dll Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.dll Microsoft.Practices.EnterpriseLibrary.Logging.dll

Ifyouareonlywrappingandreplacingexceptionsinyourapplication,youdon'tneedtoaddthe assembliesandreferencesforWCFandLogging.
//Referencestothecoreandconfigurationnamespaces. usingMicrosoft.Practices.EnterpriseLibrary.Common; usingMicrosoft.Practices.EnterpriseLibrary.Common.Configuration; usingMicrosoft.Practices.EnterpriseLibrary.Common.Configuration.Unity; usingMicrosoft.Practices.Unity; //Referencestotheapplicationblocknamespace(s). usingMicrosoft.Practices.EnterpriseLibrary.ExceptionHandling; usingMicrosoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF; usingMicrosoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging; usingMicrosoft.Practices.EnterpriseLibrary.Logging;

NowyoucanresolveaninstanceoftheExceptionManagerclassyou'llusetoperformmanagementof exceptions.YoucanusethedependencyinjectionapproachdescribedinChapter1,ortheGetInstance method.Thisexampleusesthelattersimpleapproach.


//GlobalvariabletostoretheExceptionManagerinstance. ExceptionManagerexManager; //ResolvethedefaultExceptionManagerobjectfromthecontainer. exManager=EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

3.5.3 EditingtheApplicationCodetoUsetheNewPolicy
Nowyoucanupdateyourexceptionhandlingcodetousethenewpolicy.Youhavetwochoices.Ifthe configuredexceptionpolicydoeseverythingyouneedtodo,youcanactuallyremovethetry...catch blockcompletelyfromthemethodthatmaycauseanerror,andinsteadusetheProcessmethodof theExceptionManagertoexecutethecodewithinthemethodasshownhere. AGuidetoDevelopingwithEnterpriseLibrary5.0 72

publicDecimalGetWeeklySalary(StringemployeeId,Int16weeks) { StringconnString=string.Empty; StringemployeeName=String.Empty; Decimalsalary=0; DecimalweeklySalary=0; ExManager.Process(()=>{ stringconnString=ConfigurationManager.ConnectionStrings ["EmployeeDatabase"].ConnectionString; //Accessdatabasetogetsalaryforemployee. //Inthisexample,justassumeit'ssomelargenumber. employeeName="JohnSmith"; salary=1000000; weeklySalary=salary/weeks; }, "ExceptionShielding"); returnweeklySalary; }

ThebodyofyourlogicisplacedinsidealambdafunctionandpassedtotheProcessmethod.Ifan exceptionoccursduringtheexecutionoftheexpression,itiscaughtandhandledaccordingtothe configuredpolicy.ThenameofthepolicytoexecuteisspecifiedinthesecondparameteroftheProcess method. Alternatively,youcanusetheProcessmethodinyourmaincodetocallthemethodofyourclass,as shownhere.Thisisausefulapproachifyouwanttoperformexceptionshieldingattheboundaryof otherclassesorobjects.


exManager.Process(()=> { SalaryCalculatorcalc=newSalaryCalculator(); Console.WriteLine("Resultis:{0}",calc.GetWeeklySalary("jsmith",0)); }, "ExceptionShielding");

Now,whenanerroroccurs,theglobalapplicationexceptionhandlerseesthewrappedexception insteadoftheoriginal"informational"exception.Inthesampleapplication,ifyouselecttheoption[B] "BehaviorAfterApplyingExceptionShieldingwithaWrapHandler",thecatchsectionnowdisplaysthe following.YoucanseethattheoriginalexceptionishiddenintheInnerException,andtheexception thatwrapsitcontainsthegenericerrormessage.


ExceptiontypeSystem.Exceptionwasthrown. Message:'ApplicationError.Pleasecontactyouradministrator.' Source:'Microsoft.Practices.EnterpriseLibrary.ExceptionHandling' InnerException:System.Exception:ErrorcalculatingsalaryforJohnSmith. Salary:1000000.Weeks:0

AGuidetoDevelopingwithEnterpriseLibrary5.0

73

Connection:Database=Employees;Server=CorpHQ;UserID=admin;Password=2g$tXD76qr Attemptedtodividebyzero. atExceptionHandlingExample.SalaryCalculator.GetWeeklySalary(StringemployeeI d,Int32weeks)inE:\Projects\EntLib5\Guides\DevGuide\CodeCS\ExceptionHandling \ExceptionHandling\SalaryCalculator.cs:line34 atExceptionHandlingExample.Program.<WithWrapExceptionShielding>b__0()inE:\ Projects\EntLib5\Guides\DevGuide\CodeCS\ExceptionHandling\ExceptionHandling\Pro gram.cs:line109 atMicrosoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionManagerIm pl.Process(Actionaction,StringpolicyName)

Thismeansthatdevelopersandadministratorscanexaminethewrapped(inner)exceptiontogetmore information.However,bearinmindthatthesensitiveinformationisstillavailableintheexception, whichcouldleadtoaninformationleakiftheexceptionpropagatesbeyondyoursecureperimeter. Whilethisapproachmaybesuitableforhighlytechnical,specificerrors,forcompletesecurityand exceptionshielding,youshouldusethetechniqueshowninthenextsectiontoreplacetheexception withonethatdoesnotcontainanysensitiveinformation. Forsimplicity,thisexampleshowstheprinciplesofexceptionshieldingattheleveloftheUIview.The businessfunctionalityitusesmaybeinthesamelayer,inaseparatebusinesslayer,orevenona separatephysicaltier.Rememberthatyoushoulddesignandimplementanexceptionhandling strategyforindividuallayersortiersinordertoshieldexceptionsonthelayerorserviceboundaries.

3.6

ReplacinganException

Havingseenhoweasyitistouseexceptionhandlingpolicies,we'llnowlookathowyoucanimplement exceptionshieldingbyreplacinganexceptionwithadifferentexception.Thisapproachisalsousefulif youneedtoperformcleanupoperationsinyourcode,andthenusetheexceptiontoexposeonlywhat isrelevant.Toconfigurethisscenario,simplycreateapolicyinthesamewayasthepreviousexample, butwithaReplacehandlerinsteadofaWraphandler,asshowninthefollowingscreenshot. [Policyname:"ReplacingException"]

[Awaitingnewimage] AGuidetoDevelopingwithEnterpriseLibrary5.0 74

Whenyoucallthemethodthatgeneratesanexception,youseethesamegenericexceptionmessageas inthepreviousexample.However,thereisnoinnerexceptionthistime.Ifyouselect[C]"BehaviorAfter ApplyingExceptionShieldingwithaReplaceHandler"inthesampleapplication,theExceptionHandling blockreplacestheoriginalexceptionwiththenewonespecifiedintheexceptionhandlingpolicy.Thisis theresult:


ExceptiontypeSystem.Exceptionwasthrown. Message:'ApplicationError.Pleasecontactyouradministrator.' Source:'Microsoft.Practices.EnterpriseLibrary.ExceptionHandling' NoInnerException

3.7

LogginganException

Thepreviousexampleshowshowyoucanperformexceptionshieldingbyreplacinganexceptionwitha newsanitizedversion.However,younowloseallthevaluabledebuggingandtestinginformationthat wasavailableintheoriginalexception.Ofcourse,TheLibrarian(rememberhim?)realizedthatyou wouldneedtoretainthisinformationandmakeitavailableinsomewayaspartofimplementingthe ExceptionShieldingpattern.Youachievethistaskbychainingexceptionhandlerswithinyourexception handlingpolicy.Inotherwords,youaddaLogginghandlertothepolicy. ThatdoesntmeanthattheLogginghandlerisonlyusefulaspartofachainofhandlers.Ifyouonlywant tologdetailsofanexception(andthenthrowitorignoreit,dependingontherequirementsofthe application),youcandefineapolicythatcontainsjustaLogginghandler.However,inmostcases,you willuseaLogginghandlerwithotherhandlersthatwraporreplaceexceptions. ThefollowingfigureshowswhathappenswhenyouaddaLogginghandlertoyourexceptionhandling policy.TheconfigurationtoolautomaticallyaddstheLoggingApplicationBlocktotheconfigurationwith asetofdefaultpropertiesthatwillwritelogentriestoWindowsApplicationEventLog.Youdoneedto setafewpropertiesoftheLogginghandler: TheIDforthelogeventyourcodewillgenerate. Thetypeofformattertouse.Clicktheellipses(...)buttonintheFormatterTypepropertyand selecttheTextFormattertypeinthedialogthatappears. Thecategoryforthelogevent.TheLoggingblockcontainsadefaultcategorynamedGeneral, andyoucanselectthisfromthedropdownlistthatisavailablewhenyouclickonthe LogCategorypropertyoftheLogginghandler.

Policyname:LoggingAndReplacingException]

AGuidetoDevelopingwithEnterpriseLibrary5.0

75

[Awaitingnewimage] Theconfigurationtooladdsnewexceptionhandlerstotheendofthehandlerchainbydefault. However,youwillobviouslywanttologthedetailsoftheoriginalexceptionratherthanthenew exceptionthatreplacesit,andsoyoumustusetheshortcutmenutomovetheLogginghandlerupto thefirstpositioninthechainofhandlers. Inaddition,ifyoudidnotalreadydoso,youmustaddareferencetotheLoggingApplicationBlock assemblytoyourprojectand(optionally)addausingorImportsstatementtoyourclass,asshownhere.


usingMicrosoft.Practices.EnterpriseLibrary.Logging;

Now,whentheapplicationcausesanexception,theglobalexceptionhandlercontinuestodisplaythe samesanitizederrormessage.However,theLogginghandlercapturesdetailsoftheoriginalexception beforetheExceptionHandlingblockpolicyreplacesit,andwritesthedetailstowhicheverloggingsink youspecifyintheconfigurationfortheLoggingApplicationBlockWindows.Thedefaultinthisexample isWindowsApplicationEventLog.Ifyouselecttheoption[D]"LogginganExceptiontoPreservethe InformationitContains"intheexampleapplication,youwillseeanexceptionlikethefollowing generated.

AGuidetoDevelopingwithEnterpriseLibrary5.0

76

ThisexampleshowsExceptionHandlingblockusingthedefaultsettingsfortheLoggingblock.However, asyoucanseeinChapter4,"AsEasyAsFallingOffaLog",theLoggingblockisextremelyconfigurable. SoyoucanarrangefortheLogginghandlerinyourexceptionhandlingpolicytowritetheinformationto anyWindowsEventLog,anemailmessage,adatabase,amessagequeue,atextfile,aWindows ManagementInstrumentation(WMI)event,oracustomlocationusingclassesyoucreatethattake advantageoftheapplicationblockextensionpoints.

3.7.1 AvoidingDuplicateLogging
[TBD][Needtodescribeastrategytodealwithasituationwhenthecallerhasnowayofknowing whethertheexceptionhasbeenloggedornotevenwithinthesametier,whichmaypotentiallyresultin doublelogging.EvenworseisifthecallerdoesnothaveaccesstotheuniqueIDgeneratedduringthe initiallogging.Whatsourrecommendationhere?Whatsthewaytocrossreference?]

AGuidetoDevelopingwithEnterpriseLibrary5.0

77

3.8

ShieldingExceptionsatWCFServiceBoundaries

YoucanusetheExceptionHandlingblocktoimplementexceptionhandlingpoliciesforWindows CommunicationFoundation(WCF)services.AcommonscenarioistoimplementtheExceptionShielding patternataWCFserviceboundary.TheExceptionHandlingblockcontainsahandlerspecifically designedforthis,whichmapsthevaluesintheexceptiontoanewinstanceofafaultcontractthatyou specify.

3.8.1 CreatingaFaultContract
AfaultcontractforaWCFservicewillgenerallycontainjustthemostusefulpropertiesforanexception, andexcludesensitiveinformationsuchasthestacktraceandanythingelsethatmayprovideattackers withusefulinformationabouttheinternalworkingsoftheservice.Thefollowingcodeshowsasimple exampleofafaultcontractsuitableforusewiththeFaultContractexceptionhandler:
[DataContract] publicclassSalaryCalculationFault { [DataMember] publicGuidFaultID{get;set;} [DataMember] publicstringFaultMessage{get;set;} }

3.8.2 ConfiguringtheExceptionHandlingPolicy
ThefollowingfigureshowsasampleconfigurationfortheFaultContractexceptionhandler.This specifiesthetypeSalaryCalculationFaultasthetargetfaultcontracttype,andtheexceptionmessage thatthepolicywillgeneratetosendtotheclient.Notethat,whenusingtheFaultContractexception handler,youshouldalwayssetthePostHandlingActionpropertytoThrowNewExceptionsothatthe ExceptionHandlingblockthrowsanexceptionthatforcesWCFtoreturnthefaultcontracttotheclient. [Policyname:SalaryServicePolicy]

[Awaitingnewimage]

AGuidetoDevelopingwithEnterpriseLibrary5.0

78

3.8.3 EditingtheServiceCodetoUsetheNewPolicy
AfteryouspecifyyourfaultcontractandconfiguretheFaultContractexceptionhandler,youmustedit yourservicecodetousethenewexceptionpolicy.Ifyoudidnotalreadydoso,youmustalsoadda referencetotheassemblythatcontainstheFaultContractexceptionhandlertoyourprojectand (optionally)addausingorImportsstatementtoyourserviceclassasshownhere:
UsingMicrosoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF;

YoucannowcalltheProcessmethodoftheExceptionManagerclassfromcodeinyourservicein exactlythesamewayasshowninthepreviousexamplesofwrappingandreplacingexceptionsina WindowsFormsapplication.Alternatively,youcanaddattributestothemethodsinyourserviceclassto specifythepolicytheyshouldusewhenanexceptionoccurs,asshowninthiscode:


[ServiceContract] publicinterfaceISalaryService { [OperationContract] [FaultContract(typeof(SalaryCalculationFault))] decimalGetWeeklySalary(stringemployeeId,intweeks); } [ExceptionShielding("SalaryServicePolicy")] publicclassSalaryService:ISalaryService { publicdecimalGetWeeklySalary(stringemployeeId,intweeks) { SalaryCalculatorcalc=newSalaryCalculator(); returncalc.GetWeeklySalary(employeeId,weeks); } }

YouaddtheExceptionShieldingattributetoaserviceimplementationclassortoaservicecontract interface,anduseittospecifythenameoftheexceptionpolicytouse.Ifyoudonotspecifythenameof apolicyintheconstructorparameter,orifthespecifiedpolicyisnotdefinedinconfiguration,the ExceptionHandlingblockwillautomaticallylookforapolicynamed"WCFExceptionShielding".

3.8.4 WhattheFaultContractExceptionHandlerDoes
TheExceptionHandlingblockexecutestheFaultMappingexceptionhandlerthatyouspecifyinyour policywhenanexceptionoccurs.Effectively,theFaultContracthandlerisaspecializedversionofthe Replacehandler.Ittakestheoriginalexception,generatesaninstanceofthefaultcontract,populatesit withvaluesfromtheexception,andthenthrowsaFaultException<YourFaultContractType>exception. Thehandlerperformsthefollowingactions: ItgeneratesanewinstanceofthefaultcontractclassyouspecifyfortheFaultContractType propertyoftheFaultMappingexceptionhandler. Itextractsthevaluesfromthepropertiesoftheexceptionthatyoupasstothemethod. 79

AGuidetoDevelopingwithEnterpriseLibrary5.0

Itsetsthevaluesofthenewfaultcontractinstancetothevaluesextractedfromtheoriginal exception.Itusesmappingsbetweentheexceptionpropertynamesandthenamesofthe propertiesexposedbythefaultcontracttoassigntheexceptionvaluestotheappropriate properties.Ifyoudonotspecifyamapping,itmatchesthesourceandtargetpropertiesthat havethesamename.

Theresultisthat,insteadofageneralservicefailuremessage,theclientreceivesafaultmessage containingtheappropriateinformationabouttheexception. Option[E]"ApplyingExceptionShieldingatWCFApplicationBoundaries"intheexampleapplicationuses theservicedescribedaboveandtheExceptionHandlingBlockWCFFaultContracthandlerto demonstrateexceptionshielding.ItincludesmappingsdefinedintheconfigurationfilefortheWCF servicethatmapthemessagefromtheexceptiongeneratedwithintheservicetotheFaultMessage propertyoftheSalaryCalculationFaultclass,andmaptheuniqueHandlingInstanceIDoftheexception (specifiedbysettingtheSourceto"{Guid}")totheFaultIDproperty. Youcanrunthisexampleinoneofthreeways: InsideVisualStudiobystartingitwithF5(debuggingmode)andthenpressingF5againwhen thedebuggerhaltsattheexceptionintheSalaryCalculatorclass. InsideVisualStudiobyrightclickingSalaryService.svcinSolutionExplorerandselectingViewin Browsertostarttheservice,thenpressingCtrlF5(nondebuggingmode)toruntheapplication. BystartingtheSalaryServiceinVisualStudio(asdescribedinpreviousbullet)andthenrunning theexecutablefileExceptionHandlingExample.exeinthebin\debugfolderdirectly.

Theresultisshownbelow.YoucanseethattheexceptionraisedbytheSalaryCalculatorclasscauses theservicetoreturnaninstanceoftheSalaryCalculationFaulttypethatcontainsthefaultIDandfault message.However,theExceptionHandlingblockcapturesthisexceptionandreplacesthesensitive informationinthemessagewithonethatsuggeststheusercontacttheiradministrator.Researchshows thatusersreallyappreciatethistypeofinformativeerrormessage.


Gettingsalaryfor'jsmith'fromWCFSalaryService... ExceptiontypeSystem.ServiceModel.FaultException`1[ExceptionHandlingExample.Sal aryService.SalaryCalculationFault]wasthrown. Message:'Serviceerror.Pleasecontactyouradministrator.' Source:'mscorlib' NoInnerException Faultcontractdetail: FaultID:bafb7ec2ed054036b4d556d6af9046a5 FaultMessage:ErrorcalculatingsalaryforJohnSmith.Salary:1000000.Weeks: 0 Connection:Database=Employees;Server=CorpHQ;UserID=admin;Password=2g$tXD76qr Attemptedtodividebyzero.

AGuidetoDevelopingwithEnterpriseLibrary5.0

80

Youcanalsoseebelowthedetailsoftheexceptionraisedthecontentsoftheoriginalfaultcontract, whichareobtainedbycastingtheexceptiontothetypeFaultException<SalaryCalculationFault>and queryingtheproperties.Youcanseethatthiscontainstheoriginalexceptionmessagegeneratedwithin theservice.Lookatthecodeintheexamplefile,andrunit,toseemoredetails.

3.9

HandlingSpecificExceptionTypes

Sofar,alloftheexampleshaveusedanexceptionpolicythathandlesasingleexceptiontype(inthe examples,thisisExceptionsothatthepolicywillapplytoanytypeofexceptionpassedtoit).However, youcanspecifymultipleexceptiontypeswithinapolicy,andspecifydifferenthandlersincludingchains ofhandlersforeachexceptiontype.Thefollowingfigureshowsasectionoftheconfigurationconsole withthreeexceptiontypesdefinedforthepolicynamedNotifyingRethrow(whichisusedinthenext example).Eachexceptiontypehasdifferentexceptionhandlersspecified. [Policyname:NotifyingRethrow]

[Awaitingnewimage] Theadvantageofthiscapabilityshouldbeobvious.Youcancreatepoliciesthatwillhandledifferent typesofexceptionsindifferentwaysand,foreachexceptiontype,canhavedifferentmessagesand posthandlingactionsaswellasdifferenthandlercombinations.And,bestofall,administratorscan modifythepoliciespostdeploymenttochangethebehavioroftheexceptionhandlingasrequired.They canaddnewexceptiontypes,modifythetypesspecified,changethepropertiesforeachexceptiontype andtheassociatedhandlers,andgenerallyfinetunethestrategytosuitdaytodayoperational requirements. Ofcourse,thiswillonlyworkifyourapplicationcodethrowstheappropriateexceptiontypes.Ifyou generateinformationalexceptionsthatareallofthebasetypeException,aswedidinearlierexamples inthischapter,onlythehandlersforthatexceptiontypewillexecute.

3.10

ExecutingCodearoundExceptionHandling

Sofar,alloftheexampleshaveusedtheProcessmethodtoexecutethecodethatmaycausean exception.TheysimplyusedtheProcessmethodtoexecutethetargetclassmethodasshownhere. AGuidetoDevelopingwithEnterpriseLibrary5.0 81

exManager.Process(()=> { SalaryCalculatorcalc=newSalaryCalculator(); Console.WriteLine("Resultis:{0}",calc.GetWeeklySalary("jsmith",0)); }, "ExceptionPolicyName");

However,asyousawearlierinthischapter,theProcessmethoddoesnotallowyoutodetectthereturn valuefromtheexceptionhandlingpolicyexecutedbytheExceptionHandlingblock.Insomecases, thoughperhapsrare,youmaywanttodetectthereturnvalueandperformsomeprocessingbasedon thisvalue,andperhapsevencapturetheexceptionreturnedbytheExceptionHandlingblockto manipulateitordecidewhetherornottothrowitinyourcode. Inthiscase,youcanusetheHandleExceptionmethodtopassanexceptiontotheblockasanout parametertobepopulatedbythepolicy,andretrievetheBooleanresultthatindicatesifthepolicy determinedthattheexceptionshouldbethrownorignored. Theexample[F],"ExecutingCustomCodeBeforeandAfterHandlinganException",demonstratesthis approach.TheSalaryCalculatorclasscontainstwomethodsinadditiontotheGetWeeklySalarymethod weveusedsofarinthischapter.Thesetwomethods,namedRaiseDivideByZeroExceptionand RaiseArgumentOutOfRangeException,willcauseanexceptionofthetypeindicatedbythemethod namewhencalled. ThesamplefirstattemptstoexecutetheRaiseDivideByZeroExceptionmethod,likethis. C#
SalaryCalculatorcalc=newSalaryCalculator(); Console.WriteLine("Resultis:{0}",calc.RaiseDivideByZeroException("jsmith",0));

VisualBasic
{Insertcodehere}

Thisexceptioniscaughtinthemainroutineusingtheexceptionhandlingcodeshownbelow.This createsanewExceptioninstanceandpassesittotheExceptionHandlingblockastheoutparameter, specifyingthattheblockshouldusetheNotifyingRethrowpolicy.Thispolicyspecifiesthattheblock shouldlogDivideByZeroexceptions,andreplacethemessagewithasanitizedone.However,italsohas thePostHandlingActionsettoNone,whichmeansthattheHandleExceptionmethodwillreturnfalse. Thesamplecodesimplydisplaysamessageandcontinues.


... catch(Exceptionex) { ExceptionnewException; boolrethrow=exManager.HandleException(ex,"NotifyingRethrow", outnewException); if(rethrow) { //Exceptionpolicysettingis"ThrowNewException".

AGuidetoDevelopingwithEnterpriseLibrary5.0

82

//Codeheretoperformanycleanuptasksrequired. //Thenthrowtheexceptionreturnedbytheexceptionhandlingpolicy. thrownewException; } else { //Exceptionpolicysettingis"None"soexceptionisnotthrown. //Codeheretoperformanyotherprocessingrequired. //Inthisexample,justignoretheexceptionanddonothing. Console.WriteLine("DetectedandignoredDivideByZeroError" +"novaluereturned."); } }

Therefore,whenyouexecutethissample,itdisplaysthefollowingmessage.
Gettingsalaryfor'jsmith'...thiswillraiseaDivideByZeroexception. DetectedandignoredDivideByZeroErrornovaluereturned.

ThesamplethencontinuesbyexecutingtheRaiseArgumentOutOfRangeExceptionmethodofthe SalaryCalculatorclass,likethis.
SalaryCalculatorcalc=newSalaryCalculator(); Console.WriteLine("Resultis:{0}", calc.RaiseArgumentOutOfRangeException("jsmith",0));

ThissectionofthesamplealsocontainsaCatchsection,whichisotherthanthemessagedisplayedto thescreenidenticaltothatshownearlier.However,theNotifyingRethrowpolicyspecifiesthat exceptionsoftypeException(oranyexceptionsthatarenotoftypeDivideByZeroException)should simplybewrappedinanewexceptionthathasasanitizederrormessage.ThePostHandlingActionfor theExceptiontypeissettoThrowNewException,whichmeansthattheHandleExceptionmethodwill returntrue.Thereforethecodeinthecatchblockwillthrowtheexceptionreturnedfromtheblock, resultingintheoutputshownhere.


Gettingsalaryfor'jsmith'...thiswillraiseanArgumentOutOfRangeexception. ExceptiontypeSystem.Exceptionwasthrown. Message:'Anapplicationerrorhasoccurred.' Source:'ExceptionHandlingExample' InnerException:System.ArgumentOutOfRangeException:startIndexcannotbelarger thanlengthofstring. Parametername:startIndex atSystem.String.InternalSubStringWithChecks(Int32startIndex,Int32length, BooleanfAlwaysCopy) atSystem.String.Substring(Int32startIndex,Int32length) atExceptionHandlingExample.SalaryCalculator.RaiseArgumentOutOfRangeException (StringemployeeId,Int32weeks)inE:\Projects\EntLib5\Guides\DevGuide\CodeCS\ ExceptionHandling\ExceptionHandling\SalaryCalculator.cs:line57 atExceptionHandlingExample.Program.ExecutingCodeAroundException(Int32positi

AGuidetoDevelopingwithEnterpriseLibrary5.0

83

onInTitleArray)inE:\Projects\EntLib5\Guides\DevGuide\CodeCS\ExceptionHandling \ExceptionHandling\Program.cs:line222

3.11

AssistingAdministrators

SomewouldsaythattheExceptionHandlingblockalreadydoesplentytomakeadministrators'lifeeasy. However,italsocontainsfeaturesthatallowyoutoexertextracontroloverthewaythatexception informationismadeavailable,andthewaythatitcanbeusedbyadministratorsandoperationsstaff.If youhaveeverworkedinatechnicalsupportrole,you'llrecognizethescenario.Ausercallstotellyou thatanerrorhasoccurredintheapplication.Ifyouarelucky,theuserwillbeabletotellyouexactly whattheyweredoingatthetime,andtheexacttextoftheerrormessage.Morelikely,heorshewilltell youthatthey"weren'tdoinganythingreally",andthatthemessagesaid"somethingaboutcontacting theadministrator". Toresolvethisregularoccurringproblem,youcanmakeuseoftheHandlingInstanceIDvaluegenerated bytheblocktoassociateloggedexceptiondetailswithspecificexceptions,andwithrelatedexceptions. TheExceptionHandlingblockcreatesauniqueGUIDvaluefortheHandlingInstanceIDofevery executionofapolicy.Thevalueisavailabletoallofthehandlersinthepolicywhilethatpolicyis executing.TheLogginghandlerautomaticallywritestheHandlingInstanceIDvalueintoeverylog messageitcreates.TheWrapandReplacehandlerscanaccesstheHandlingInstanceIDvalueand includeitinamessageusingthespecialtoken{handlingInstanceID}. ThefollowingfigureshowshowyoucanconfigureaLogginghandlerandaReplacehandlerinapolicy, andincludethe{handlingInstanceID}tokenintheExceptionMessagepropertyoftheReplacehandler. [Policyname:AssistingAdministrators]

[Awaitingnewimage] Nowyourapplicationcandisplaytheuniqueexceptionidentifiertotheuser,andtheycanpassittothe administratorwhocanuseittoidentifythematchingloggedexceptioninformation.Thislogged informationwillincludetheinformationfromtheoriginalexception,beforetheReplacehandler replaceditwiththesanitizedexception.Ifyouselecttheoption[G]"ProvidingAssistanceto

AGuidetoDevelopingwithEnterpriseLibrary5.0

84

AdministratorsforLocatingExceptionDetails"intheexampleapplication,youcanseethisinoperation. Theexampledisplaysthefollowingdetailsoftheexceptionreturnedfromtheexceptionhandlingpolicy:
ExceptiontypeSystem.Exceptionwasthrown. Message:'Applicationerror.Pleaseadviseyouradministratorandprovidethem withthiserrorcode:22f759d38f5843dc9adc93b953a4f733' Source:'Microsoft.Practices.EnterpriseLibrary.ExceptionHandling'

Inaproductionapplication,youwillprobablyshowthismessageinadialogofsometype.Oneissue, however,isthatusersmaynotcopytheGUIDcorrectlyfromastandarderrordialog(suchasamessage box).IfyoudecidetousetheHandlingInstanceIDvaluetoassistadministrators,considerusingaform containingareadonlytextbox,oranerrorpageinaWebapplication,todisplaytheGUIDvalueina waythatallowsuserstocopyittotheclipboardandpasteintoadocumentoremailmessage.The followingfigureshowsasimpleWindowsFormdisplayedasamodaldialog.Itcontainsareadonly TextBoxcontrolthatdisplaystheMessagepropertyoftheexception,whichcontainsthe HandlingInstanceIDGUIDvalue.

AGuidetoDevelopingwithEnterpriseLibrary5.0

85

3.12

ExtendingyourExceptionHandling

LikealloftheEnterpriseLibraryapplicationblocks,theExceptionHandlingblockisextensible.Youcan createnewexceptionhandlersandexceptionformattersifyouneedtoperformspecifictasksthatthe blockdoesnotimplementbydefault.Forexample,youcouldcreateanexceptionhandlerthatdisplays theexceptiondetailsinadialog,createsandXMLmessage,orgeneratesaWebpage.Allthatisrequired istoimplementtheIExceptionHandlerinterfacedefinedwithintheblock.Thisinterfacecontainsone methodnamedHandleExceptionthattheExceptionHandlingblockwillexecutewhenyouaddyour handlertoapolicychain. TheExceptionHandlingblockusesformatterstocreatethemessagesenttotheLoggingblockwhenyou useaLogginghandler.ThetwoformattersprovidedaretheTextExceptionFormatterandthe XmlExceptionFormatter.TheTextExceptionFormattergeneratesasimpletextformatfortheerror message,asyouhaveseenintheprevioussectionsofthischapter(suchasinFigure13).The TextExceptionFormattergenerates,asyouwillexpect,anXMLformatteddocumentastheerror message.Youcancreatecustomformattersifyouwanttocontroltheexactformatofthisinformation. YousimplycreateanewclassthatderivesfromtheExceptionFormatterbaseclassintheException Handlingblock,andoverridetheseveralmethodsitcontainsforformattingtheexceptioninformation asrequired.

3.13

Summary

Inthischapteryouhaveseenwhy,when,andhowyoucanusetheEnterpriseLibraryException Handlingblocktocreateandimplementexceptionhandlingstrategies.Poorerrorhandlingcanmake yourapplicationdifficulttomanageandmaintain,hardtodebugandtest,andmayallowittoexpose sensitiveinformationusefultoattackersandmalicioususers. Goodpracticeforexceptionmanagementistoimplementstrategiesthatprovideacontrolledand decoupledapproachtoexceptionhandlingthroughconfigurablepolicies.TheExceptionHandlingblock makesiteasytoimplementsuchstrategiesforyourapplications,irrespectiveoftheirtypeand complexity.YoucanusetheExceptionHandlingblockinWebandWindowsFormsapplications,Web services,consolebasedapplicationsandutilities,andeveninadministrationscriptsandapplications hostedinenvironmentssuchasSharePoint,MicrosoftOfficeapplications,otherenterprisesystems. Thischapterdemonstratedhowyoucanimplementcommonexceptionhandlingpatternssuchas ExceptionShielding,usingtechniquessuchaswrapping,replacing,andloggingexceptions.Italso demonstratedhowyoucanhandledifferenttypesofexceptions,assistadministratorsbyusingunique exceptionidentifiers,andextendtheExceptionHandlingblocktoperformtasksthatarespecifictoyour ownrequirements.

AGuidetoDevelopingwithEnterpriseLibrary5.0

86

Additionalchapters availableonline
EntLib.codeplex.com
Yourfeedbackisinvited!

Das könnte Ihnen auch gefallen