작성자: 스콧 미첼
이전 자습서에서는 GridView 컨트롤을 사용하여 텍스트 데이터를 간단하게 편집하고 삭제하는 방법을 알아보았습니다. 이 자습서에서는 이진 데이터가 데이터베이스에 저장되거나 파일 시스템에 저장되는지 여부에 관계없이 GridView 컨트롤을 통해 이진 데이터를 편집하고 삭제하는 방법을 알아보세요.
소개
지난 3개의 자습서를 통해 이진 데이터 작업을 위한 많은 기능을 추가했습니다. 우리는 BrochurePath
테이블에 Categories
열을 추가하고 그에 따라 아키텍처를 업데이트했습니다. 또한 이미지 파일의 이진 콘텐츠를 포함하는 Categories 테이블의 기존 Picture
열을 사용하는 데이터 액세스 계층 및 비즈니스 논리 계층 메서드를 추가했습니다. 이진 데이터를 사용자에게 브로셔에 대한 다운로드 링크를 제공하는 GridView와 함께 웹 페이지를 만들었으며, 범주의 그림이 <img>
요소에 표시되고 사용자가 새 범주를 추가하고 브로셔 및 그림 데이터를 업로드할 수 있도록 DetailsView를 추가했습니다.
구현해야 할 것은 기존 범주를 편집하고 삭제하는 기능입니다. 이 자습서에서는 GridView의 기본 제공 편집 및 삭제 기능을 사용하여 수행할 것입니다. 범주를 편집할 때 사용자는 필요에 따라 새 사진을 업로드하거나 범주가 기존 그림을 계속 사용하도록 할 수 있습니다. 브로셔의 경우 기존 브로슈어를 사용하거나, 새 브로슈어를 업로드하거나, 범주에 더 이상 브로셔가 연결되어 있지 않음을 나타낼 수 있습니다. 시작해 보겠습니다!
1단계: 데이터 액세스 계층 업데이트
DAL에는 자동 생성된 Insert
, Update
, 및 Delete
메서드가 있지만, 이 메서드들은 CategoriesTableAdapter
열을 포함하지 않는 Picture
의 기본 쿼리를 기반으로 생성되었습니다. 따라서 및 Insert
메서드에는 Update
범주 그림에 대한 이진 데이터를 지정하기 위한 매개 변수가 포함되지 않습니다.
이전 자습서에서와 마찬가지로 이진 데이터를 지정할 때 테이블을 업데이트 Categories
하기 위한 새 TableAdapter 메서드를 만들어야 합니다.
형식화된 데이터 세트를 열고 디자이너에서 머리글을 마우스 오른쪽 단추로 클릭하고 CategoriesTableAdapter
상황에 맞는 메뉴에서 쿼리 추가를 선택하여 TableAdapter 쿼리 구성 마법사를 시작합니다. 이 마법사는 TableAdapter 쿼리가 데이터베이스에 액세스하는 방법을 묻는 것으로 시작합니다. SQL 문 사용을 선택하고 다음을 클릭합니다. 다음 단계에서는 생성할 쿼리 형식을 묻는 메시지를 표시합니다. 테이블에 새 레코드를 추가하는 쿼리를 만들고 있으므로 UPDATE를 Categories
선택하고 다음을 클릭합니다.
그림 1: 업데이트 옵션 선택(전체 크기 이미지를 보려면 클릭)
이제 SQL 문을 지정 UPDATE
해야 합니다. 마법사는 TableAdapter의 기본 쿼리에 해당하는 UPDATE
문장(이는 CategoryName
, Description
, BrochurePath
값을 업데이트하는 쿼리)을 자동으로 제안합니다. 다음과 같이 열이 Picture
매개 변수와 함께 @Picture
포함되도록 문을 변경합니다.
UPDATE [Categories] SET
[CategoryName] = @CategoryName,
[Description] = @Description,
[BrochurePath] = @BrochurePath ,
[Picture] = @Picture
WHERE (([CategoryID] = @Original_CategoryID))
마법사의 마지막 화면에서 새 TableAdapter 메서드의 이름을 지정하도록 요청합니다.
UpdateWithPicture
를 입력하고 마침을 클릭합니다.
그림 2: 새 TableAdapter 메서드 UpdateWithPicture
이름 지정(전체 크기 이미지를 보려면 클릭)
2단계: 비즈니스 논리 계층 메서드 추가
DAL을 업데이트하는 것 외에도 범주를 업데이트하고 삭제하는 메서드를 포함하도록 BLL을 업데이트해야 합니다. 다음은 프레젠테이션 계층에서 호출되는 메서드입니다.
우리는 자동 생성된 CategoriesTableAdapter
메서드를 사용하여 범주를 삭제할 수 있습니다.
CategoriesBLL
클래스에 다음 메서드를 추가합니다.
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Delete, True)> _
Public Function DeleteCategory(ByVal categoryID As Integer) As Boolean
Dim rowsAffected As Integer = Adapter.Delete(categoryID)
' Return true if precisely one row was deleted, otherwise false
Return rowsAffected = 1
End Function
이 자습서에서는 범주를 업데이트하기 위한 두 가지 메서드를 만들어 보겠습니다. 하나는 이진 그림 데이터를 예상하여 방금 추가된 UpdateWithPicture
메서드를 호출하는 것이고, 다른 하나는 CategoriesTableAdapter
, CategoryName
, Description
값만 허용하고 BrochurePath
클래스의 자동 생성된 CategoriesTableAdapter
문을 사용하는 것입니다. 두 가지 방법을 사용하는 이유는 경우에 따라 사용자가 다른 필드와 함께 범주 그림을 업데이트하려고 할 수 있으며, 이 경우 사용자가 새 그림을 업로드해야 한다는 것입니다. 업로드된 그림의 이진 데이터는 UPDATE
문장에 사용할 수 있습니다. 다른 경우에는 사용자가 이름 및 설명을 업데이트하는 데만 관심이 있을 수 있습니다. 하지만, UPDATE
구문이 Picture
열의 이진 데이터도 필요하다면, 그 정보를 제공해야 합니다. 이렇게 하려면 편집 중인 레코드에 대한 그림 데이터를 다시 가져오기 위해 데이터베이스를 추가로 이동해야 합니다. 따라서 두 가지 UPDATE
메서드를 원합니다. 비즈니스 논리 계층은 범주를 업데이트할 때 그림 데이터가 제공되는지 여부에 따라 사용할 항목을 결정합니다.
이를 용이하게 하려면 두 메서드를 CategoriesBLL
클래스에 추가하고, 두 메서드 모두 UpdateCategory
이라는 이름을 사용합니다. 첫 번째는 3개의 String
및 Byte
배열, Integer
를 입력 매개변수로 허용해야 하며, 두 번째는 3개의 String
와 1개의 Integer
를 허용해야 합니다. 입력 매개 변수는 String
범주 이름, 설명 및 브로셔 파일 경로에 대한 것이며, Byte
배열은 범주 그림의 이진 내용에 대한 것이며 Integer
업데이트할 레코드의 식별을 나타냅니다 CategoryID
. 전달된 Byte
배열이 Nothing
인 경우에는 첫 번째 오버로드가 두 번째 오버로드를 호출합니다.
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Update, False)> _
Public Function UpdateCategory(categoryName As String, description As String, _
brochurePath As String, picture() As Byte, categoryID As Integer) As Boolean
' If no picture is specified, use other overload
If picture Is Nothing Then
Return UpdateCategory(categoryName, description, brochurePath, categoryID)
End If
' Update picture, as well
Dim rowsAffected As Integer = Adapter.UpdateWithPicture _
(categoryName, description, brochurePath, picture, categoryID)
' Return true if precisely one row was updated, otherwise false
Return rowsAffected = 1
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateCategory(categoryName As String, description As String, _
brochurePath As String, categoryID As Integer) As Boolean
Dim rowsAffected As Integer = Adapter.Update _
(categoryName, description, brochurePath, categoryID)
' Return true if precisely one row was updated, otherwise false
Return rowsAffected = 1
End Function
3단계: 삽입 및 보기 기능 복사
이전 자습서에서는 GridView의 모든 범주를 나열하는 페이지를 UploadInDetailsView.aspx
만들고 시스템에 새 범주를 추가하는 DetailsView를 제공했습니다. 이 자습서에서는 편집 및 삭제 지원을 포함하도록 GridView를 확장합니다. 핵심구성: UploadInDetailsView.aspx
에서 계속 작업을 하기보다는, 같은 폴더에 있는 UpdatingAndDeleting.aspx
에 ~/BinaryData
라는 페이지에 이 자습서의 변경 내용을 배치하겠습니다.
UploadInDetailsView.aspx
부터 UpdatingAndDeleting.aspx
까지 선언적 태그와 코드를 복사하여 붙여넣으세요.
페이지를 열어 시작합니다 UploadInDetailsView.aspx
. 그림 3과 같이 요소 내 <asp:Content>
의 선언적 구문을 모두 복사합니다. 다음으로, UpdatingAndDeleting.aspx
을 열고 <asp:Content>
요소 내에 이 마크업을 붙여넣습니다. 마찬가지로 페이지의 코드 숨김 클래스에서 UploadInDetailsView.aspx
의 코드를 가져와서 UpdatingAndDeleting.aspx
로 복사합니다.
그림 3: 선언적 태그 UploadInDetailsView.aspx
복사(전체 크기 이미지를 보려면 클릭)
선언적 태그와 코드를 복사한 후, UpdatingAndDeleting.aspx
를 방문하세요. 이전 자습서의 UploadInDetailsView.aspx
페이지와 마찬가지로 동일한 출력과 같은 사용자 경험을 제공해야 합니다.
4단계: ObjectDataSource 및 GridView에 삭제 지원 추가
데이터 삽입, 업데이트 및 삭제 개요 자습서에서 다시 설명한 것처럼 GridView는 기본 제공 삭제 기능을 제공하며 그리드의 기본 데이터 원본이 삭제를 지원하는 경우 확인란의 틱에서 이러한 기능을 사용하도록 설정할 수 있습니다. 현재 GridView가 ()에 바인딩된CategoriesDataSource
ObjectDataSource는 삭제를 지원하지 않습니다.
이 문제를 해결하려면 ObjectDataSource의 스마트 태그에서 데이터 원본 구성 옵션을 클릭하여 마법사를 시작합니다. 첫 번째 화면에서는 ObjectDataSource가 클래스와 함께 작동하도록 구성되어 있음을 CategoriesBLL
보여줍니다. 다음을 누릅니다. 현재 ObjectDataSource InsertMethod
및 SelectMethod
속성만 지정됩니다. 그러나 마법사는 UPDATE 및 DELETE 탭의 드롭다운 목록을 각각 UpdateCategory
및 DeleteCategory
메서드로 자동으로 채웠습니다. 이는 클래스에서 이러한 메서드를 CategoriesBLL
업데이트 및 삭제를 위한 기본 메서드로 사용하여 DataObjectMethodAttribute
표시했기 때문입니다.
지금은 UPDATE 탭의 드롭다운 목록을 (없음)으로 설정하지만 DELETE 탭의 드롭다운 목록을 다음으로 DeleteCategory
설정합니다. 업데이트 지원을 추가하려면 6단계에서 이 마법사로 돌아갑니다.
그림 4: 메서드를 사용하도록 DeleteCategory
ObjectDataSource 구성(전체 크기 이미지를 보려면 클릭)
비고
마법사를 완료하면 Visual Studio에서 데이터 웹 컨트롤 필드를 다시 생성할 필드 및 키를 새로 고칠지 묻는 메시지가 표시될 수 있습니다. 예를 선택하면 이미 수행한 필드 사용자 지정이 덮어써지므로, 아니요를 선택하십시오.
이제 ObjectDataSource에는 DeleteMethod
속성에 대한 값과 DeleteParameter
값이 포함됩니다. 마법사를 사용하여 메서드를 지정할 때 Visual Studio는 ObjectDataSource의 OldValuesParameterFormatString
속성을 original_{0}
업데이트 및 삭제 메서드 호출에 문제가 발생하도록 설정합니다. 따라서 이 속성을 모두 지우거나 기본값 {0}
으로 다시 설정합니다. 이 ObjectDataSource 속성에서 메모리를 새로 고쳐야 하는 경우 데이터 삽입, 업데이트 및 삭제 자습서의 개요를 참조하세요.
마법사를 완료하고 OldValuesParameterFormatString
를 수정한 후, ObjectDataSource의 선언적 태그는 다음과 비슷하게 표시됩니다.
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="{0}" SelectMethod="GetCategories"
TypeName="CategoriesBLL" InsertMethod="InsertWithPicture"
DeleteMethod="DeleteCategory">
<InsertParameters>
<asp:Parameter Name="categoryName" Type="String" />
<asp:Parameter Name="description" Type="String" />
<asp:Parameter Name="brochurePath" Type="String" />
<asp:Parameter Name="picture" Type="Object" />
</InsertParameters>
<DeleteParameters>
<asp:Parameter Name="categoryID" Type="Int32" />
</DeleteParameters>
</asp:ObjectDataSource>
ObjectDataSource를 구성한 후 GridView의 스마트 태그에서 삭제 사용 확인란을 선택하여 GridView에 삭제 기능을 추가합니다. 이로 인해 ShowDeleteButton
속성으로 설정된 True
이(가) 포함된 GridView에 CommandField가 추가됩니다.
그림 5: GridView에서 삭제 지원 사용(전체 크기 이미지를 보려면 클릭)
잠시 시간을 내어 삭제 기능을 테스트합니다. 테이블과 Products
테이블 CategoryID
Categories
사이에 CategoryID
외래 키가 있으므로 처음 8개 범주 중에서 삭제하려고 하면 외래 키 제약 조건 위반 예외가 발생합니다. 이 기능을 테스트하려면 브로셔와 그림을 모두 제공하는 새 범주를 추가합니다. 그림 6에 표시된 내 테스트 범주에는 명명 Test.pdf
된 테스트 브로슈어 파일과 테스트 그림이 포함되어 있습니다. 그림 7은 테스트 범주가 추가된 후의 GridView를 보여줍니다.
그림 6: 브로슈어 및 이미지를 사용하여 테스트 범주 추가(전체 크기 이미지를 보려면 클릭)
그림 7: 테스트 범주를 삽입한 후 GridView에 표시됩니다(전체 크기 이미지를 보려면 클릭).
Visual Studio에서 솔루션 탐색기를 새로 고칩니다. 이제 폴더 ~/Brochures
에 Test.pdf
새 파일이 표시됩니다(그림 8 참조).
그런 다음, 테스트 범주 행에서 삭제 링크를 클릭하면 페이지가 포스트백되어 클래스 CategoriesBLL
의 메서드 DeleteCategory
가 실행됩니다. 이렇게 하면 DAL 메서드 Delete
가 호출되어 적절한 DELETE
문이 데이터베이스로 전송됩니다. 그런 다음 데이터는 GridView로 다시 돌아가고 태그는 테스트 범주가 더 이상 존재하지 않는 클라이언트로 다시 전송됩니다.
삭제 워크플로가 테이블에서 테스트 범주 레코드를 Categories
성공적으로 제거한 반면 웹 서버의 파일 시스템에서 해당 브로셔 파일을 제거하지는 않았습니다. 솔루션 탐색기를 새로 고치면 Test.pdf
가 여전히 ~/Brochures
폴더에 있는 것을 볼 수 있습니다.
그림 8: Test.pdf
웹 서버의 파일 시스템에서 파일이 삭제되지 않았습니다.
5단계: 삭제된 범주의 브로셔 파일 제거
데이터베이스 외부에 이진 데이터를 저장하는 단점 중 하나는 연결된 데이터베이스 레코드가 삭제될 때 이러한 파일을 정리하기 위해 추가 단계를 수행해야 한다는 것입니다. GridView 및 ObjectDataSource는 삭제 명령이 수행되기 전과 후에 발생하는 이벤트를 제공합니다. 실제로는 사전 및 사후 작업 이벤트 모두에 대한 이벤트 처리기를 만들어야 합니다. 레코드를 Categories
삭제하기 전에 해당 PDF 파일의 경로를 확인해야 하지만 일부 예외가 있고 범주가 삭제되지 않는 경우 범주가 삭제되기 전에 PDF를 삭제하지 않습니다.
GridView의 RowDeleting
이벤트는 ObjectDataSource의 delete 명령이 호출되기 전에 발생하며 RowDeleted
그 후에 이벤트가 발생합니다. 다음 코드를 사용하여 이러한 두 이벤트에 대한 이벤트 처리기를 만듭니다.
' A page variable to "remember" the deleted category's BrochurePath value
Private deletedCategorysPdfPath As String = Nothing
Protected Sub Categories_RowDeleting(sender As Object, e As GridViewDeleteEventArgs) _
Handles Categories.RowDeleting
' Determine the PDF path for the category being deleted...
Dim categoryID As Integer = Convert.ToInt32(e.Keys("CategoryID"))
Dim categoryAPI As New CategoriesBLL()
Dim categoriesData As Northwind.CategoriesDataTable = _
categoryAPI.GetCategoryByCategoryID(categoryID)
Dim category As Northwind.CategoriesRow = categoriesData(0)
If category.IsBrochurePathNull() Then
deletedCategorysPdfPath = Nothing
Else
deletedCategorysPdfPath = category.BrochurePath
End If
End Sub
Protected Sub Categories_RowDeleted(sender As Object, e As GridViewDeletedEventArgs) _
Handles Categories.RowDeleted
' Delete the brochure file if there were no problems deleting the record
If e.Exception Is Nothing Then
DeleteRememberedBrochurePath()
End If
End Sub
RowDeleting
이벤트 처리기에서 삭제 중인 행의 CategoryID
은 GridView의 DataKeys
컬렉션에서 가져옵니다. 이 컬렉션은 e.Keys
컬렉션을 통해 이 이벤트 처리기에서 액세스할 수 있습니다. 다음으로, CategoriesBLL
삭제되는 레코드에 대한 정보를 반환하기 위해 클래스 s GetCategoryByCategoryID(categoryID)
가 호출됩니다. 반환 CategoriesDataRow
된 개체에 값NULL``BrochurePath
이 없는 경우 이벤트 처리기에서 파일을 삭제할 수 있도록 페이지 변수 deletedCategorysPdfPath
에 RowDeleted
저장됩니다.
비고
대신에 GridView 속성 BrochurePath
에 Categories
를 추가하고 RowDeleting
컬렉션을 통해 레코드 BrochurePath
의 값을 액세스할 수 있었던 것처럼, 이벤트 처리기 내에서 삭제되는 DataKeyNames
레코드로부터 e.Keys
세부 정보를 검색하는 것이 가능합니다. 이렇게 하면 GridView의 뷰 상태 크기가 약간 증가하지만 필요한 코드의 양이 줄어들고 데이터베이스로의 이동이 저장됩니다.
ObjectDataSource의 기본 삭제 명령이 호출되면 GridView의 RowDeleted
이벤트 처리기가 실행됩니다. 데이터 삭제에 예외가 없고 값 deletedCategorysPdfPath
이 있는 경우 파일 시스템에서 PDF가 삭제됩니다. 이 추가 코드는 그림과 연결된 범주의 이진 데이터를 정리하는 데 필요하지 않습니다. 그림 데이터가 데이터베이스에 직접 저장되므로 행을 삭제하면 Categories
해당 범주의 그림 데이터도 삭제됩니다.
두 이벤트 처리기를 추가한 후 이 테스트 사례를 다시 실행합니다. 범주를 삭제할 때 관련 PDF도 삭제됩니다.
기존 레코드의 연결된 이진 데이터를 업데이트하면 몇 가지 흥미로운 문제가 발생합니다. 이 자습서의 나머지 부분에서는 브로셔 및 그림에 업데이트 기능을 추가하는 방법을 자세히 설명합니다. 6단계에서는 브로슈어 정보를 업데이트하는 기술을 살펴보고 7단계는 그림 업데이트를 살펴봅니다.
6단계: 범주 브로슈어 업데이트
데이터 삽입, 업데이트 및 삭제 개요 자습서에서 설명한 대로 GridView는 기본 데이터 원본이 적절하게 구성된 경우 확인란의 틱으로 구현할 수 있는 기본 제공 행 수준 편집 지원을 제공합니다. 현재 CategoriesDataSource
ObjectDataSource는 업데이트 지원을 포함하도록 아직 구성되지 않았으므로 추가해 보겠습니다.
ObjectDataSource 마법사에서 데이터 원본 구성 링크를 클릭하고 두 번째 단계로 진행합니다. 사용되므로 DataObjectMethodAttribute
, CategoriesBLL
에서 UPDATE 드롭다운 목록은 UpdateCategory
로 자동으로 채워지며, 이는 네 개의 입력 매개 변수를 허용하는 오버로드입니다(모든 열에서 Picture
는 제외). 5개의 매개 변수가 있는 오버로드를 사용할 수 있도록 이 값을 변경합니다.
그림 9: 매개 변수 UpdateCategory
를 포함하는 메서드를 사용하도록 Picture
ObjectDataSource 구성(전체 크기 이미지를 보려면 클릭)
이제 ObjectDataSource에는 해당 UpdateMethod
속성의 값과 해당 UpdateParameter
값이 포함됩니다. 4단계에서 설명한 것처럼 Visual Studio는 데이터 원본 구성 마법사를 OldValuesParameterFormatString
사용할 때 ObjectDataSource의 original_{0}
속성을 설정합니다. 이렇게 하면 업데이트 및 삭제 메서드 호출에 문제가 발생합니다. 따라서 이 속성을 모두 지우거나 기본값 {0}
으로 다시 설정합니다.
마법사를 완료하고 OldValuesParameterFormatString
를 수정한 후, ObjectDataSource의 선언적 태그는 다음과 같이 보일 것입니다.
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="{0}" SelectMethod="GetCategories"
TypeName="CategoriesBLL" InsertMethod="InsertWithPicture"
DeleteMethod="DeleteCategory" UpdateMethod="UpdateCategory">
<InsertParameters>
<asp:Parameter Name="categoryName" Type="String" />
<asp:Parameter Name="description" Type="String" />
<asp:Parameter Name="brochurePath" Type="String" />
<asp:Parameter Name="picture" Type="Object" />
</InsertParameters>
<DeleteParameters>
<asp:Parameter Name="categoryID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="categoryName" Type="String" />
<asp:Parameter Name="description" Type="String" />
<asp:Parameter Name="brochurePath" Type="String" />
<asp:Parameter Name="picture" Type="Object" />
<asp:Parameter Name="categoryID" Type="Int32" />
</UpdateParameters>
</asp:ObjectDataSource>
GridView의 기본 제공 편집 기능을 켜려면 GridView의 스마트 태그에서 편집 사용 옵션을 선택합니다. 이렇게 하면 CommandField ShowEditButton
속성 True
이 설정되고 편집 단추(편집 중인 행의 업데이트 및 취소 단추)가 추가됩니다.
그림 10: 편집을 지원하도록 GridView 구성(전체 크기 이미지를 보려면 클릭)
브라우저를 통해 페이지를 방문하여 행의 편집 단추 중 하나를 클릭합니다.
CategoryName
및 Description
BoundFields는 텍스트 상자로 렌더링됩니다.
BrochurePath
TemplateField는 EditItemTemplate
가 없기 때문에 계속해서 ItemTemplate
브로셔에 대한 링크를 표시합니다. ImageField는 Picture
텍스트박스로 렌더링되며 그 Text
속성에 ImageField의 DataImageUrlField
값인 CategoryID
이 할당됩니다.
그림 11: GridView에 대한 편집 인터페이스 BrochurePath
가 없습니다(전체 크기 이미지를 보려면 클릭).
BrochurePath
편집 인터페이스 사용자 지정
사용자가 다음 중 하나를 허용하는 TemplateField에 대한 BrochurePath
편집 인터페이스를 만들어야 합니다.
- 카테고리의 브로슈어 as-is을(를) 그대로 두십시오.
- 새 브로슈어를 업로드하여 범주의 브로셔를 업데이트하거나
- 범주의 브로셔를 모두 제거합니다(범주에 연결된 브로셔가 더 이상 없는 경우).
또한 ImageField의 편집 인터페이스를 Picture
업데이트해야 하지만 7단계에서 이 작업을 수행합니다.
GridView의 스마트 태그에서 템플릿 편집 링크를 클릭하고 드롭다운 목록에서 TemplateField를 BrochurePath
선택합니다EditItemTemplate
. 템플릿에 RadioButtonList 웹 컨트롤을 추가하고, ID
속성을 BrochureOptions
로, AutoPostBack
속성을 True
로 설정합니다. 속성 창에서 Items
속성의 줄임표를 클릭하면 ListItem
컬렉션 편집기가 표시됩니다. 각각 s 1, 2 및 3을 사용하여 Value
다음 세 가지 옵션을 추가합니다.
- 현재 브로셔 사용
- 현재 브로셔 제거
- 새 브로셔 업로드
첫 번째 ListItem
속성을 Selected
로 True
설정합니다.
그림 12: RadioButtonList에 3개 ListItem
추가
RadioButtonList 아래에 이름이 인 BrochureUpload
FileUpload 컨트롤을 추가합니다. 해당 AutoSize 속성을 true
로 설정합니다.
그림 13: RadioButtonList 및 FileUpload 컨트롤을 EditItemTemplate
추가합니다(전체 크기 이미지를 보려면 클릭).
이 RadioButtonList는 사용자에 대한 세 가지 옵션을 제공합니다. FileUpload 컨트롤은 마지막 옵션인 새 브로셔 업로드가 선택된 경우에만 표시됩니다. 이렇게 하려면 RadioButtonList 이벤트에 SelectedIndexChanged
대한 이벤트 처리기를 만들고 다음 코드를 추가합니다.
Protected Sub BrochureOptions_SelectedIndexChanged _
(sender As Object, e As EventArgs)
' Get a reference to the RadioButtonList and its Parent
Dim BrochureOptions As RadioButtonList = _
CType(sender, RadioButtonList)
Dim parent As Control = BrochureOptions.Parent
' Now use FindControl("controlID") to get a reference of the
' FileUpload control
Dim BrochureUpload As FileUpload = _
CType(parent.FindControl("BrochureUpload"), FileUpload)
' Only show BrochureUpload if SelectedValue = "3"
BrochureUpload.Visible = (BrochureOptions.SelectedValue = "3")
End Sub
RadioButtonList 및 FileUpload 컨트롤은 템플릿 내에 있으므로 이러한 컨트롤에 프로그래밍 방식으로 액세스하려면 약간의 코드를 작성해야 합니다.
SelectedIndexChanged
이벤트 처리기는 입력 매개 변수에서 RadioButtonList의 참조를 sender
전달합니다. FileUpload 컨트롤을 얻으려면 RadioButtonList의 부모 컨트롤을 가져와서 여기에서 메서드를 FindControl("controlID")
사용해야 합니다. RadioButtonList 및 FileUpload 컨트롤 모두에 대한 참조가 있으면 FileUpload 컨트롤의 속성은 RadioButtonList가 Visible
True
3인 경우에만 설정 SelectedValue
됩니다. 이는 Value
업로드 새 브로셔ListItem
에 대한 것입니다.
이 코드를 사용하면 잠시 시간을 내어 편집 인터페이스를 테스트합니다. 행에 대한 편집 단추를 클릭합니다. 처음에는 현재 브로셔 사용 옵션을 선택해야 합니다. 선택한 인덱스가 변경되면 포스트백이 발생합니다. 세 번째 옵션을 선택하면 FileUpload 컨트롤이 표시되고, 그렇지 않으면 숨겨집니다. 그림 14는 편집 단추를 처음 클릭할 때 편집 인터페이스를 보여 줍니다. 그림 15는 새 브로셔 업로드 옵션을 선택한 후의 인터페이스를 보여줍니다.
그림 14: 처음에는 현재 브로셔 사용 옵션이 선택되었습니다(전체 크기 이미지를 보려면 클릭).
그림 15: 새 브로셔 업로드 옵션을 선택하면 FileUpload 컨트롤이 표시됩니다(전체 크기 이미지를 보려면 클릭).
브로슈어 파일 저장 및 열 업데이트BrochurePath
GridView의 업데이트 단추를 클릭하면 해당 RowUpdating
이벤트가 발생합니다. ObjectDataSource의 업데이트 명령이 호출된 다음 GridView의 RowUpdated
이벤트가 발생합니다. 삭제 워크플로와 마찬가지로 이러한 두 이벤트에 대한 이벤트 처리기를 만들어야 합니다.
RowUpdating
이벤트 처리기에서 RadioButtonList의 SelectedValue
을 기반으로 BrochureOptions
수행할 작업을 결정해야 합니다.
-
SelectedValue
1이면 동일한BrochurePath
설정을 계속 사용하려고 합니다. 따라서 ObjectDataSource의brochurePath
매개 변수를 업데이트할 레코드의 기존BrochurePath
값으로 설정해야 합니다. ObjectDataSource의brochurePath
매개 변수는 .를 사용하여e.NewValues["brochurePath"] = value
설정할 수 있습니다. -
SelectedValue
이 2이면, 기록의BrochurePath
값을NULL
로 설정합니다. 이 작업은 ObjectDataSource의brochurePath
매개 변수를Nothing
문에서 사용되는 데이터베이스NULL
로 설정하여 수행할 수 있습니다. 제거 중인 기존 브로셔 파일이 있는 경우 기존 파일을 삭제해야 합니다. 그러나 예외를 발생하지 않고 업데이트가 완료된 경우에만 이 작업을 수행하려고 합니다. -
SelectedValue
3이면 사용자가 PDF 파일을 업로드했는지 확인하고 파일 시스템에 저장하고 레코드의BrochurePath
열 값을 업데이트하려고 합니다. 또한 대체되는 기존 브로셔 파일이 있는 경우 이전 파일을 삭제해야 합니다. 그러나 예외를 발생하지 않고 업데이트가 완료된 경우에만 이 작업을 수행하려고 합니다.
RadioButtonList SelectedValue
가 3일 때 완료해야 하는 단계는 DetailsView의 ItemInserting
이벤트 처리기에서 사용하는 단계와 거의 동일합니다. 이 이벤트 처리기는 이전 자습서에서 추가한 DetailsView 컨트롤에서 새 범주 레코드가 추가될 때 실행됩니다. 따라서 이 기능을 별도의 메서드로 리팩터링해야 합니다. 특히 일반적인 기능을 다음 두 가지 방법으로 이동했습니다.
-
ProcessBrochureUpload(FileUpload, out bool)
는 FileUpload 컨트롤 인스턴스 및 삭제 또는 편집 작업을 계속할지 또는 일부 유효성 검사 오류로 인해 취소해야 하는지 여부를 지정하는 출력 부울 값을 입력으로 허용합니다. 이 메서드는 저장된 파일의 경로를 반환하거나null
파일이 저장되지 않은 경우 반환합니다. -
DeleteRememberedBrochurePath
가 아닌deletedCategorysPdfPath
경우deletedCategorysPdfPath
페이지 변수null
의 경로에 지정된 파일을 삭제합니다.
이 두 메서드에 대한 코드는 다음과 같습니다. 이전 자습서의 DetailsView ProcessBrochureUpload
이벤트 처리기와 ItemInserting
간의 유사성을 확인하십시오. 이 자습서에서는 이러한 새 메서드를 사용하도록 DetailsView의 이벤트 처리기를 업데이트했습니다. DetailsView의 이벤트 처리기에 대한 수정 내용을 보려면 이 자습서와 연결된 코드를 다운로드합니다.
Private Function ProcessBrochureUpload _
(BrochureUpload As FileUpload, CancelOperation As Boolean) As String
CancelOperation = False ' by default, do not cancel operation
If BrochureUpload.HasFile Then
' Make sure that a PDF has been uploaded
If String.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName), _
".pdf", True) <> 0 Then
UploadWarning.Text = _
"Only PDF documents may be used for a category's brochure."
UploadWarning.Visible = True
CancelOperation = True
Return Nothing
End If
Const BrochureDirectory As String = "~/Brochures/"
Dim brochurePath As String = BrochureDirectory + BrochureUpload.FileName
Dim fileNameWithoutExtension As String = _
System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName)
Dim iteration As Integer = 1
While System.IO.File.Exists(Server.MapPath(brochurePath))
brochurePath = String.Concat(BrochureDirectory, _
fileNameWithoutExtension, "-", iteration, ".pdf")
iteration += 1
End While
' Save the file to disk and set the value of the brochurePath parameter
BrochureUpload.SaveAs(Server.MapPath(brochurePath))
Return brochurePath
Else
' No file uploaded
Return Nothing
End If
End Function
Private Sub DeleteRememberedBrochurePath()
' Is there a file to delete?
If deletedCategorysPdfPath IsNot Nothing Then
System.IO.File.Delete(Server.MapPath(deletedCategorysPdfPath))
End If
End Sub
GridView RowUpdating
및 RowUpdated
이벤트 처리기는 다음 코드와 같이 ProcessBrochureUpload
메서드 및 DeleteRememberedBrochurePath
메서드를 사용합니다.
Protected Sub Categories_RowUpdating _
(sender As Object, e As GridViewUpdateEventArgs) _
Handles Categories.RowUpdating
' Reference the RadioButtonList
Dim BrochureOptions As RadioButtonList = _
CType(Categories.Rows(e.RowIndex).FindControl("BrochureOptions"), _
RadioButtonList)
' Get BrochurePath information about the record being updated
Dim categoryID As Integer = Convert.ToInt32(e.Keys("CategoryID"))
Dim categoryAPI As New CategoriesBLL()
Dim categoriesData As Northwind.CategoriesDataTable = _
categoryAPI.GetCategoryByCategoryID(categoryID)
Dim category As Northwind.CategoriesRow = categoriesData(0)
If BrochureOptions.SelectedValue = "1" Then
' Use current value for BrochurePath
If category.IsBrochurePathNull() Then
e.NewValues("brochurePath") = Nothing
Else
e.NewValues("brochurePath") = category.BrochurePath
End If
ElseIf BrochureOptions.SelectedValue = "2" Then
' Remove the current brochure (set it to NULL in the database)
e.NewValues("brochurePath") = Nothing
ElseIf BrochureOptions.SelectedValue = "3" Then
' Reference the BrochurePath FileUpload control
Dim BrochureUpload As FileUpload = _
CType(categories.Rows(e.RowIndex).FindControl("BrochureUpload"), _
FileUpload)
' Process the BrochureUpload
Dim cancelOperation As Boolean = False
e.NewValues("brochurePath") = _
ProcessBrochureUpload(BrochureUpload, cancelOperation)
e.Cancel = cancelOperation
Else
' Unknown value!
Throw New ApplicationException( _
String.Format("Invalid BrochureOptions value, {0}", _
BrochureOptions.SelectedValue))
End If
If BrochureOptions.SelectedValue = "2" OrElse _
BrochureOptions.SelectedValue = "3" Then
' "Remember" that we need to delete the old PDF file
If (category.IsBrochurePathNull()) Then
deletedCategorysPdfPath = Nothing
Else
deletedCategorysPdfPath = category.BrochurePath
End If
End If
End Sub
Protected Sub Categories_RowUpdated _
(sender As Object, e As GridViewUpdatedEventArgs) _
Handles Categories.RowUpdated
' If there were no problems and we updated the PDF file,
' then delete the existing one
If e.Exception Is Nothing Then
DeleteRememberedBrochurePath()
End If
End Sub
RowUpdating
이벤트 처리기가 BrochureOptions
RadioButtonList의 SelectedValue
속성 값을 기반으로 적절한 작업을 수행하기 위해 일련의 조건문을 사용하는 방법을 주목하세요.
이 코드를 사용하면 범주를 편집하고 현재 브로셔를 사용하거나 브로셔를 사용하지 않거나 새 브로셔를 업로드할 수 있습니다. 한번 시도해 보세요. 워크플로를 이해하기 위해 이벤트 처리기 RowUpdating
및 RowUpdated
에서 중단점을 설정하세요.
7단계: 새 그림 업로드
ImageField의 편집 인터페이스는 Picture
속성의 값 DataImageUrlField
으로 채워진 텍스트 상자로 렌더링됩니다. 편집 워크플로 중에 GridView는 매개 변수 이름을 ImageField DataImageUrlField
속성의 값과 편집 인터페이스의 텍스트 상자에 입력한 매개 변수 값으로 ObjectDataSource에 매개 변수를 전달합니다. 이 동작은 이미지가 파일 시스템에 파일로 저장되고 DataImageUrlField
이미지의 전체 URL을 포함하는 경우에 적합합니다. 이러한 경우 편집 인터페이스는 사용자가 변경하고 데이터베이스에 다시 저장할 수 있는 이미지의 URL을 텍스트 상자에 표시합니다. 이 기본 인터페이스는 사용자가 새 이미지를 업로드할 수 없도록 허용하지만 이미지의 URL을 현재 값에서 다른 값으로 변경할 수 있습니다. 그러나 이 자습서에서는 이진 데이터가 데이터베이스에 직접 저장되고 Picture
만 속성에 저장되므로 ImageField의 기본 편집 인터페이스는 충분하지 DataImageUrlField
않습니다.
사용자가 ImageField를 사용하여 행을 편집할 때 자습서에서 수행되는 작업을 더 잘 이해하려면 다음 예제를 고려하세요. 사용자가 10이 있는 행 CategoryID
을 편집하여 Picture
ImageField가 값이 10인 텍스트 상자로 렌더링됩니다. 사용자가 이 텍스트 상자의 값을 50으로 변경하고 업데이트 단추를 클릭한다고 상상해 보십시오. 포스트백이 발생하고 GridView는 처음에 값 50으로 명명된 CategoryID
매개 변수를 만듭니다. GridView가 이 매개변수와 CategoryName
및 Description
매개변수를 보내기 전에 DataKeys
컬렉션의 값을 추가합니다. 따라서 매개 변수를 CategoryID
현재 행의 기본 CategoryID
값인 10으로 덮어씁니다. 간단히 말해서 ImageField의 편집 인터페이스는 ImageField 속성과 그리드 값의 이름이 동일하기 때문에 이 자습서의 DataImageUrlField
DataKey
편집 워크플로에 영향을 주지 않습니다.
ImageField를 사용하면 데이터베이스 데이터를 기반으로 이미지를 쉽게 표시할 수 있지만 편집 인터페이스에 텍스트 상자를 제공하지는 않습니다. 대신 최종 사용자가 범주의 그림을 변경하는 데 사용할 수 있는 FileUpload 컨트롤을 제공하려고 합니다. 값과 BrochurePath
달리 이러한 자습서의 경우 각 범주에 그림이 있어야 합니다. 따라서 사용자가 새 사진을 업로드하거나 현재 그림을 as-is그대로 둘 수 있는 연결된 사진이 없음을 사용자에게 표시할 필요가 없습니다.
ImageField의 편집 인터페이스를 사용자 지정하려면 템플릿 필드로 변환해야 합니다. GridView의 스마트 태그에서 열 편집 링크를 클릭하고 ImageField를 선택한 다음 이 필드를 TemplateField 링크로 변환을 클릭합니다.
그림 16: ImageField를 TemplateField로 변환
이러한 방식으로 ImageField를 TemplateField로 변환하면 두 개의 템플릿이 있는 TemplateField가 생성됩니다. 다음 선언적 구문은 ItemTemplate
이(가) 포함된 것으로, 이 컨트롤의 ImageUrl
속성은 ImageField의 DataImageUrlField
및 DataImageUrlFormatString
속성에 기반한 데이터 바인딩 구문을 사용하여 할당됩니다.
EditItemTemplate
에는 Text
속성에 지정된 값에 바인딩된 DataImageUrlField
속성을 가진 TextBox가 포함됩니다.
<asp:TemplateField>
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"
Text='<%# Eval("CategoryID") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Image ID="Image1" runat="server"
ImageUrl='<%# Eval("CategoryID",
"DisplayCategoryPicture.aspx?CategoryID={0}") %>' />
</ItemTemplate>
</asp:TemplateField>
FileUpload 컨트롤을 EditItemTemplate
사용하도록 업데이트해야 합니다. GridView의 스마트 태그에서 템플릿 편집 링크를 클릭한 다음 드롭다운 목록에서 TemplateField를 Picture
선택합니다EditItemTemplate
. 템플릿에서 TextBox가 이를 제거하는 것을 볼 수 있습니다. 다음으로, FileUpload 컨트롤을 도구 상자에서 템플릿으로 끌어 ID
을(를) PictureUpload
으로 설정합니다. 텍스트 '범주의 그림을 수정하려면 새 그림을 지정하십시오'를 추가합니다. 범주의 그림을 동일하게 유지하려면 템플릿에도 필드를 비워 둡니다.
그림 17: FileUpload 컨트롤을 EditItemTemplate
추가합니다(전체 크기 이미지를 보려면 클릭).
편집 인터페이스를 사용자 지정한 후 브라우저에서 진행률을 확인합니다. 읽기 전용 모드에서 행을 볼 때 범주 이미지가 이전과 같이 표시되지만 편집 단추를 클릭하면 그림 열이 FileUpload 컨트롤을 사용하여 텍스트로 렌더링됩니다.
그림 18: 편집 인터페이스에 FileUpload 컨트롤이 포함되어 있습니다(전체 크기 이미지를 보려면 클릭).
ObjectDataSource는 CategoriesBLL
클래스의 UpdateCategory
메서드를 호출하도록 구성되어 있으며, 이 메서드는 그림에 대한 이진 데이터를 Byte
배열로 입력으로 허용합니다. 그러나 이 배열이 Nothing
인 경우, UpdateCategory
열을 수정하지 않는 UPDATE
SQL 문을 발행하는 대체 Picture
오버로드가 호출되어, 범주의 현재 이미지를 그대로 둡니다. 따라서 GridView의 RowUpdating
이벤트 처리기에서 프로그래밍 방식으로 FileUpload 컨트롤을 PictureUpload
참조하고 파일이 업로드되었는지 확인해야 합니다. 업로드되지 않은 경우 매개 변수의 값을 지정picture
않습니다. 반면에 FileUpload 컨트롤에 PictureUpload
파일이 업로드된 경우 해당 파일이 JPG 파일인지 확인하려고 합니다. 그렇다면 picture
매개 변수를 통해 ObjectDataSource에 이진 콘텐츠를 보낼 수 있습니다.
6단계에서 사용된 코드와 마찬가지로 여기에 필요한 코드의 대부분은 DetailsView의 ItemInserting
이벤트 처리기에 이미 존재합니다. 따라서 공통 기능을 새 메서드로 리팩터링하고 이 메서드 ValidPictureUpload
를 ItemInserting
사용하도록 이벤트 처리기를 업데이트했습니다.
GridView RowUpdating
이벤트 처리기의 시작 부분에 다음 코드를 추가합니다. 잘못된 그림 파일이 업로드된 경우 브로셔를 웹 서버의 파일 시스템에 저장하지 않기 때문에 이 코드는 브로셔 파일을 저장하는 코드 앞에 오는 것이 중요합니다.
' Reference the PictureUpload FileUpload
Dim PictureUpload As FileUpload = _
CType(categories.Rows(e.RowIndex).FindControl("PictureUpload"), _
FileUpload)
If PictureUpload.HasFile Then
' Make sure the picture upload is valid
If ValidPictureUpload(PictureUpload) Then
e.NewValues("picture") = PictureUpload.FileBytes
Else
' Invalid file upload, cancel update and exit event handler
e.Cancel = True
Exit Sub
End If
End If
이 메서드는 ValidPictureUpload(FileUpload)
FileUpload 컨트롤을 유일한 입력 매개 변수로 사용하고 업로드된 파일의 확장자를 확인하여 업로드된 파일이 JPG인지 확인합니다. 그림 파일이 업로드된 경우에만 호출됩니다. 업로드된 파일이 없으면 그림 매개 변수가 설정되지 않으므로 기본값인 .를 Nothing
사용합니다. 그림을 업로드하고 ValidPictureUpload
반환 True
picture
하면 매개 변수에 업로드된 이미지의 이진 데이터가 할당됩니다. 메서드가 반환False
되면 업데이트 워크플로가 취소되고 이벤트 처리기가 종료됩니다.
ValidPictureUpload(FileUpload)
DetailsView의 ItemInserting
이벤트 처리기에서 리팩터링된 메서드 코드는 다음과 같습니다.
Private Function ValidPictureUpload(ByVal PictureUpload As FileUpload) As Boolean
' Make sure that a JPG has been uploaded
If String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
".jpg", True) <> 0 AndAlso _
String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
".jpeg", True) <> 0 Then
UploadWarning.Text = _
"Only JPG documents may be used for a category's picture."
UploadWarning.Visible = True
Return False
Else
Return True
End If
End Function
8단계: 원래 범주 그림을 JPG로 바꾸기
원래 8개의 범주 그림은 OLE 헤더로 래핑된 비트맵 파일입니다. 기존 레코드의 이미지를 편집하는 기능을 추가했으므로 잠시 시간을 내어 이러한 비트맵을 JPG로 바꾸십시오. 현재 범주 그림을 계속 사용하려면 다음 단계를 수행하여 JPG로 변환할 수 있습니다.
- 비트맵 이미지를 하드 드라이브에 저장합니다. 브라우저에서
UpdatingAndDeleting.aspx
페이지를 방문하고 처음 8개 범주 각각에 대해 이미지를 마우스 오른쪽 단추로 클릭하고 그림을 저장하도록 선택합니다. - 선택한 이미지 편집기에서 이미지를 엽니다. 예를 들어 Microsoft Paint를 사용할 수 있습니다.
- 비트맵을 JPG 이미지로 저장합니다.
- JPG 파일을 사용하여 편집 인터페이스를 통해 범주 그림을 업데이트합니다.
범주를 편집하고 JPG 이미지를 업로드한 후에는 페이지가 처음 8개 범주의 그림에서 처음 78바이트를 제거하므로 이미지가 브라우저 DisplayCategoryPicture.aspx
에서 렌더링되지 않습니다. OLE 헤더 제거를 수행하는 코드를 제거하여 이 문제를 해결합니다. 이 DisplayCategoryPicture.aspx``Page_Load
작업을 수행한 후 이벤트 처리기에는 다음 코드만 있어야 합니다.
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim categoryID As Integer = _
Convert.ToInt32(Request.QueryString("CategoryID"))
' Get information about the specified category
Dim categoryAPI As New CategoriesBLL()
Dim categories As Northwind.CategoriesDataTable = _
categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID)
Dim category As Northwind.CategoriesRow = categories(0)
' For new categories, images are JPGs...
' Output HTTP headers providing information about the binary data
Response.ContentType = "image/jpeg"
' Output the binary data
Response.BinaryWrite(category.Picture)
End Sub
비고
UpdatingAndDeleting.aspx
페이지의 삽입 및 편집 인터페이스는 좀 더 개선이 필요합니다.
CategoryName
DetailsView 및 GridView의 BoundFields Description
는 TemplateFields로 변환되어야 합니다.
CategoryName
가 NULL
값을 허용하지 않으므로, RequiredFieldValidator를 반드시 추가해야 합니다. 그리고 TextBox는 Description
여러 줄로 구성된 TextBox로 바꾸는 것이 좋을 것입니다. 나는 이 마지막 손질을 당신의 연습 문제로 남겨둡니다.
요약
이 자습서에서는 이진 데이터 작업을 완료합니다. 이 자습서와 이전 세 가지에서는 이진 데이터를 파일 시스템에 저장하거나 데이터베이스 내에서 직접 저장할 수 있는 방법을 알아보았습니다. 사용자는 하드 드라이브에서 파일을 선택하고 웹 서버에 업로드하여 시스템에 이진 데이터를 제공합니다. 이 데이터를 파일 시스템에 저장하거나 데이터베이스에 삽입할 수 있습니다. ASP.NET 2.0에는 끌어서 놓기처럼 쉽게 인터페이스를 제공하는 FileUpload 컨트롤이 포함되어 있습니다. 그러나 파일 업로드 튜토리얼에서 설명한 것처럼 FileUpload 컨트롤은 비교적 작은 파일 업로드에만 적합하며, 크기가 이상적으로는 1메가바이트를 넘지 않아야 합니다. 또한 업로드된 데이터를 기본 데이터 모델과 연결하는 방법뿐만 아니라 기존 레코드에서 이진 데이터를 편집하고 삭제하는 방법도 살펴보했습니다.
다음 자습서 집합에서는 다양한 캐싱 기술을 살펴봅니다. 캐싱은 비용이 많이 드는 작업의 결과를 가져와 더 빠르게 액세스할 수 있는 위치에 저장하여 애플리케이션의 전반적인 성능을 개선하는 방법을 제공합니다.
행복한 프로그래밍!
작성자 정보
7개의 ASP/ASP.NET 책의 저자이자 4GuysFromRolla.com 창립자인 Scott Mitchell은 1998년부터 Microsoft 웹 기술을 연구해 왔습니다. Scott은 독립 컨설턴트, 트레이너 및 작가로 일합니다. 그의 최신 책은 Sams Teach Yourself ASP.NET 2.0 in 24 Hours입니다. 그에게 mitchell@4GuysFromRolla.com으로 연락할 수 있습니다.
특별히 감사드립니다.
이 자습서 시리즈는 많은 유용한 검토자가 검토했습니다. 이 자습서의 수석 검토자는 테레사 머피였습니다. 예정된 MSDN 문서를 검토하는 데 관심이 있으신가요? 그렇다면 mitchell@4GuysFromRolla.com으로 메시지를 보내 주세요.