새 레코드를 추가할 때 파일 업로드 옵션 포함(C#)Including a File Upload Option When Adding a New Record (C#)

Scott Mitchellby Scott Mitchell

샘플 앱 다운로드 또는 PDF 다운로드Download Sample App or Download PDF

이 자습서에서는 사용자가 텍스트 데이터를 입력 하 고 이진 파일을 업로드 하는 데 사용할 수 있는 웹 인터페이스를 만드는 방법을 보여 줍니다.This tutorial shows how to create a Web interface that allows the user to both enter text data and upload binary files. 이진 데이터를 저장 하는 데 사용할 수 있는 옵션을 설명 하기 위해 한 파일은 데이터베이스에 저장 되 고 다른 파일은 파일 시스템에 저장 됩니다.To illustrate the options available to store binary data, one file will be saved in the database while the other is stored in the file system.

소개Introduction

이전 두 자습서에서는 응용 프로그램 데이터 모델에 연결 된 이진 데이터를 저장 하는 기술에 대해 살펴보았습니다. FileUpload 컨트롤을 사용 하 여 클라이언트에서 웹 서버로 파일을 전송 하는 방법 및 데이터에이 이진 데이터를 제공 하는 방법에 대해 살펴보았습니다. eb 컨트롤입니다.In the previous two tutorials we explored techniques for storing binary data that is associated with the application s data model, looked at how to use the FileUpload control to send files from the client to the web server, and saw how to present this binary data in a data Web control. 그러나 업로드 된 데이터를 데이터 모델에 연결 하는 방법에 대해서는 아직 설명 하지 않았습니다.We ve yet to talk about how to associate uploaded data with the data model, though.

이 자습서에서는 새 범주를 추가 하는 웹 페이지를 만듭니다.In this tutorial we will create a web page to add a new category. 범주 이름 및 설명에 대 한 텍스트 상자 외에도이 페이지에는 새 category s 그림에 대 한 두 개의 FileUpload 컨트롤과 브로슈어에 하나씩 포함 해야 합니다.In addition to TextBoxes for the category s name and description, this page will need to include two FileUpload controls one for the new category s picture and one for the brochure. 업로드 된 그림은 새 레코드의 Picture 열에 직접 저장 되는 반면, 브로슈어는 새 레코드의 BrochurePath 열에 저장 된 파일의 경로를 사용 하 여 ~/Brochures 폴더에 저장 됩니다.The uploaded picture will be stored directly in the new record s Picture column, whereas the brochure will be saved to the ~/Brochures folder with the path to the file saved in the new record s BrochurePath column.

이 새 웹 페이지를 만들기 전에 아키텍처를 업데이트 해야 합니다.Before creating this new web page, we'll need to update the architecture. CategoriesTableAdapter s 주 쿼리는 Picture 열을 검색 하지 않습니다.The CategoriesTableAdapter s main query does not retrieve the Picture column. 따라서 자동 생성 된 Insert 메서드에는 CategoryName, DescriptionBrochurePath 필드에 대 한 입력만 있습니다.Consequently, the auto-generated Insert method only has inputs for the CategoryName, Description, and BrochurePath fields. 따라서 Categories 필드 4 개 모두에 대해 요청 하는 추가 메서드를 TableAdapter에 만들어야 합니다.Therefore, we need to create an additional method in the TableAdapter that prompts for all four Categories fields. 비즈니스 논리 계층의 CategoriesBLL 클래스도 업데이트 해야 합니다.The CategoriesBLL class in the Business Logic Layer will also need to be updated.

1 단계:CategoriesTableAdapterInsertWithPicture메서드 추가Step 1: Adding anInsertWithPictureMethod to theCategoriesTableAdapter

데이터 액세스 계층 만들기 자습서로 CategoriesTableAdapter을 다시 만들 때 주 쿼리를 기반으로 INSERT, UPDATEDELETE 문을 자동으로 생성 하도록 구성 했습니다.When we created the CategoriesTableAdapter back in the Creating a Data Access Layer tutorial, we configured it to automatically generate INSERT, UPDATE, and DELETE statements based on the main query. 또한 Insert, UpdateDelete메서드를 만든 DB Direct 방법을 사용 하도록 TableAdapter에 지시 했습니다.Moreover, we instructed the TableAdapter to employ the DB Direct approach, which created the methods Insert, Update, and Delete. 이러한 메서드는 자동 생성 된 INSERT, UPDATEDELETE 문을 실행 하므로 주 쿼리에서 반환 된 열을 기반으로 입력 매개 변수를 그대로 사용 합니다.These methods execute the auto-generated INSERT, UPDATE, and DELETE statements and, consequently, accept input parameters based on the columns returned by the main query. 파일 업로드 자습서에서 BrochurePath 열을 사용 하도록 CategoriesTableAdapter s 주 쿼리를 확장 했습니다.In the Uploading Files tutorial we augmented the CategoriesTableAdapter s main query to use the BrochurePath column.

CategoriesTableAdapter s 주 쿼리가 Picture 열을 참조 하지 않으므로 새 레코드를 추가 하거나 기존 레코드를 Picture 열의 값으로 업데이트할 수 없습니다.Since the CategoriesTableAdapter s main query does not reference the Picture column, we can neither add a new record nor update an existing record with a value for the Picture column. 이 정보를 캡처하기 위해 특히 이진 데이터를 사용 하 여 레코드를 삽입 하는 데 사용 되는 TableAdapter에 새 메서드를 만들거나 자동 생성 된 INSERT 문을 사용자 지정할 수 있습니다.In order to capture this information, we can either create a new method in the TableAdapter that is used specifically to insert a record with binary data or we can customize the auto-generated INSERT statement. 자동 생성 된 INSERT 문을 사용자 지정 하는 데 문제가 있으면 마법사에서 사용자 지정 내용을 덮어쓸 위험이 있습니다.The problem with customizing the auto-generated INSERT statement is that we risk having our customizations overwritten by the wizard. 예를 들어 INSERT 문을 사용자 지정 하 여 Picture 열을 사용 한다고 가정 합니다.For example, imagine that we customized the INSERT statement to include use of the Picture column. 이는 범주 s 그림의 이진 데이터에 대 한 추가 입력 매개 변수를 포함 하도록 TableAdapter s Insert 메서드를 업데이트 합니다.This would update the TableAdapter s Insert method to include an additional input parameter for the category s picture s binary data. 그런 다음이 DAL 메서드를 사용 하 고 프레젠테이션 계층을 통해이 BLL 메서드를 호출 하는 비즈니스 논리 계층에서 메서드를 만들 수 있으며, 모든 것이 wonderfully 작동 합니다.We could then create a method in the Business Logic Layer to use this DAL method and invoke this BLL method through the Presentation Layer, and everything would work wonderfully. 즉, 다음 번에 TableAdapter 구성 마법사를 통해 TableAdapter를 구성할 때까지입니다.That is, until the next time we configured the TableAdapter through the TableAdapter Configuration wizard. 마법사가 완료 되는 즉시 INSERT 문에 대 한 사용자 지정을 덮어쓰므로 Insert 메서드가 이전 형식으로 되돌아가고 코드는 더 이상 컴파일되지 않습니다.As soon as the wizard completed, our customizations to the INSERT statement would be overwritten, the Insert method would revert to its old form, and our code would no longer compile!

Note

임시 SQL 문 대신 저장 프로시저를 사용 하는 경우에는 문제가 되지 않습니다.This annoyance is a non-issue when using stored procedures instead of ad-hoc SQL statements. 이후 자습서에서는 데이터 액세스 계층에서 임시 SQL 문을 사용 하는 대신 저장 프로시저를 사용 하는 방법을 살펴봅니다.A future tutorial will explore using stored procedures in lieu of ad-hoc SQL statements in the Data Access Layer.

자동 생성 된 SQL 문을 사용자 지정 하는 대신이 잠재적 골칫거리을 방지 하기 위해에서 TableAdapter에 대 한 새 메서드를 만들 수 있습니다.To avoid this potential headache, rather than customizing the auto-generated SQL statements let s instead create a new method for the TableAdapter. InsertWithPicture이라는이 메서드는 CategoryName, Description, BrochurePathPicture 열에 대 한 값을 허용 하 고 네 개의 값을 모두 새 레코드에 저장 하는 INSERT 문을 실행 합니다.This method, named InsertWithPicture, will accept values for the CategoryName, Description, BrochurePath, and Picture columns and execute an INSERT statement that stores all four values in a new record.

형식화 된 데이터 집합을 열고 디자이너에서 CategoriesTableAdapter s 헤더를 마우스 오른쪽 단추로 클릭 한 다음 상황에 맞는 메뉴에서 쿼리 추가를 선택 합니다.Open the Typed DataSet and, from the Designer, right-click on the CategoriesTableAdapter s header and choose Add Query from the context menu. Tableadapter 쿼리가 데이터베이스에 액세스 하는 방법을 묻는 TableAdapter 쿼리 구성 마법사가 시작 됩니다.This launches the TableAdapter Query Configuration Wizard, which begins by asking us how the TableAdapter query should access the database. SQL 문 사용을 선택 하 고 다음을 클릭 합니다.Choose Use SQL statements and click Next. 다음 단계에서는 생성할 쿼리 유형을 묻는 메시지를 표시 합니다.The next step prompts for the type of query to be generated. Categories 테이블에 새 레코드를 추가 하는 쿼리를 다시 작성 하기 때문에 삽입을 선택 하 고 다음을 클릭 합니다.Since we re creating a query to add a new record to the Categories table, choose INSERT and click Next.

삽입 옵션 선택 합니다.Select the INSERT Option

그림 1: 삽입 옵션 선택 (전체 크기 이미지를 보려면 클릭)Figure 1: Select the INSERT Option (Click to view full-size image)

이제 INSERT SQL 문을 지정 해야 합니다.We now need to specify the INSERT SQL statement. 마법사에서는 TableAdapter 주 쿼리에 해당 하는 INSERT 문을 자동으로 제안 합니다.The wizard automatically suggests an INSERT statement corresponding to the TableAdapter s main query. 이 경우 CategoryName, DescriptionBrochurePath 값을 삽입 하는 INSERT 문입니다.In this case, it s an INSERT statement that inserts the CategoryName, Description, and BrochurePath values. Picture 열이 @Picture 매개 변수와 함께 포함 되도록 문을 업데이트 합니다. 예를 들면 다음과 같습니다.Update the statement so that the Picture column is included along with a @Picture parameter, like so:

INSERT INTO [Categories] 
    ([CategoryName], [Description], [BrochurePath], [Picture]) 
VALUES 
    (@CategoryName, @Description, @BrochurePath, @Picture)

마법사의 마지막 화면에서 새 TableAdapter 메서드의 이름을 묻는 메시지를 표시 합니다.The final screen of the wizard asks us to name the new TableAdapter method. InsertWithPicture를 입력 하 고 마침을 클릭 합니다.Enter InsertWithPicture and click Finish.

새 TableAdapter 메서드 InsertWithPicture의 이름을 합니다.Name the New TableAdapter Method InsertWithPicture

그림 2: 새 TableAdapter 메서드 이름 InsertWithPicture (전체 크기 이미지를 보려면 클릭)Figure 2: Name the New TableAdapter Method InsertWithPicture (Click to view full-size image)

2 단계: 비즈니스 논리 계층 업데이트Step 2: Updating the Business Logic Layer

프레젠테이션 계층은 데이터 액세스 계층으로 직접 이동 하는 것이 아니라 비즈니스 논리 계층과만 인터페이스 해야 하기 때문에 방금 만든 DAL 메서드 (InsertWithPicture)를 호출 하는 BLL 메서드를 만들어야 합니다.Since the Presentation Layer should only interface with the Business Logic Layer rather than bypassing it to go directly to the Data Access Layer, we need to create a BLL method that invokes the DAL method we just created (InsertWithPicture). 이 자습서에서는 입력으로 3 개의 string s와 byte 배열을 허용 하는 InsertWithPicture 라는 CategoriesBLL 클래스에 메서드를 만듭니다.For this tutorial, create a method in the CategoriesBLL class named InsertWithPicture that accepts as input three string s and a byte array. string 입력 매개 변수는 범주 이름, 설명 및 브로셔 파일 경로에 대 한 것 이지만 byte 배열은 범주 그림의 이진 콘텐츠를 위한 것입니다.The string input parameters are for the category s name, description, and brochure file path, while the byte array is for the binary contents of the category s picture. 다음 코드에 나와 있는 것 처럼이 BLL 메서드는 해당 DAL 메서드를 호출 합니다.As the following code shows, this BLL method invokes the corresponding DAL method:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Insert, false)] 
public void InsertWithPicture(string categoryName, string description, 
    string brochurePath, byte[] picture)
{
    Adapter.InsertWithPicture(categoryName, description, brochurePath, picture);
}

Note

InsertWithPicture 메서드를 BLL에 추가 하기 전에 형식화 된 데이터 집합을 저장 했는지 확인 합니다.Make sure that you have saved the Typed DataSet before adding the InsertWithPicture method to the BLL. CategoriesTableAdapter 클래스 코드는 형식화 된 데이터 집합을 기반으로 자동 생성 되므로, 먼저 변경 내용을 형식화 된 데이터 집합에 저장 하지 않은 경우 Adapter 속성이 InsertWithPicture 메서드에 대해 인식 하지 못합니다.Since the CategoriesTableAdapter class code is auto-generated based on the Typed DataSet, if you don t first save your changes to the Typed DataSet the Adapter property won't know about the InsertWithPicture method.

3 단계: 기존 범주 및 해당 이진 데이터 나열Step 3: Listing the Existing Categories and their Binary Data

이 자습서에서는 최종 사용자가 시스템에 새 범주를 추가 하 여 새 범주에 대 한 그림과 브로슈어를 제공 하는 데 사용할 수 있는 페이지를 만듭니다.In this tutorial we will create a page that allows an end user to add a new category to the system, providing a picture and brochure for the new category. 이전 자습서 에서는 Templatefield로 변환 및 ImageField와 함께 GridView를 사용 하 여 각 범주 이름, 설명, 그림 및 브로슈어를 다운로드 하는 링크를 표시 했습니다.In the preceding tutorial we used a GridView with a TemplateField and ImageField to display each category s name, description, picture, and a link to download its brochure. 에서이 자습서에 대 한 해당 기능을 복제 하 여 모든 기존 범주를 나열 하 고 새 범주를 만들 수 있는 페이지를 만들어 보겠습니다.Let s replicate that functionality for this tutorial, creating a page that both lists all existing categories and allows for new ones to be created.

먼저 BinaryData 폴더에서 DisplayOrDownload.aspx 페이지를 엽니다.Start by opening the DisplayOrDownload.aspx page from the BinaryData folder. 원본 뷰로 이동 하 고 GridView 및 ObjectDataSource s 선언 구문을 복사 하 여 UploadInDetailsView.aspx<asp:Content> 요소 내에 붙여 넣습니다.Go to the Source view and copy the GridView and ObjectDataSource s declarative syntax, pasting it within the <asp:Content> element in UploadInDetailsView.aspx. 또한 DisplayOrDownload.aspx의 코드 숨김이 클래스에서 GenerateBrochureLink 메서드를 UploadInDetailsView.aspx로 복사 하는 것을 잊지 마십시오.Also, don t forget to copy over the GenerateBrochureLink method from the code-behind class of DisplayOrDownload.aspx to UploadInDetailsView.aspx.

선언 구문을 복사 하 여 DisplayOrDownload에서 UploadInDetailsView에 붙여넣습니다.Copy and Paste the Declarative Syntax from DisplayOrDownload.aspx to UploadInDetailsView.aspx

그림 3: DisplayOrDownload.aspx의 선언 구문을 복사 하 여 UploadInDetailsView.aspx에 붙여넣기 (전체 크기 이미지를 보려면 클릭)Figure 3: Copy and Paste the Declarative Syntax from DisplayOrDownload.aspx to UploadInDetailsView.aspx (Click to view full-size image)

선언적 구문과 GenerateBrochureLink 메서드를 UploadInDetailsView.aspx 페이지로 복사한 후 브라우저를 통해 페이지를 확인 하 여 모든 항목이 올바르게 복사 되었는지 확인 합니다.After copying the declarative syntax and GenerateBrochureLink method over to the UploadInDetailsView.aspx page, view the page through a browser to ensure that everything was copied over correctly. 브로슈어를 다운로드할 수 있는 링크와 범주 그림을 포함 하는 8 개의 범주가 나열 된 GridView가 표시 됩니다.You should see a GridView listing the eight categories that includes a link to download the brochure as well as the category s picture.

이제 각 범주를 이진 데이터와 함께 표시 합니다.You Should Now See Each Category Along with Its Binary Data

그림 4: 이제 각 범주가 이진 데이터와 함께 표시 됩니다 (전체 크기 이미지를 보려면 클릭).Figure 4: You Should Now See Each Category Along with Its Binary Data (Click to view full-size image)

4 단계: 삽입을 지원 하도록CategoriesDataSource구성Step 4: Configuring theCategoriesDataSourceto Support Inserting

Categories GridView에서 사용 하는 CategoriesDataSource ObjectDataSource는 현재 데이터를 삽입 하는 기능을 제공 하지 않습니다.The CategoriesDataSource ObjectDataSource used by the Categories GridView currently does not provide the ability to insert data. 이 데이터 소스 컨트롤을 통해 삽입을 지원 하기 위해 Insert 메서드를 기본 개체인 CategoriesBLL의 메서드에 매핑해야 합니다.In order to support inserting through this data source control, we need to map its Insert method to a method in its underlying object, CategoriesBLL. 특히 2 단계, InsertWithPicture에서 다시 추가한 CategoriesBLL 메서드에 매핑하려고 합니다.In particular, we want to map it to the CategoriesBLL method we added back in Step 2, InsertWithPicture.

먼저 ObjectDataSource s 스마트 태그에서 데이터 소스 구성 링크를 클릭 합니다.Start by clicking the Configure Data Source link from the ObjectDataSource s smart tag. 첫 번째 화면에는 데이터 원본이 작동 하도록 구성 된 개체 CategoriesBLL표시 됩니다.The first screen shows the object the data source is configured to work with, CategoriesBLL. 이 설정을 그대로 두고 다음을 클릭 하 여 데이터 메서드 정의 화면으로 이동 합니다.Leave this setting as-is and click Next to advance to the Define Data Methods screen. 삽입 탭으로 이동 하 고 드롭다운 목록에서 InsertWithPicture 메서드를 선택 합니다.Move to the INSERT tab and pick the InsertWithPicture method from the drop-down list. 마침을 클릭하여 마법사를 완료합니다.Click Finish to complete the wizard.

InsertWithPicture 메서드를 사용 하도록 ObjectDataSource를 구성 Configure the ObjectDataSource to use the InsertWithPicture Method

그림 5: InsertWithPicture 메서드를 사용 하도록 ObjectDataSource 구성 (전체 크기 이미지를 보려면 클릭)Figure 5: Configure the ObjectDataSource to use the InsertWithPicture Method (Click to view full-size image)

Note

마법사가 완료 되 면 Visual Studio에서 필드와 키를 새로 고칠지 여부를 묻는 메시지를 표시할 수 있습니다. 그러면 데이터 웹 컨트롤 필드가 다시 생성 됩니다.Upon completing the wizard, Visual Studio may ask if you want to Refresh Fields and Keys, which will regenerate the data Web controls fields. 예를 선택 하면 수행한 필드 사용자 지정 항목을 덮어쓰기 때문에 아니요를 선택 합니다.Choose No, because choosing Yes will overwrite any field customizations you may have made.

마법사를 완료 한 후에는 다음 선언 태그에서 보여 주는 것 처럼 ObjectDataSource에 InsertMethod 속성 값과 4 개의 범주 열에 대 한 InsertParameters 포함 됩니다.After completing the wizard, the ObjectDataSource will now include a value for its InsertMethod property as well as InsertParameters for the four category columns, as the following declarative markup illustrates:

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories" 
    TypeName="CategoriesBLL" InsertMethod="InsertWithPicture">
    <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>
</asp:ObjectDataSource>

5 단계: 삽입 인터페이스 만들기Step 5: Creating the Inserting Interface

데이터 삽입, 업데이트 및 삭제에 대 한 개요에서 처음에 설명한 것 처럼 DetailsView 컨트롤은 삽입을 지 원하는 데이터 소스 컨트롤을 사용할 때 사용할 수 있는 기본 제공 삽입 인터페이스를 제공 합니다.As first covered in the An Overview of Inserting, Updating, and Deleting Data, the DetailsView control provides a built-in inserting interface that can be utilized when working with a data source control that supports inserting. 삽입 인터페이스를 영구적으로 렌더링 하 여 사용자가 새 범주를 신속 하 게 추가할 수 있도록 하는 GridView 위의이 페이지에 DetailsView 컨트롤을 추가 해 보겠습니다.Let s add a DetailsView control to this page above the GridView that will permanently render its inserting interface, allowing a user to quickly add a new category. DetailsView에 새 범주를 추가 하면 그 아래의 GridView가 자동으로 새로 고쳐 새 범주를 표시 합니다.Upon adding a new category in the DetailsView, the GridView beneath it will automatically refresh and display the new category.

먼저 도구 상자의 DetailsView을 GridView 위의 디자이너로 끌어 옵니다. ID 속성을 NewCategory로 설정 하 고 HeightWidth 속성 값을 선택 취소 합니다.Start by dragging a DetailsView from the Toolbox onto the Designer above the GridView, setting its ID property to NewCategory and clearing out the Height and Width property values. DetailsView의 스마트 태그에서 기존 CategoriesDataSource에 바인딩한 다음 삽입 사용 확인란을 선택 합니다.From the DetailsView s smart tag, bind it to the existing CategoriesDataSource and then check the Enable Inserting checkbox.

는 DetailsView을 범주 데이터 원본에 바인딩하고 삽입을 사용 하도록 설정 합니다.Bind the DetailsView to the CategoriesDataSource and Enable Inserting

그림 6: CategoriesDataSource에 DetailsView 바인딩 및 삽입 사용 (전체 크기 이미지를 보려면 클릭)Figure 6: Bind the DetailsView to the CategoriesDataSource and Enable Inserting (Click to view full-size image)

삽입 인터페이스에서 DetailsView을 영구적으로 렌더링 하려면 해당 DefaultMode 속성을 Insert로 설정 합니다.To permanently render the DetailsView in its inserting interface, set its DefaultMode property to Insert.

BoundField는 BrochurePath 속성이 CategoryID로 설정 되어 있으므로 삽입 인터페이스에서 렌더링 되지 않지만, CategoryName, Description, NumberOfProductsInsertVisible BoundFields에는 5 개의 CategoryID있습니다.falseNote that the DetailsView has five BoundFields CategoryID, CategoryName, Description, NumberOfProducts, and BrochurePath although the CategoryID BoundField is not rendered in the inserting interface because its InsertVisible property is set to false. 이러한 BoundFields는 GetCategories() 메서드에서 반환 되는 열 이기 때문에 존재 합니다 .이는 ObjectDataSource가 데이터를 검색 하기 위해 호출 하는 것입니다.These BoundFields exists because they are the columns returned by the GetCategories() method, which is what the ObjectDataSource invokes to retrieve its data. 그러나 삽입을 위해 사용자가 NumberOfProducts에 대 한 값을 지정할 수 있도록 합니다.For inserting, however, we don t want to let the user specify a value for NumberOfProducts. 또한 새 범주에 대 한 그림을 업로드 하 고 브로슈어에 PDF를 업로드 하도록 허용 해야 합니다.Moreover, we need to allow them to upload a picture for the new category as well as upload a PDF for the brochure.

DetailsView에서 NumberOfProducts BoundField를 완전히 제거한 다음 CategoryNameHeaderText 속성 및 BrochurePath BoundFields를 각각 Category 및 브로셔로 업데이트 합니다.Remove the NumberOfProducts BoundField from the DetailsView altogether and then update the HeaderText properties of the CategoryName and BrochurePath BoundFields to Category and Brochure, respectively. 그런 다음 BrochurePath BoundField를 Templatefield로 변환로 변환 하 고 그림에 대 한 새 Templatefield로 변환를 추가 하 여이 새 Templatefield로 변환에 그림의 HeaderText 값을 제공 합니다.Next, convert the BrochurePath BoundField into a TemplateField and add a new TemplateField for the picture, giving this new TemplateField a HeaderText value of Picture. BrochurePath Templatefield로 변환와 CommandField Templatefield로 변환 Picture를 이동 합니다.Move the Picture TemplateField so that it is between the BrochurePath TemplateField and CommandField.

범주 데이터 원본에 DetailsView 바인딩 및 삽입 사용

그림 7: CategoriesDataSource에 DetailsView 바인딩 및 삽입 사용Figure 7: Bind the DetailsView to the CategoriesDataSource and Enable Inserting

필드 편집 대화 상자를 통해 BrochurePath BoundField를 Templatefield로 변환로 변환한 경우 Templatefield로 변환에는 ItemTemplate, EditItemTemplateInsertItemTemplate포함 됩니다.If you converted the BrochurePath BoundField into a TemplateField through the Edit Fields dialog box, the TemplateField includes an ItemTemplate, EditItemTemplate, and InsertItemTemplate. 그러나 InsertItemTemplate 필요한 경우에만 다른 두 템플릿을 제거할 수 있습니다.Only the InsertItemTemplate is needed, however, so feel free to remove the other two templates. 이 시점에서 DetailsView의 선언적 구문은 다음과 같습니다.At this point your DetailsView s declarative syntax should look like the following:

<asp:DetailsView ID="NewCategory" runat="server" AutoGenerateRows="False" 
    DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource" 
    DefaultMode="Insert">
    <Fields>
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="CategoryID" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            SortExpression="CategoryName" />
        <asp:BoundField DataField="Description" HeaderText="Description" 
            SortExpression="Description" />
        <asp:TemplateField HeaderText="Brochure" SortExpression="BrochurePath">
            <InsertItemTemplate>
                <asp:TextBox ID="TextBox1" runat="server"
                    Text='<%# Bind("BrochurePath") %>'></asp:TextBox>
            </InsertItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Picture"></asp:TemplateField>
        <asp:CommandField ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

브로셔 및 그림 필드에 대 한 FileUpload 컨트롤 추가Adding FileUpload Controls for the Brochure and Picture Fields

현재 BrochurePath Templatefield로 변환 s InsertItemTemplate에는 TextBox가 포함 되어 있지만 Picture Templatefield로 변환에는 템플릿이 포함 되어 있지 않습니다.Presently, the BrochurePath TemplateField s InsertItemTemplate contains a TextBox, while the Picture TemplateField does not contain any templates. FileUpload 컨트롤을 사용 하려면 이러한 두 Templatefield로 변환 s InsertItemTemplate를 업데이트 해야 합니다.We need to update these two TemplateField s InsertItemTemplate s to use FileUpload controls.

DetailsView의 스마트 태그에서 템플릿 편집 옵션을 선택한 다음 드롭다운 목록에서 BrochurePath Templatefield로 변환 s InsertItemTemplate를 선택 합니다.From the DetailsView s smart tag, choose the Edit Templates option and then select the BrochurePath TemplateField s InsertItemTemplate from the drop-down list. 텍스트 상자를 제거한 다음 FileUpload 컨트롤을 도구 상자에서 템플릿으로 끌어 옵니다.Remove the TextBox and then drag a FileUpload control from the Toolbox into the template. FileUpload 컨트롤 s IDBrochureUpload로 설정 합니다.Set the FileUpload control s ID to BrochureUpload. 마찬가지로 Picture Templatefield로 변환 s InsertItemTemplate에 FileUpload 컨트롤을 추가 합니다.Similarly, add a FileUpload control to the Picture TemplateField s InsertItemTemplate. 이 FileUpload 컨트롤 ID PictureUpload로 설정 합니다.Set this FileUpload control s ID to PictureUpload.

FileUpload 컨트롤을 InsertItemTemplate에 추가 Add a FileUpload Control to the InsertItemTemplate

그림 8: InsertItemTemplate에 FileUpload 컨트롤 추가 (전체 크기 이미지를 보려면 클릭)Figure 8: Add a FileUpload Control to the InsertItemTemplate (Click to view full-size image)

이러한 추가 작업을 수행한 후에는 두 개의 Templatefield로 변환 s 선언 구문이 다음과 같이 됩니다.After making these additions, the two TemplateField s declarative syntax will be:

<asp:TemplateField HeaderText="Brochure" SortExpression="BrochurePath">
    <InsertItemTemplate>
        <asp:FileUpload ID="BrochureUpload" runat="server" />
    </InsertItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Picture">
    <InsertItemTemplate>
        <asp:FileUpload ID="PictureUpload" runat="server" />
    </InsertItemTemplate>
</asp:TemplateField>

사용자가 새 범주를 추가 하는 경우 브로슈어 및 그림이 올바른 파일 형식 인지 확인 하려고 합니다.When a user adds a new category, we want to ensure that the brochure and picture are of the correct file type. 브로슈어에 대해 사용자는 PDF를 제공 해야 합니다.For the brochure, the user must supply a PDF. 그림의 경우 이미지 파일을 업로드 하는 데 사용자가 필요 하지만, Gif 또는 JPGs 같은 특정 형식의 이미지 파일 또는 이미지 파일만 허용 하나요 ?For the picture, we need the user to upload an image file, but do we allow any image file or only image files of a particular type, such as GIFs or JPGs? 다양 한 파일 형식을 허용 하기 위해 파일 형식을 캡처하는 열을 포함 하도록 Categories 스키마를 확장 하 여 DisplayCategoryPicture.aspxResponse.ContentType를 통해이 형식을 클라이언트에 보낼 수 있도록 해야 합니다.In order to allow for different file types, we d need to extend the Categories schema to include a column that captures the file type so that this type can be sent to the client through Response.ContentType in DisplayCategoryPicture.aspx. 이러한 열이 없기 때문에 특정 이미지 파일 형식만 제공 하도록 사용자를 제한 하는 것이 좋습니다.Since we don t have such a column, it would be prudent to restrict users to only providing a specific image file type. Categories 테이블 s 기존 이미지는 비트맵 이지만 JPGs는 웹을 통해 제공 되는 이미지에 대 한 보다 적절 한 파일 형식입니다.The Categories table s existing images are bitmaps, but JPGs are a more appropriate file format for images served over the web.

사용자가 잘못 된 파일 형식을 업로드 하는 경우 삽입을 취소 하 고 문제를 나타내는 메시지를 표시 해야 합니다.If a user uploads an incorrect file type, we need to cancel the insert and display a message indicating the problem. DetailsView 아래에 Label 웹 컨트롤을 추가 합니다.Add a Label Web control beneath the DetailsView. ID 속성을 UploadWarning로 설정 하 고 Text 속성을 지우고 CssClass 속성을 경고로 설정 하 고 VisibleEnableViewState 속성을 false로 설정 합니다.Set its ID property to UploadWarning, clear out its Text property, set the CssClass property to Warning, and the Visible and EnableViewState properties to false. Warning CSS 클래스는 Styles.css에서 정의 되며 텍스트를 크게, 빨강, 기울임꼴, 굵은 글꼴로 렌더링 합니다.The Warning CSS class is defined in Styles.css and renders the text in a large, red, italicized, bold font.

Note

이상적으로 CategoryNameDescription BoundFields는 템플릿 필드 및 사용자 지정 된 삽입 인터페이스로 변환 됩니다.Ideally, the CategoryName and Description BoundFields would be converted to TemplateFields and their inserting interfaces customized. 예를 들어 Description 인터페이스를 삽입 하는 것은 여러 줄 텍스트 상자를 통해 보다 적합할 수 있습니다.The Description inserting interface, for example, would likely be better suited through a multi-line textbox. CategoryName 열에 NULL 값이 허용 되지 않으므로 사용자가 새 범주 이름에 대 한 값을 제공할 수 있도록 RequiredFieldValidator를 추가 해야 합니다.And since the CategoryName column does not accept NULL values, a RequiredFieldValidator should be added to ensure the user provides a value for the new category s name. 이러한 단계는 판독기에 대 한 연습으로 남아 있습니다.These steps are left as an exercise to the reader. 데이터 수정 인터페이스를 확대 하는 방법에 대 한 자세한 내용은 데이터 수정 인터페이스 사용자 지정 을 참조 하세요.Refer back to Customizing the Data Modification Interface for an in-depth look at augmenting the data modification interfaces.

6 단계: 업로드 된 브로슈어를 웹 서버의 파일 시스템에 저장Step 6: Saving the Uploaded Brochure to the Web Server s File System

사용자가 새 범주에 대 한 값을 입력 하 고 삽입 단추를 클릭 하면 포스트백이 발생 하 고 삽입 워크플로가 펼칩니다 됩니다.When the user enters the values for a new category and clicks the Insert button, a postback occurs and the inserting workflow unfolds. 먼저 DetailsView s ItemInserting 이벤트가 발생 합니다.First, the DetailsView s ItemInserting event fires. 그런 다음 ObjectDataSource s Insert() 메서드를 호출 하 여 Categories 테이블에 새 레코드를 추가 합니다.Next, the ObjectDataSource s Insert() method is invoked, which results in a new record being added to the Categories table. 그 후에는 DetailsView s ItemInserted 이벤트가 발생 합니다.After that, the DetailsView s ItemInserted event fires.

ObjectDataSource s Insert() 메서드를 호출 하기 전에 먼저 사용자가 적절 한 파일 형식이 업로드 되었는지 확인 한 다음 브로슈어 PDF를 웹 서버의 파일 시스템에 저장 해야 합니다.Before the ObjectDataSource s Insert() method is invoked, we must first ensure that the appropriate file types were uploaded by the user and then save the brochure PDF to the web server s file system. DetailsView s ItemInserting 이벤트에 대 한 이벤트 처리기를 만들고 다음 코드를 추가 합니다.Create an event handler for the DetailsView s ItemInserting event and add the following code:

// Reference the FileUpload control
FileUpload BrochureUpload = 
    (FileUpload)NewCategory.FindControl("BrochureUpload");
if (BrochureUpload.HasFile)
{
    // Make sure that a PDF has been uploaded
    if (string.Compare(System.IO.Path.GetExtension
        (BrochureUpload.FileName), ".pdf", true) != 0)
    {
        UploadWarning.Text = 
            "Only PDF documents may be used for a category's brochure.";
        UploadWarning.Visible = true;
        e.Cancel = true;
        return;
    }
}

이벤트 처리기는 DetailsView 템플릿에서 BrochureUpload FileUpload 컨트롤을 참조 하 여 시작 합니다.The event handler starts by referencing the BrochureUpload FileUpload control from the DetailsView s templates. 그런 다음 브로슈어를 업로드 한 경우 업로드 된 파일의 확장명을 검사 합니다.Then, if a brochure has been uploaded, the uploaded file s extension is examined. 확장이이 아니면입니다. 그런 다음, 경고가 표시 되 고, 삽입이 취소 되 고, 이벤트 처리기 실행이 종료 됩니다.If the extension is not .PDF, then a warning is displayed, the insert is cancelled, and the execution of the event handler ends.

Note

업로드 된 파일의 확장에 의존 하는 것은 업로드 된 파일이 PDF 문서 인지 확인 하기 위한 것입니다.Relying on the uploaded file s extension is not a sure-fire technique for ensuring that the uploaded file is a PDF document. 사용자는 .Brochure확장을 포함 하는 유효한 PDF 문서를 포함 하거나 PDF 문서가 아닌 문서를 가져와서 .pdf 확장명을 지정할 수 있습니다.The user could have a valid PDF document with the extension .Brochure, or could have taken a non-PDF document and given it a .pdf extension. 파일의 이진 콘텐츠는 파일 형식을 더 결론 내릴 확인 하기 위해 프로그래밍 방식으로 검사 해야 합니다.The file s binary content would need to be programmatically examined in order to more conclusively verify the file type. 그러나 이러한 철저 한 접근 방식은 일반적으로 과도 합니다. 대부분의 시나리오에서는 확장을 확인 하는 것 만으로도 충분 합니다.Such thorough approaches, though, are often overkill; checking the extension is sufficient for most scenarios.

파일 업로드 자습서에서 설명한 대로 파일 시스템에 파일을 저장할 때는 한 사용자의 업로드가 다른를 덮어쓰지 않도록 주의를 기울여야 합니다.As discussed in the Uploading Files tutorial, care must be taken when saving files to the file system so that one user s upload does not overwrite another s. 이 자습서에서는 업로드 된 파일과 동일한 이름을 사용 하려고 합니다.For this tutorial we will attempt to use the same name as the uploaded file. 그러나 동일한 파일 이름을 가진 파일이 ~/Brochures 디렉터리에 이미 있는 경우에는 고유한 이름을 찾을 때까지 끝에 번호를 추가 합니다.If there already exists a file in the ~/Brochures directory with that same file name, however, we'll append a number at the end until a unique name is found. 예를 들어 사용자가 Meats.pdf이라는 브로슈어 파일을 업로드 하지만 ~/Brochures 폴더에 이미 Meats.pdf 라는 파일이 있는 경우 저장 된 파일 이름을 Meats-1.pdf로 변경 합니다.For example, if the user uploads a brochure file named Meats.pdf, but there is already a file named Meats.pdf in the ~/Brochures folder, we'll change the saved file name to Meats-1.pdf. 이 경우 고유한 파일 이름을 찾을 때까지 Meats-2.pdf시도 합니다.If that exists, we'll try Meats-2.pdf, and so on, until a unique file name is found.

다음 코드는 File.Exists(path) 메서드 를 사용 하 여 지정 된 파일 이름을 가진 파일이 이미 있는지 여부를 확인 합니다.The following code uses the File.Exists(path) method to determine if a file already exists with the specified file name. 그렇다면 충돌을 찾을 수 없을 때까지 계속 해 서 브로슈어에 새 파일 이름을 시도 합니다.If so, it continues to try new file names for the brochure until no conflict is found.

const string BrochureDirectory = "~/Brochures/";
string brochurePath = BrochureDirectory + BrochureUpload.FileName;
string fileNameWithoutExtension = 
    System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName);
int iteration = 1;
while (System.IO.File.Exists(Server.MapPath(brochurePath)))
{
    brochurePath = string.Concat(BrochureDirectory, 
        fileNameWithoutExtension, "-", iteration, ".pdf");
    iteration++;
}

유효한 파일 이름이 발견 되 면 파일을 파일 시스템에 저장 해야 하며,이 파일 이름을 데이터베이스에 쓰도록 ObjectDataSource s brochurePath``InsertParameter 값을 업데이트 해야 합니다.Once a valid file name has been found, the file needs to be saved to the file system and the ObjectDataSource s brochurePath``InsertParameter value needs to be updated so that this file name is written to the database. 파일 업로드 자습서에서 돌아와서 FileUpload 컨트롤 SaveAs(path) 메서드를 사용 하 여 파일을 저장할 수 있습니다.As we saw back in the Uploading Files tutorial, the file can be saved using the FileUpload control s SaveAs(path) method. ObjectDataSource s brochurePath 매개 변수를 업데이트 하려면 e.Values 컬렉션을 사용 합니다.To update the ObjectDataSource s brochurePath parameter, use the e.Values collection.

// Save the file to disk and set the value of the brochurePath parameter
BrochureUpload.SaveAs(Server.MapPath(brochurePath));
e.Values["brochurePath"] = brochurePath;

7 단계: 업로드 된 그림을 데이터베이스에 저장Step 7: Saving the Uploaded Picture to the Database

업로드 된 그림을 새 Categories 레코드에 저장 하려면 업로드 한 이진 콘텐츠를 DetailsView s ItemInserting 이벤트의 ObjectDataSource s picture 매개 변수에 할당 해야 합니다.To store the uploaded picture in the new Categories record, we need to assign the uploaded binary content to the ObjectDataSource s picture parameter in the DetailsView s ItemInserting event. 그러나이 할당을 수행 하기 전에 먼저 업로드 된 그림이 JPG 이며 다른 이미지 형식이 아닌 JPG 인지 확인 해야 합니다.Before we make this assignment, however, we need to first make sure that the uploaded picture is a JPG and not some other image type. 6 단계에서와 같이에서 업로드 된 사진의 파일 확장명을 사용 하 여 해당 형식을 확인 하도록 합니다.As in Step 6, let s use the uploaded picture s file extension to ascertain its type.

Categories 테이블은 Picture 열에 NULL 값을 허용 하지만 모든 범주에는 현재 그림이 있습니다.While the Categories table allows NULL values for the Picture column, all categories currently have a picture. 에서이 페이지를 통해 새 범주를 추가할 때 사용자가 그림을 제공 하도록 합니다.Let s force the user to provide a picture when adding a new category through this page. 다음 코드에서는 그림이 업로드 되었으며 적절 한 확장이 있는지 확인 합니다.The following code checks to ensure that a picture has been uploaded and that it has an appropriate extension.

// Reference the FileUpload controls
FileUpload PictureUpload = (FileUpload)NewCategory.FindControl("PictureUpload");
if (PictureUpload.HasFile)
{
    // Make sure that a JPG has been uploaded
    if (string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), 
            ".jpg", true) != 0 &&
        string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), 
            ".jpeg", true) != 0)
    {
        UploadWarning.Text = 
            "Only JPG documents may be used for a category's picture.";
        UploadWarning.Visible = true;
        e.Cancel = true;
        return;
    }
}
else
{
    // No picture uploaded!
    UploadWarning.Text = 
        "You must provide a picture for the new category.";
    UploadWarning.Visible = true;
    e.Cancel = true;
    return;
}

이 코드는 6 단계의 코드 에 배치 해야 합니다. 그림 업로드에 문제가 발생 하는 경우 브로슈어 파일이 파일 시스템에 저장 되기 전에 이벤트 처리기가 종료 됩니다.This code should be placed before the code from Step 6 so that if there is a problem with the picture upload, the event handler will terminate before the brochure file is saved to the file system.

적절 한 파일을 업로드 했다고 가정 하 고 다음 코드 줄을 사용 하 여 업로드 된 이진 콘텐츠를 그림 매개 변수 s 값에 할당 합니다.Assuming that an appropriate file has been uploaded, assign the uploaded binary content to the picture parameter s value with the following line of code:

// Set the value of the picture parameter
e.Values["picture"] = PictureUpload.FileBytes;

CompleteItemInserting이벤트 처리기The CompleteItemInsertingEvent Handler

완전성을 위해 다음은 전체 ItemInserting 이벤트 처리기입니다.For completeness, here is the ItemInserting event handler in its entirety:

protected void NewCategory_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
    // Reference the FileUpload controls
    FileUpload PictureUpload = (FileUpload)NewCategory.FindControl("PictureUpload");
    if (PictureUpload.HasFile)
    {
        // Make sure that a JPG has been uploaded
        if (string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), 
                ".jpg", true) != 0 &&
            string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), 
                ".jpeg", true) != 0)
        {
            UploadWarning.Text = 
                "Only JPG documents may be used for a category's picture.";
            UploadWarning.Visible = true;
            e.Cancel = true;
            return;
        }
    }
    else
    {
        // No picture uploaded!
        UploadWarning.Text = 
            "You must provide a picture for the new category.";
        UploadWarning.Visible = true;
        e.Cancel = true;
        return;
    }
    // Set the value of the picture parameter
    e.Values["picture"] = PictureUpload.FileBytes;
    
    
    // Reference the FileUpload controls
    FileUpload BrochureUpload = 
        (FileUpload)NewCategory.FindControl("BrochureUpload");
    if (BrochureUpload.HasFile)
    {
        // Make sure that a PDF has been uploaded
        if (string.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName), 
            ".pdf", true) != 0)
        {
            UploadWarning.Text = 
                "Only PDF documents may be used for a category's brochure.";
            UploadWarning.Visible = true;
            e.Cancel = true;
            return;
        }
        const string BrochureDirectory = "~/Brochures/";
        string brochurePath = BrochureDirectory + BrochureUpload.FileName;
        string fileNameWithoutExtension = 
            System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName);
        int iteration = 1;
        while (System.IO.File.Exists(Server.MapPath(brochurePath)))
        {
            brochurePath = string.Concat(BrochureDirectory, fileNameWithoutExtension, 
                "-", iteration, ".pdf");
            iteration++;
        }
        // Save the file to disk and set the value of the brochurePath parameter
        BrochureUpload.SaveAs(Server.MapPath(brochurePath));
        e.Values["brochurePath"] = brochurePath;
    }
}

8 단계:DisplayCategoryPicture.aspx페이지 수정Step 8: Fixing theDisplayCategoryPicture.aspxPage

를 사용 하 여 마지막 몇 단계에서 생성 된 ItemInserting 이벤트 처리기 및 삽입 인터페이스를 테스트 합니다.Let s take a moment to test out the inserting interface and ItemInserting event handler that was created over the last few steps. 브라우저를 통해 UploadInDetailsView.aspx 페이지를 방문 하 여 범주를 추가 하 고, 그림을 생략 하거나, 비 JPG 그림 또는 비-PDF 브로슈어를 지정 합니다.Visit the UploadInDetailsView.aspx page through a browser and attempt to add a category, but omit the picture, or specify a non-JPG picture or a non-PDF brochure. 이러한 경우에는 오류 메시지가 표시 되 고 삽입 워크플로가 취소 됩니다.In any of these cases, an error message will be displayed and the insert workflow cancelled.

잘못 된 파일 형식이 업로드 된 경우 경고 메시지가 표시 됩니다.A Warning Message is Displayed If an Invalid File Type is Uploaded

그림 9: 잘못 된 파일 형식이 업로드 된 경우 경고 메시지가 표시 됨 (전체 크기 이미지를 보려면 클릭)Figure 9: A Warning Message is Displayed If an Invalid File Type is Uploaded (Click to view full-size image)

페이지에서 그림을 업로드 해야 하는 것을 확인 하 고 비 PDF 또는 비 JPG 파일을 수락 하지 않도록 확인 한 후에는 유효한 JPG 그림이 있는 새 범주를 추가 하 여 브로슈어 필드가 비어 있는 상태로 둡니다.Once you have verified that the page requires a picture to be uploaded and won't accept non-PDF or non-JPG files, add a new category with a valid JPG picture, leaving the Brochure field empty. 삽입 단추를 클릭 하면 페이지가 다시 게시 되 고 업로드 된 이미지의 이진 내용이 데이터베이스에 직접 저장 된 Categories 테이블에 새 레코드가 추가 됩니다.After clicking the Insert button, the page will postback and a new record will be added to the Categories table with the uploaded image s binary contents stored directly in the database. GridView가 업데이트 되 고 새로 추가 된 범주에 대 한 행을 표시 하지만 그림 10에 표시 된 것 처럼 새 범주 s 그림이 올바르게 렌더링 되지 않습니다.The GridView is updated and shows a row for the newly added category, but, as Figure 10 shows, the new category s picture is not rendered correctly.

새 범주 s 그림이 표시 되지 The New Category s Picture is not Displayed

그림 10: 새 범주 s 그림이 표시 되지 않음 (전체 크기 이미지를 보려면 클릭)Figure 10: The New Category s Picture is not Displayed (Click to view full-size image)

새 그림이 표시 되지 않는 이유는 지정 된 범주를 반환 하는 DisplayCategoryPicture.aspx 페이지가 OLE 헤더를 포함 하는 비트맵을 처리 하도록 구성 되어 있기 때문입니다.The reason the new picture is not displayed is because the DisplayCategoryPicture.aspx page that returns a specified category s picture is configured to process bitmaps that have an OLE header. 이 78 바이트 헤더는 Picture 열 s 이진 콘텐츠에서 제거 되어 클라이언트에 다시 전송 됩니다.This 78 byte header is stripped from the Picture column s binary contents before they are sent back to the client. 그러나 방금 새 범주에 대해 업로드 한 JPG 파일에는이 OLE 머리글이 없습니다. 따라서 필요한 바이트는 이미지 s의 이진 데이터에서 제거 됩니다.But the JPG file we just uploaded for the new category does not have this OLE header; therefore, valid, necessary bytes are being removed from the image s binary data.

이제 Categories 테이블에 OLE 헤더와 JPGs의 비트맵이 모두 있으므로 원본 8 개 범주에 대 한 OLE 헤더 제거를 수행 하 고 최신 범주 레코드에 대해이 제거를 무시 하도록 DisplayCategoryPicture.aspx를 업데이트 해야 합니다.Since there are now both bitmaps with OLE headers and JPGs in the Categories table, we need to update DisplayCategoryPicture.aspx so that it does the OLE header stripping for the original eight categories and bypasses this stripping for the newer category records. 다음 자습서에서는 기존 레코드의 이미지를 업데이트 하는 방법을 살펴보겠습니다. 모든 이전 범주 사진은 JPGs 되도록 업데이트 합니다.In our next tutorial we'll examine how to update an existing record s image, and we'll update all of the old category pictures so that they are JPGs. 그러나 지금은 DisplayCategoryPicture.aspx에서 다음 코드를 사용 하 여 원래 8 개 범주에 대해서만 OLE 헤더를 제거 합니다.For now, though, use the following code in DisplayCategoryPicture.aspx to strip the OLE headers only for those original eight categories:

protected void Page_Load(object sender, EventArgs e)
{
    int categoryID = Convert.ToInt32(Request.QueryString["CategoryID"]);
    // Get information about the specified category
    CategoriesBLL categoryAPI = new CategoriesBLL();
    Northwind.CategoriesDataTable categories = 
        categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID);
    Northwind.CategoriesRow category = categories[0];
    if (categoryID <= 8)
    {
        // For older categories, we must strip the OLE header... images are bitmaps
        // Output HTTP headers providing information about the binary data
        Response.ContentType = "image/bmp";
        // Output the binary data
        // But first we need to strip out the OLE header
        const int OleHeaderLength = 78;
        int strippedImageLength = category.Picture.Length - OleHeaderLength;
        byte[] strippedImageData = new byte[strippedImageLength];
        Array.Copy(category.Picture, OleHeaderLength, strippedImageData, 
            0, strippedImageLength);
        Response.BinaryWrite(strippedImageData);
    }
    else
    {
        // 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);
    }
}

이와 같이 변경 하면 JPG 이미지가 이제 GridView에서 올바르게 렌더링 됩니다.With this change, the JPG image is now rendered correctly in the GridView.

새 범주에 대 한 JPG 이미지가 올바르게 렌더링 The JPG Images for New Categories are Correctly Rendered

그림 11: 새 범주의 JPG 이미지가 올바르게 렌더링 됨 (전체 크기 이미지를 보려면 클릭)Figure 11: The JPG Images for New Categories are Correctly Rendered (Click to view full-size image)

9 단계: 예외의 면에서 브로슈어 삭제Step 9: Deleting the Brochure in the Face of an Exception

이진 데이터를 웹 서버의 파일 시스템에 저장 하는 문제 중 하나는 데이터 모델과 해당 이진 데이터 간의 연결 해제를 도입 하는 것입니다.One of the challenges of storing binary data on the web server s file system is that it introduces a disconnect between the data model and its binary data. 따라서 레코드를 삭제할 때마다 파일 시스템의 해당 이진 데이터도 제거 해야 합니다.Therefore, whenever a record is deleted, the corresponding binary data on the file system must also be removed. 삽입 하는 경우에도이를 재생할 수 있습니다.This can come into play when inserting, as well. 사용자가 유효한 그림과 브로슈어를 지정 하 여 새 범주를 추가 하는 시나리오를 고려해 보십시오.Consider the following scenario: a user adds a new category, specifying a valid picture and brochure. 삽입 단추를 클릭 하면 포스트백이 발생 하 고 DetailsView s ItemInserting 이벤트가 발생 하 여 브로슈어에 웹 서버 파일 시스템에 저장 됩니다.Upon clicking the Insert button, a postback occurs and the DetailsView s ItemInserting event fires, saving the brochure to the web server s file system. 그런 다음 CategoriesBLL 클래스 s InsertWithPicture 메서드를 호출 하는 ObjectDataSource s Insert() 메서드를 호출 합니다 .이 메서드는 CategoriesTableAdapter s InsertWithPicture 메서드를 호출 합니다.Next, the ObjectDataSource s Insert() method is invoked, which calls the CategoriesBLL class s InsertWithPicture method, which calls the CategoriesTableAdapter s InsertWithPicture method.

이제 데이터베이스가 오프 라인 상태 이거나 INSERT SQL 문에 오류가 있는 경우 어떻게 되나요?Now, what happens if the database is offline, or if there is an error in the INSERT SQL statement? 분명히 삽입이 실패 하므로 새 범주 행이 데이터베이스에 추가 되지 않습니다.Clearly the INSERT will fail, so no new category row will be added to the database. 그러나 업로드 된 브로슈어 파일은 웹 서버의 파일 시스템에 그대로 남아 있습니다.But we still have the uploaded brochure file sitting on the web server s file system! 삽입 하는 동안 예외가 발생 한 경우이 파일을 삭제 해야 합니다.This file needs to be deleted in the face of an exception during the inserting workflow.

ASP.NET 페이지 자습서의 BLL 및 DAL 수준 예외 처리 에서 앞서 설명한 것 처럼, 아키텍처의 깊이 내에서 예외가 throw 되 면 다양 한 계층을 통해 버블링 됩니다.As discussed previously in the Handling BLL- and DAL-Level Exceptions in an ASP.NET Page tutorial, when an exception is thrown from within the depths of the architecture it is bubbled up through the various layers. 프레젠테이션 계층에서 DetailsView s ItemInserted 이벤트에서 예외가 발생 했는지 여부를 확인할 수 있습니다.At the Presentation Layer, we can determine if an exception has occurred from the DetailsView s ItemInserted event. 이 이벤트 처리기는 또한 ObjectDataSource s InsertParameters의 값을 제공 합니다.This event handler also provides the values of the ObjectDataSource s InsertParameters. 따라서 예외가 있는지 확인 하 고, 필요한 경우 ObjectDataSource s brochurePath 매개 변수로 지정 된 파일을 삭제 하는 ItemInserted 이벤트에 대 한 이벤트 처리기를 만들 수 있습니다.Therefore, we can create an event handler for the ItemInserted event that checks if there was an exception and, if so, deletes the file specified by the ObjectDataSource s brochurePath parameter:

protected void NewCategory_ItemInserted
    (object sender, DetailsViewInsertedEventArgs e)
{
    if (e.Exception != null)
    {
        // Need to delete brochure file, if it exists
        if (e.Values["brochurePath"] != null)
            System.IO.File.Delete(Server.MapPath(
                e.Values["brochurePath"].ToString()));
    }
}

요약Summary

이진 데이터를 포함 하는 레코드를 추가 하기 위해 웹 기반 인터페이스를 제공 하기 위해 수행 해야 하는 여러 단계가 있습니다.There are a number of steps that must be performed in order to provide a web-based interface for adding records that include binary data. 이진 데이터를 데이터베이스에 직접 저장 하는 경우에는 이진 데이터가 삽입 되는 경우를 처리 하는 특정 메서드를 추가 하 여 아키텍처를 업데이트 해야 할 가능성이 있습니다.If the binary data is being stored directly into the database, chances are you'll need to update the architecture, adding specific methods to handle the case where binary data is being inserted. 아키텍처가 업데이트 된 후 다음 단계는 삽입 인터페이스를 만드는 것입니다 .이 인터페이스는 각 이진 데이터 필드에 대 한 FileUpload 컨트롤을 포함 하도록 사용자 지정 된 DetailsView을 사용 하 여 수행할 수 있습니다.Once the architecture has been updated, the next step is creating the inserting interface, which can be accomplished using a DetailsView that has been customized to include a FileUpload control for each binary data field. 업로드 된 데이터를 웹 서버의 파일 시스템에 저장 하거나 DetailsView s ItemInserting 이벤트 처리기의 데이터 원본 매개 변수에 할당할 수 있습니다.The uploaded data can then be saved to the web server s file system or assigned to a data source parameter in the DetailsView s ItemInserting event handler.

이진 데이터를 파일 시스템에 저장 하려면 데이터를 데이터베이스에 직접 저장 하는 것 보다 더 많은 계획이 필요 합니다.Saving binary data to the file system requires more planning than saving data directly into the database. 한 사용자의 업로드에서 다른 사용자를 덮어쓰는 것을 방지 하려면 이름 지정 체계를 선택 해야 합니다.A naming scheme must be chosen in order to avoid one user s upload overwriting another s. 또한 데이터베이스 삽입에 실패 하는 경우 업로드 된 파일을 삭제 하려면 추가 단계를 수행 해야 합니다.Also, extra steps must be taken to delete the uploaded file if the database insert fails.

이제 브로슈어 및 그림을 사용 하 여 시스템에 새 범주를 추가할 수 있지만, 기존 범주 이진 데이터를 업데이트 하는 방법 또는 삭제 된 범주에 대 한 이진 데이터를 올바르게 제거 하는 방법을 확인 합니다.We now have the ability to add new categories to the system with a brochure and picture, but we ve yet to look at how to update an existing category s binary data or how to correctly remove the binary data for a deleted category. 다음 자습서에서는 이러한 두 가지 항목을 살펴보겠습니다.We'll explore these two topics in the next tutorial.

행복 한 프로그래밍Happy Programming!

저자 정보About the Author

Scott Mitchell(7 개의 ASP/ASP. NET books 및 4GuysFromRolla.com창립자)은 1998부터 Microsoft 웹 기술을 사용 하 여 작업 했습니다.Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott은 독립 컨설턴트, 강사 및 기록기로 작동 합니다.Scott works as an independent consultant, trainer, and writer. 최신 책은 24 시간 이내에 ASP.NET 2.0을 sams teach yourself것입니다.His latest book is Sams Teach Yourself ASP.NET 2.0 in 24 Hours. mitchell@4GuysFromRolla.com에 도달할 수 있습니다 .He can be reached at mitchell@4GuysFromRolla.com. 또는 블로그를 통해 http://ScottOnWriting.NET에서 찾을 수 있습니다.or via his blog, which can be found at http://ScottOnWriting.NET.

특별히 감사 합니다.Special Thanks To

이 자습서 시리즈는 많은 유용한 검토자가 검토 했습니다.This tutorial series was reviewed by many helpful reviewers. 이 자습서에 대 한 리드 검토자는 Dave Gardner, Teresa Murphy 및 Bernadette Leigh 였습니다.Lead reviewers for this tutorial were Dave Gardner, Teresa Murphy, and Bernadette Leigh. 예정 된 MSDN 문서를 검토 하는 데 관심이 있나요?Interested in reviewing my upcoming MSDN articles? 그렇다면mitchell@4GuysFromRolla.com에서 줄을 삭제 합니다.If so, drop me a line at mitchell@4GuysFromRolla.com.