Beruflich Dokumente
Kultur Dokumente
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
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
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
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
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.
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
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.
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>
AGuidetoDevelopingwithEnterpriseLibrary5.0
18
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.
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>();
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.
AGuidetoDevelopingwithEnterpriseLibrary5.0
24
AGuidetoDevelopingwithEnterpriseLibrary5.0
25
AGuidetoDevelopingwithEnterpriseLibrary5.0
26
propertyinjectionforaclassnamedMyNewObjectthatexposesasapropertyareferencetoan instanceoftheEnterpriseLibraryCacheManagerclass.
publicclassMyNewObject { [Dependency] publicCacheManagerDefaultCache{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
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?
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
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.
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.
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?
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
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;
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); }
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
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); } }
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.
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
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
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;
AGuidetoDevelopingwithEnterpriseLibrary5.0
42
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
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>
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.
AGuidetoDevelopingwithEnterpriseLibrary5.0
46
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);
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
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);
AGuidetoDevelopingwithEnterpriseLibrary5.0
52
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);
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
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
AGuidetoDevelopingwithEnterpriseLibrary5.0
60
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
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
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?
3.4
WhatExceptionPoliciesDoINeed?
AGuidetoDevelopingwithEnterpriseLibrary5.0
65
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.
AGuidetoDevelopingwithEnterpriseLibrary5.0
66
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.
AGuidetoDevelopingwithEnterpriseLibrary5.0
69
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
3.5
WrappinganException
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;
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; }
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
[Awaitingnewimage] AGuidetoDevelopingwithEnterpriseLibrary5.0 74
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
AGuidetoDevelopingwithEnterpriseLibrary5.0
76
3.7.1 AvoidingDuplicateLogging
[TBD][Needtodescribeastrategytodealwithasituationwhenthecallerhasnowayofknowing whethertheexceptionhasbeenloggedornotevenwithinthesametier,whichmaypotentiallyresultin doublelogging.EvenworseisifthecallerdoesnothaveaccesstotheuniqueIDgeneratedduringthe initiallogging.Whatsourrecommendationhere?Whatsthewaytocrossreference?]
AGuidetoDevelopingwithEnterpriseLibrary5.0
77
3.8
ShieldingExceptionsatWCFServiceBoundaries
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;
3.8.4 WhattheFaultContractExceptionHandlerDoes
TheExceptionHandlingblockexecutestheFaultMappingexceptionhandlerthatyouspecifyinyour policywhenanexceptionoccurs.Effectively,theFaultContracthandlerisaspecializedversionofthe Replacehandler.Ittakestheoriginalexception,generatesaninstanceofthefaultcontract,populatesit withvaluesfromtheexception,andthenthrowsaFaultException<YourFaultContractType>exception. Thehandlerperformsthefollowingactions: ItgeneratesanewinstanceofthefaultcontractclassyouspecifyfortheFaultContractType propertyoftheFaultMappingexceptionhandler. Itextractsthevaluesfromthepropertiesoftheexceptionthatyoupasstothemethod. 79
AGuidetoDevelopingwithEnterpriseLibrary5.0
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.
AGuidetoDevelopingwithEnterpriseLibrary5.0
80
3.9
HandlingSpecificExceptionTypes
[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
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}
AGuidetoDevelopingwithEnterpriseLibrary5.0
82
Therefore,whenyouexecutethissample,itdisplaysthefollowingmessage.
Gettingsalaryfor'jsmith'...thiswillraiseaDivideByZeroexception. DetectedandignoredDivideByZeroErrornovaluereturned.
ThesamplethencontinuesbyexecutingtheRaiseArgumentOutOfRangeExceptionmethodofthe SalaryCalculatorclass,likethis.
SalaryCalculatorcalc=newSalaryCalculator(); Console.WriteLine("Resultis:{0}", calc.RaiseArgumentOutOfRangeException("jsmith",0));
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]
AGuidetoDevelopingwithEnterpriseLibrary5.0
84
AdministratorsforLocatingExceptionDetails"intheexampleapplication,youcanseethisinoperation. Theexampledisplaysthefollowingdetailsoftheexceptionreturnedfromtheexceptionhandlingpolicy:
ExceptiontypeSystem.Exceptionwasthrown. Message:'Applicationerror.Pleaseadviseyouradministratorandprovidethem withthiserrorcode:22f759d38f5843dc9adc93b953a4f733' Source:'Microsoft.Practices.EnterpriseLibrary.ExceptionHandling'
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!