[Link] [Link][Link]
WorkingwithDatainASP.NET2.0::Includinga FileUploadOptionWhenAddingaNewRecord Introduction
Intheprevioustwotutorialsweexploredtechniquesforstoringbinarydatathatisassociatedwiththeapplications datamodel,lookedathowtousetheFileUploadcontroltosendfilesfromtheclienttothewebserver,andsaw [Link] thedatamodel,though. [Link] anddescription,thispagewillneedtoincludetwoFileUploadcontrolsoneforthenewcategoryspictureand [Link] column,whereas thebrochurewillbesavedtothe~/Brochures folderwiththepathtothefilesavedinthenewrecords BrochurePath column. Beforecreatingthisnewwebpage,[Link] querydoesnotretrievethePicture [Link],theautogeneratedInsert methodonlyhasinputsfor theCategoryName,Description,andBrochurePath [Link],weneedtocreateanadditionalmethodin theTableAdapterthatpromptsforallfourCategories [Link] classintheBusinessLogic Layerwillalsoneedtobeupdated.
Step1:AddinganInsertWithPicture Methodtothe
CategoriesTableAdapter
WhenwecreatedtheCategoriesTableAdapter backintheCreatingaDataAccessLayer tutorial,weconfigured ittoautomaticallygenerateINSERT,UPDATE,andDELETE [Link],we instructedtheTableAdaptertoemploytheDBDirectapproach,whichcreatedthemethodsInsert,Update,and [Link],UPDATE,andDELETE statementsand,consequently, [Link] augmentedtheCategoriesTableAdaptersmainquerytousetheBrochurePath column. SincetheCategoriesTableAdaptersmainquerydoesnotreferencethePicture column,wecanneitheradda newrecordnorupdateanexistingrecordwithavalueforthePicture [Link], wecaneithercreateanewmethodintheTableAdapterthatisusedspecificallytoinsertarecordwithbinarydata orwecancustomizetheautogeneratedINSERT [Link] INSERT [Link],imaginethat wecustomizedtheINSERT statementtoincludeuseofthePicture [Link] Insert [Link] createamethodintheBusinessLogicLayertousethisDALmethodandinvokethisBLLmethodthroughthe PresentationLayer,[Link],untilthenexttimeweconfiguredthe [Link],our customizationstotheINSERT statementwouldbeoverwritten,theInsert methodwouldreverttoitsoldform,and ourcodewouldnolongercompile! Note:ThisannoyanceisanonissuewhenusingstoredproceduresinsteadofadhocSQLstatements.A
1 of17
futuretutorialwillexploreusingstoredproceduresinlieuofadhocSQLstatementsintheDataAccess Layer. Toavoidthispotentialheadache,ratherthancustomizingtheautogeneratedSQLstatementsletsinsteadcreatea [Link],namedInsertWithPicture,willacceptvaluesforthe CategoryName,Description,BrochurePath,andPicture columnsandexecuteanINSERT statementthatstores allfourvaluesinanewrecord. OpentheTypedDataSetand,fromtheDesigner,rightclickontheCategoriesTableAdaptersheaderand [Link],which [Link] [Link] recordtotheCategories table,chooseINSERTandclickNext.
Figure1:SelecttheINSERTOption
WenowneedtospecifytheINSERT [Link] statement [Link],itsanINSERT statementthatinsertsthe CategoryName,Description,andBrochurePath [Link] columnis includedalongwitha@Picture parameter,likeso:
INSERTINTO[Categories] ([CategoryName],[Description],[BrochurePath],[Picture]) VALUES (@CategoryName,@Description,@BrochurePath,@Picture)
2 of17
[Link] andclick Finish.
Figure2:NametheNewTableAdapterMethodInsertWithPicture
Step2:UpdatingtheBusinessLogicLayer
SincethePresentationLayershouldonlyinterfacewiththeBusinessLogicLayerratherthanbypassingittogo directlytotheDataAccessLayer,weneedtocreateaBLLmethodthatinvokestheDALmethodwejustcreated (InsertWithPicture).Forthistutorial,createamethodintheCategoriesBLL classnamedInsertWithPicture thatacceptsasinputthreeStringsandaByte [Link] inputparametersareforthecategorysname, description,andbrochurefilepath,whiletheByte [Link] followingcodeshows,thisBLLmethodinvokesthecorrespondingDALmethod:
<[Link].DataObjectMethodAttribute_ ([Link],False)>_ PublicSubInsertWithPicture(categoryNameAsString,descriptionAsString,_ brochurePathAsString,picture()AsByte) [Link](categoryName,description,brochurePath,picture) EndSub
Note:MakesurethatyouhavesavedtheTypedDataSetbeforeaddingtheInsertWithPicture methodto [Link] classcodeisautogeneratedbasedontheTypedDataSet,if youdontfirstsaveyourchangestotheTypedDataSettheAdapter propertywontknowaboutthe
3 of17
InsertWithPicture method.
Step3:ListingtheExistingCategoriesandtheirBinaryData
Inthistutorialwewillcreateapagethatallowsanendusertoaddanewcategorytothesystem,providinga [Link] weusedaGridViewwithaTemplateFieldand ImageFieldtodisplayeachcategorysname,description,picture,[Link] replicatethatfunctionalityforthistutorial,creatingapagethatbothlistsallexistingcategoriesandallowsfornew onestobecreated. [Link] pagefromtheBinaryData [Link] copytheGridViewandObjectDataSourcesdeclarativesyntax,pastingitwithinthe<asp:Content> elementin [Link],dontforgettocopyoverthe GenerateBrochureLink methodfromthecode [Link] [Link].
Figure3:[Link] to
[Link]
AftercopyingthedeclarativesyntaxandGenerateBrochureLink methodovertothe [Link] page,viewthepagethroughabrowsertoensurethateverythingwascopiedover [Link] wellasthecategoryspicture.
4 of17
Figure4:YouShouldNowSeeEachCategoryAlongwithItsBinaryData
Step4:ConfiguringtheCategoriesDataSource toSupportInserting
TheCategoriesDataSource ObjectDataSourceusedbytheCategories GridViewcurrentlydoesnotprovidethe [Link],weneedtomapitsInsert methodtoamethodinitsunderlyingobject,[Link],wewanttomapittothe CategoriesBLL methodweaddedbackinStep2,InsertWithPicture . [Link] objectthedatasourceisconfiguredtoworkwith,[Link] [Link] method [Link].
5 of17
Figure5:ConfiguretheObjectDataSourcetousetheInsertWithPicture Method
Note:Uponcompletingthewizard,VisualStudiomayaskifyouwanttoRefreshFieldsandKeys,which [Link],becausechoosingYeswilloverwriteanyfield customizationsyoumayhavemade. Aftercompletingthewizard,theObjectDataSourcewillnowincludeavalueforitsInsertMethod propertyaswell asInsertParameters forthefourcategorycolumns,asthefollowingdeclarativemarkupillustrates:
<asp:ObjectDataSourceID="CategoriesDataSource"runat="server" OldValuesParameterFormatString="original_{0}"SelectMethod="GetCategories" TypeName="CategoriesBLL"InsertMethod="InsertWithPicture"> <InsertParameters> <asp:ParameterName="categoryName"Type="String"/> <asp:ParameterName="description"Type="String"/> <asp:ParameterName="brochurePath"Type="String"/> <asp:ParameterName="picture"Type="Object"/> </InsertParameters> </asp:ObjectDataSource>
Step5:CreatingtheInsertingInterface
AsfirstcoveredintheAnOverviewofInserting,Updating,andDeletingData,theDetailsViewcontrolprovidesa builtininsertinginterfacethatcanbeutilizedwhenworkingwithadatasourcecontrolthatsupportsinserting. LetsaddaDetailsViewcontroltothispageabovetheGridViewthatwillpermanentlyrenderitsinserting interface,[Link],the 6 of17
GridViewbeneathitwillautomaticallyrefreshanddisplaythenewcategory. StartbydraggingaDetailsViewfromtheToolboxontotheDesignerabovetheGridView,settingitsID propertyto NewCategory andclearingouttheHeight andWidth [Link],binditto theexistingCategoriesDataSource andthenchecktheEnableInsertingcheckbox.
Figure6:BindtheDetailsViewtotheCategoriesDataSource andEnableInserting
TopermanentlyrendertheDetailsViewinitsinsertinginterface,setitsDefaultMode propertytoInsert. NotethattheDetailsViewhasfiveBoundFieldsCategoryID,CategoryName,Description, NumberOfProducts,andBrochurePath althoughtheCategoryID BoundFieldisnotrenderedintheinserting interfacebecauseitsInsertVisible [Link] columnsreturnedbytheGetCategories() method,whichiswhattheObjectDataSourceinvokestoretrieveits [Link],however,[Link],we needtoallowthemtouploadapictureforthenewcategoryaswellasuploadaPDFforthebrochure. RemovetheNumberOfProducts BoundFieldfromtheDetailsViewaltogetherandthenupdatetheHeaderText propertiesoftheCategoryName andBrochurePath BoundFieldstoCategoryand Brochure, respectively. Next,converttheBrochurePath BoundFieldintoaTemplateFieldandaddanewTemplateFieldforthepicture, givingthisnewTemplateFieldaHeaderText valueof Picture. MovethePicture TemplateFieldsothatitis betweentheBrochurePath TemplateFieldandCommandField.
7 of17
Figure7:BindtheDetailsViewtotheCategoriesDataSource andEnableInserting
IfyouconvertedtheBrochurePath BoundFieldintoaTemplateFieldthroughtheEditFieldsdialogbox,the TemplateFieldincludesanItemTemplate,EditItemTemplate,[Link] InsertItemTemplate isneeded,however,[Link] DetailsViewsdeclarativesyntaxshouldlooklikethefollowing:
<asp:DetailsViewID="NewCategory"runat="server"AutoGenerateRows="False" DataKeyNames="CategoryID"DataSourceID="CategoriesDataSource" DefaultMode="Insert"> <Fields> <asp:BoundFieldDataField="CategoryID"HeaderText="CategoryID" InsertVisible="False"ReadOnly="True" SortExpression="CategoryID"/> <asp:BoundFieldDataField="CategoryName"HeaderText="Category" SortExpression="CategoryName"/> <asp:BoundFieldDataField="Description"HeaderText="Description" SortExpression="Description"/> <asp:TemplateFieldHeaderText="Brochure"SortExpression="BrochurePath"> <InsertItemTemplate> <asp:TextBoxID="TextBox1"runat="server" Text='<%#Bind("BrochurePath")%>'></asp:TextBox> </InsertItemTemplate> </asp:TemplateField> <asp:TemplateFieldHeaderText="Picture"></asp:TemplateField> <asp:CommandFieldShowInsertButton="True"/> </Fields> </asp:DetailsView>
8 of17
AddingFileUploadControlsfortheBrochureandPictureFields
Presently,theBrochurePath TemplateFieldsInsertItemTemplate containsaTextBox,whilethePicture [Link] InsertItemTemplatestouseFileUploadcontrols. FromtheDetailsViewssmarttag,choosetheEditTemplates optionandthenselecttheBrochurePath TemplateFieldsInsertItemTemplate [Link] [Link] [Link],adda FileUploadcontroltothePicture [Link] to PictureUpload.
Figure8:AddaFileUploadControltotheInsertItemTemplate
Aftermakingtheseadditions,thetwoTemplateFieldsdeclarativesyntaxwillbe:
<asp:TemplateFieldHeaderText="Brochure"SortExpression="BrochurePath"> <InsertItemTemplate> <asp:FileUploadID="BrochureUpload"runat="server"/> </InsertItemTemplate> </asp:TemplateField> <asp:TemplateFieldHeaderText="Picture"> <InsertItemTemplate> <asp:FileUploadID="PictureUpload"runat="server"/> </InsertItemTemplate> </asp:TemplateField>
Whenauseraddsanewcategory,[Link]
9 of17
thebrochure,[Link],weneedtheusertouploadanimagefile,butdowe allow any imagefileoronlyimagefilesofaparticulartype,suchasGIFsorJPGs?Inordertoallowfordifferent filetypes,wedneedtoextendtheCategories schematoincludeacolumnthatcapturesthefiletypesothatthis [Link] [Link] havesuchacolumn,[Link] Categories tablesexistingimagesarebitmaps,butJPGsareamoreappropriatefileformatforimagesserved overtheweb. Ifauseruploadsanincorrectfiletype,weneedtocanceltheinsertanddisplayamessageindicatingtheproblem. [Link] propertytoUploadWarning,clearoutits Text property,settheCssClass propertytoWarning, andtheVisible andEnableViewState propertiestoFalse. TheWarning [Link] andrendersthetextinalarge,red,italicized,boldfont. Note:Ideally,theCategoryName andDescription BoundFieldswouldbeconvertedtoTemplateFieldsand [Link] insertinginterface,forexample,wouldlikelybe [Link] columndoesnotacceptNULL values, aRequiredFieldValidatorshouldbeaddedtoensuretheuserprovidesavalueforthenewcategorysname. [Link] foranindepthlookataugmentingthedatamodificationinterfaces.
Step6:SavingtheUploadedBrochuretotheWebServersFileSystem
WhentheuserentersthevaluesforanewcategoryandclickstheInsertbutton,apostbackoccursandtheinserting [Link],theDetailsViewsItemInserting [Link],theObjectDataSourcesInsert() methodisinvoked,whichresultsinanewrecordbeingaddedtotheCategories [Link],the DetailsViewsItemInserted eventfires. BeforetheObjectDataSourcesInsert() methodisinvoked,wemustfirstensurethattheappropriatefiletypes [Link] fortheDetailsViewsItemInserting eventandaddthefollowingcode:
'ReferencetheFileUploadcontrols DimBrochureUploadAsFileUpload=_ CType([Link]("BrochureUpload"),FileUpload) [Link] 'MakesurethataPDFhasbeenuploaded [Link]([Link].GetExtension_ ([Link]),".pdf",True)<>0Then [Link]=_ "OnlyPDFdocumentsmaybeusedforacategory'sbrochure." [Link]=True [Link]=True ExitSub EndIf EndIf
TheeventhandlerstartsbyreferencingtheBrochureUpload FileUploadcontrolfromtheDetailsViewstemplates. Then,ifabrochurehasbeenuploaded,[Link], thenawarningisdisplayed,theinsertiscancelled,andtheexecutionoftheeventhandlerends. Note:Relyingontheuploadedfilesextensionisnotasurefiretechniqueforensuringthattheuploadedfile [Link],orcouldhave [Link] [Link]
10 of17
[Link], though,areoftenoverkillcheckingtheextensionissufficientformostscenarios. AsdiscussedintheUploadingFilestutorial,caremustbetakenwhensavingfilestothefilesystemsothatone [Link] [Link]~/Brochures directorywiththatsamefilename,however,wellappenda [Link],[Link], [Link] inthe~/Brochures folder,wellchangethesavedfilenameto [Link],[Link],andsoon,untilauniquefilenameisfound. [Link](path) methodtodetermineifafilealreadyexistswiththespecified [Link],itcontinuestotrynewfilenamesforthebrochureuntilnoconflictisfound.
ConstBrochureDirectoryAsString="~/Brochures/" DimbrochurePathAsString=BrochureDirectory&[Link] DimfileNameWithoutExtensionAsString=_ [Link]([Link]) DimiterationAsInteger=1 [Link]([Link](brochurePath)) brochurePath=[Link](BrochureDirectory,_ fileNameWithoutExtension,"",iteration,".pdf") iteration+=1 EndWhile
Onceavalidfilenamehasbeenfound,thefileneedstobesavedtothefilesystemandtheObjectDataSources brochurePath InsertParameter [Link] sawbackintheUploadingFiles tutorial,thefilecanbesavedusingtheFileUploadcontrolsSaveAs(path) [Link] parameter,[Link] collection.
'SavethefiletodiskandsetthevalueofthebrochurePathparameter [Link]([Link](brochurePath)) [Link]("brochurePath")=brochurePath
Step7:SavingtheUploadedPicturetotheDatabase
TostoretheuploadedpictureinthenewCategories record,weneedtoassigntheuploadedbinarycontenttothe ObjectDataSourcespicture parameterintheDetailsViewsItemInserting [Link] assignment,however,weneedtofirstmakesurethattheuploadedpictureisaJPGandnotsomeotherimagetype. AsinStep6,letsusetheuploadedpicturesfileextensiontoascertainitstype. WhiletheCategories tableallowsNULL valuesforthePicture column,allcategoriescurrentlyhaveapicture. [Link] toensurethatapicturehasbeenuploadedandthatithasanappropriateextension.
'ReferencetheFileUploadcontrols DimPictureUploadAsFileUpload=_ CType([Link]("PictureUpload"),FileUpload) [Link] 'MakesurethataJPGhasbeenuploaded [Link]([Link]([Link]),_ ".jpg",True)<>0AndAlso_ [Link]([Link]([Link]),_
11 of17
".jpeg",True)<>0Then [Link]=_ "OnlyJPGdocumentsmaybeusedforacategory'spicture." [Link]=True [Link]=True ExitSub EndIf Else 'Nopictureuploaded! [Link]=_ "Youmustprovideapictureforthenewcategory." [Link]=True [Link]=True ExitSub EndIf
Thiscodeshouldbeplacedbefore thecodefromStep6sothatifthereisaproblemwiththepictureupload,the eventhandlerwillterminatebeforethebrochurefileissavedtothefilesystem. Assumingthatanappropriatefilehasbeenuploaded,assigntheuploadedbinarycontenttothepictureparameters valuewiththefollowinglineofcode:
'Setthevalueofthepictureparameter [Link]("picture")=[Link]
TheCompleteItemInserting EventHandler
Forcompleteness,hereistheItemInserting eventhandlerinitsentirety:
ProtectedSubNewCategory_ItemInserting_ (senderAsObject,eAsDetailsViewInsertEventArgs)_ [Link] 'ReferencetheFileUploadcontrols DimPictureUploadAsFileUpload=_ CType([Link]("PictureUpload"),FileUpload) [Link] 'MakesurethataJPGhasbeenuploaded [Link]([Link]([Link]),_ ".jpg",True)<>0AndAlso_ [Link]([Link]([Link]),_ ".jpeg",True)<>0Then [Link]=_ "OnlyJPGdocumentsmaybeusedforacategory'spicture." [Link]=True [Link]=True ExitSub EndIf Else 'Nopictureuploaded! [Link]=_ "Youmustprovideapictureforthenewcategory." [Link]=True
12 of17
[Link]=True ExitSub EndIf 'Setthevalueofthepictureparameter [Link]("picture")=[Link]
'ReferencetheFileUploadcontrols DimBrochureUploadAsFileUpload=_ CType([Link]("BrochureUpload"),FileUpload) [Link] 'MakesurethataPDFhasbeenuploaded [Link]([Link]([Link]),_ ".pdf",True)<>0Then [Link]=_ "OnlyPDFdocumentsmaybeusedforacategory'sbrochure." [Link]=True [Link]=True ExitSub EndIf ConstBrochureDirectoryAsString="~/Brochures/" DimbrochurePathAsString=BrochureDirectory&[Link] DimfileNameWithoutExtensionAsString=_ [Link]([Link]) DimiterationAsInteger=1 [Link]([Link](brochurePath)) brochurePath=[Link](BrochureDirectory,_ fileNameWithoutExtension,"",iteration,".pdf") iteration+=1 EndWhile 'SavethefiletodiskandsetthevalueofthebrochurePathparameter [Link]([Link](brochurePath)) [Link]("brochurePath")=brochurePath EndIf EndSub
Step8:[Link] Page
LetstakeamomenttotestouttheinsertinginterfaceandItemInserting eventhandlerthatwascreatedoverthe [Link] pagethroughabrowserandattempttoaddacategory,but omitthepicture,[Link],anerrormessagewill bedisplayedandtheinsertworkflowcancelled.
13 of17
Figure9:AWarningMessageisDisplayedIfanInvalidFileTypeisUploaded
OnceyouhaveverifiedthatthepagerequiresapicturetobeuploadedandwontacceptnonPDFornonJPGfiles, addanewcategorywithavalidJPGpicture,[Link],the pagewillpostbackandanewrecordwillbeaddedtotheCategories tablewiththeuploadedimagesbinary [Link], but,asFigure10shows,thenewcategoryspictureisnotrenderedcorrectly.
Figure10:TheNewCategorysPictureisnotDisplayed
[Link] pagethatreturnsa 14 of17
specifiedcategoryspictureisconfiguredtoprocessbitmapsthathaveanOLEheader.This78byteheaderis strippedfromthePicture [Link] uploadedforthenewcategorydoesnothavethisOLEheadertherefore,valid,necessarybytesarebeingremoved fromtheimagesbinarydata. SincetherearenowbothbitmapswithOLEheadersandJPGsintheCategories table,weneedtoupdate [Link] sothatitdoestheOLEheaderstrippingfortheoriginaleightcategoriesand [Link] recordsimage,[Link],though,usethe [Link] tostriptheOLEheadersonlyforthoseoriginaleight categories:
ProtectedSubPage_Load(senderAsObject,eAsEventArgs)[Link] DimcategoryIDAsInteger=Convert.ToInt32([Link]("CategoryID")) 'Getinformationaboutthespecifiedcategory DimcategoryAPIAsNewCategoriesBLL() [Link]=_ [Link](categoryID) [Link]=categories(0) IfcategoryID<=8Then 'OutputHTTPheadersprovidinginformationaboutthebinarydata [Link]="image/bmp" 'Outputthebinarydata 'ButfirstweneedtostripouttheOLEheader ConstOleHeaderLengthAsInteger=78 DimstrippedImageLengthAsInteger=_ [Link] DimstrippedImageData(strippedImageLength)AsByte [Link]([Link],OleHeaderLength,_ strippedImageData,0,strippedImageLength) [Link](strippedImageData) Else 'Fornewcategories,imagesareJPGs... 'OutputHTTPheadersprovidinginformationaboutthebinarydata [Link]="image/jpeg" 'Outputthebinarydata [Link]([Link]) EndIf EndSub
Withthischange,theJPGimageisnowrenderedcorrectlyintheGridView.
15 of17
Figure11:TheJPGImagesforNewCategoriesareCorrectlyRendered
Step9:DeletingtheBrochureintheFaceofanException
Oneofthechallengesofstoringbinarydataonthewebserversfilesystemisthatitintroducesadisconnect [Link],wheneverarecordisdeleted,thecorrespondingbinarydata [Link],[Link] scenario:auseraddsanewcategory,[Link],a postbackoccursandtheDetailsViewsItemInserting eventfires,savingthebrochuretothewebserversfile [Link],theObjectDataSourcesInsert() methodisinvoked,whichcallstheCategoriesBLL classs InsertWithPicture method,whichcallstheCategoriesTableAdaptersInsertWithPicture method. Now,whathappensifthedatabaseisoffline,orifthereisanerrorintheINSERT SQLstatement?Clearlythe INSERTwillfail,[Link] filesittingonthewebserversfilesystem!Thisfileneedstobedeletedinthefaceofanexceptionduringthe insertingworkflow. AsdiscussedpreviouslyintheHandlingBLL [Link] tutorial,whenan [Link] PresentationLayer,wecandetermineifanexceptionhasoccurredfromtheDetailsViewsItemInserted event. [Link],wecan createaneventhandlerfortheItemInserted eventthatchecksiftherewasanexceptionand,ifso,deletesthefile specifiedbytheObjectDataSourcesbrochurePath parameter:
ProtectedSubNewCategory_ItemInserted_ (senderAsObject,eAsDetailsViewInsertedEventArgs)_ [Link] [Link] 'Needtodeletebrochurefile,ifitexists [Link]("brochurePath")IsNotNothingThen [Link](Server.MapPath_
16 of17
([Link]("brochurePath").ToString())) EndIf EndIf EndSub
Summary
Thereareanumberofstepsthatmustbeperformedinordertoprovideawebbasedinterfaceforaddingrecords [Link],chancesareyoullneedto updatethearchitecture,[Link] architecturehasbeenupdated,thenextstepiscreatingtheinsertinginterface,whichcanbeaccomplishedusinga [Link] canthenbesavedtothewebserversfilesystemorassignedtoadatasourceparameterintheDetailsViews ItemInserting eventhandler. [Link] [Link],extrastepsmustbetaken todeletetheuploadedfileifthedatabaseinsertfails. Wenowhavetheabilitytoaddnewcategoriestothesystemwithabrochureandpicture,butweveyettolookat howtoupdateanexistingcategorysbinarydataorhowtocorrectlyremovethebinarydataforadeletedcategory. Wellexplorethesetwotopicsinthenexttutorial. HappyProgramming!
AbouttheAuthor
ScottMitchell,authorofsevenASP/[Link],hasbeenworkingwith [Link],trainer,[Link] [Link]@[Link]. or viahisblog,whichcanbefoundat [Link]
SpecialThanksTo
[Link], TeresaMurphy,[Link]?Ifso,dropmealine at mitchell@[Link].
17 of17