멤버 자격 및 관리

작성자 : Erik Reitan

이 자습서 시리즈에서는 웹용 ASP.NET 4.5 및 Microsoft Visual Studio Express 2013을 사용하여 ASP.NET Web Forms 애플리케이션을 빌드하는 기본 사항을 설명합니다. C# 소스 코드가 포함된 Visual Studio 2013 프로젝트는 이 자습서 시리즈와 함께 사용할 수 있습니다.

이 자습서에서는 Wingtip Toys 샘플 애플리케이션을 업데이트하여 사용자 지정 역할을 추가하고 ASP.NET ID를 사용하는 방법을 보여줍니다. 또한 사용자 지정 역할이 있는 사용자가 웹 사이트에서 제품을 추가하고 제거할 수 있는 관리 페이지를 구현하는 방법을 보여 줍니다.

ASP.NET ID 는 ASP.NET 웹 애플리케이션을 빌드하는 데 사용되는 멤버 자격 시스템이며 ASP.NET 4.5에서 사용할 수 있습니다. ASP.NET ID는 Visual Studio 2013 Web Forms 프로젝트 템플릿뿐만 아니라 ASP.NET MVC, ASP.NET Web APIASP.NET 단일 페이지 애플리케이션용 템플릿에도 사용됩니다. 빈 웹 애플리케이션으로 시작할 때 NuGet을 사용하여 ASP.NET ID 시스템을 구체적으로 설치할 수도 있습니다. 그러나 이 자습서 시리즈에서는 ASP.NET ID 시스템을 포함하는 Web Forms projecttemplate을 사용합니다. ASP.NET ID를 사용하면 사용자별 프로필 데이터를 애플리케이션 데이터와 쉽게 통합할 수 있습니다. 또한 ASP.NET ID를 통해 애플리케이션의 사용자 프로필에 대한 지속성 모델을 선택할 수 있습니다. Windows Azure Storage 테이블과 같은 NoSQL 데이터 저장소를 포함하여 SQL Server 데이터베이스 또는 다른 데이터 저장소에 데이터를 저장할 수 있습니다.

이 자습서는 Wingtip Toys 자습서 시리즈의 "PayPal을 사용하여 체크 아웃 및 결제"라는 이전 자습서를 기반으로 합니다.

학습할 내용:

  • 코드를 사용하여 애플리케이션에 사용자 지정 역할 및 사용자를 추가하는 방법입니다.
  • 관리 폴더 및 페이지에 대한 액세스를 제한하는 방법입니다.
  • 사용자 지정 역할에 속한 사용자에 대한 탐색을 제공하는 방법입니다.
  • 모델 바인딩을 사용하여 DropDownList 컨트롤을 제품 범주로 채우는 방법입니다.
  • FileUpload 컨트롤을 사용하여 웹 애플리케이션에 파일을 업로드하는 방법입니다.
  • 유효성 검사 컨트롤을 사용하여 입력 유효성 검사를 구현하는 방법입니다.
  • 애플리케이션에서 제품을 추가하고 제거하는 방법입니다.

이러한 기능은 자습서에 포함되어 있습니다.

  • ASP.NET ID
  • 구성 및 권한 부여
  • 모델 바인딩
  • 눈에 거슬리지 않는 유효성 검사

ASP.NET Web Forms 멤버 자격 기능을 제공합니다. 기본 템플릿을 사용하면 애플리케이션이 실행되면 즉시 사용할 수 있는 기본 제공 멤버 자격 기능이 있습니다. 이 자습서에서는 ASP.NET ID를 사용하여 사용자 지정 역할을 추가하고 해당 역할에 사용자를 할당하는 방법을 보여줍니다. 관리 폴더에 대한 액세스를 제한하는 방법을 알아봅니다. 사용자 지정 역할이 있는 사용자가 제품을 추가 및 제거하고 제품을 추가한 후 미리 볼 수 있는 페이지를 관리 폴더에 추가합니다.

사용자 지정 역할 추가

ASP.NET ID를 사용하여 사용자 지정 역할을 추가하고 코드를 사용하여 해당 역할에 사용자를 할당할 수 있습니다.

  1. 솔루션 탐색기Logic 폴더를 마우스 오른쪽 단추로 클릭하고 새 클래스를 만듭니다.

  2. 새 클래스 이름을 RoleActions.cs로 지정합니다.

  3. 다음과 같이 표시되도록 코드를 수정합니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace WingtipToys.Logic
    {
        internal class RoleActions
        {
        }
    }
    
  4. 솔루션 탐색기Global.asax.cs 파일을 엽니다.

  5. 다음과 같이 표시되도록 노란색으로 강조 표시된 코드를 추가하여 Global.asax.cs 파일을 수정합니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Optimization;
    using System.Web.Routing;
    using System.Web.Security;
    using System.Web.SessionState;
    using System.Data.Entity;
    using WingtipToys.Models;
    using WingtipToys.Logic;
    
    namespace WingtipToys
    {
        public class Global : HttpApplication
        {
            void Application_Start(object sender, EventArgs e)
            {
              // Code that runs on application startup
              RouteConfig.RegisterRoutes(RouteTable.Routes);
              BundleConfig.RegisterBundles(BundleTable.Bundles);
    
              // Initialize the product database.
              Database.SetInitializer(new ProductDatabaseInitializer());
    
              // Create the custom role and user.
              RoleActions roleActions = new RoleActions();
              roleActions.AddUserAndRole();
            }
        }
    }
    
  6. AddUserAndRole는 빨간색으로 밑줄이 그어져 있습니다. AddUserAndRole 코드를 두 번 클릭합니다.
    강조 표시된 메서드의 시작 부분에 있는 문자 "A"에 밑줄이 표시됩니다.

  7. 문자 "A"를 마우스로 가리키고 메서드에 대한 메서드 스텁을 생성할 수 있는 UI를 AddUserAndRole 클릭합니다.

    멤버 자격 및 관리 - 메서드 스텁 생성

  8. 다음과 같은 옵션을 클릭합니다.
    Generate method stub for "AddUserAndRole" in "WingtipToys.Logic.RoleActions"

  9. Logic 폴더에서 RoleActions.cs 파일을 엽니다.
    AddUserAndRole 메서드가 클래스 파일에 추가되었습니다.

  10. 을 제거하고 NotImplementedException 노란색으로 강조 표시된 코드를 추가하여 다음과 같이 표시되도록 RoleActions.cs 파일을 수정합니다.

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Web;
    using WingtipToys.Models;
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.EntityFramework;
    
    namespace WingtipToys.Logic
    {
      internal class RoleActions
      {
        internal void AddUserAndRole()
        {
          // Access the application context and create result variables.
          Models.ApplicationDbContext context = new ApplicationDbContext();
          IdentityResult IdRoleResult;
          IdentityResult IdUserResult;
    
          // Create a RoleStore object by using the ApplicationDbContext object. 
          // The RoleStore is only allowed to contain IdentityRole objects.
          var roleStore = new RoleStore<IdentityRole>(context);
    
          // Create a RoleManager object that is only allowed to contain IdentityRole objects.
          // When creating the RoleManager object, you pass in (as a parameter) a new RoleStore object. 
          var roleMgr = new RoleManager<IdentityRole>(roleStore);
    
          // Then, you create the "canEdit" role if it doesn't already exist.
          if (!roleMgr.RoleExists("canEdit"))
          {
            IdRoleResult = roleMgr.Create(new IdentityRole { Name = "canEdit" });
          }
    
          // Create a UserManager object based on the UserStore object and the ApplicationDbContext  
          // object. Note that you can create new objects and use them as parameters in
          // a single line of code, rather than using multiple lines of code, as you did
          // for the RoleManager object.
          var userMgr = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
          var appUser = new ApplicationUser
          {
            UserName = "canEditUser@wingtiptoys.com",
            Email = "canEditUser@wingtiptoys.com"
          };
          IdUserResult = userMgr.Create(appUser, ConfigurationManager.AppSettings["AppUserPasswordKey"]);
    
          // If the new "canEdit" user was successfully created, 
          // add the "canEdit" user to the "canEdit" role. 
          if (!userMgr.IsInRole(userMgr.FindByEmail("canEditUser@wingtiptoys.com").Id, "canEdit"))
          {
            IdUserResult = userMgr.AddToRole(userMgr.FindByEmail("canEditUser@wingtiptoys.com").Id, "canEdit");
          }
        }
      }
    }
    

위의 코드는 먼저 멤버 자격 데이터베이스에 대한 데이터베이스 컨텍스트를 설정합니다. 멤버 자격 데이터베이스도 App_Data 폴더에 .mdf 파일로 저장됩니다. 첫 번째 사용자가 이 웹 애플리케이션에 로그인하면 이 데이터베이스를 볼 수 있습니다.

참고

제품 데이터와 함께 멤버 자격 데이터를 저장하려는 경우 위의 코드에 제품 데이터를 저장하는 데 사용한 것과 동일한 DbContext 를 사용하는 것이 좋습니다.

내부 키워드(keyword) 형식(예: 클래스) 및 형식 멤버(예: 메서드 또는 속성)에 대한 액세스 한정자입니다. 내부 형식 또는 멤버는 동일한 어셈블리 (.dll 파일)에 포함된 파일 내에서만 액세스할 수 있습니다. 애플리케이션을 빌드할 때 애플리케이션을 실행할 때 실행되는 코드가 포함된 어셈블리 파일 (.dll)이 만들어집니다.

RoleStore 역할 관리를 제공하는 개체는 데이터베이스 컨텍스트에 따라 만들어집니다.

참고

개체를 RoleStore 만들 때 제네릭 IdentityRole 형식을 사용합니다. 즉, 는 RoleStore 개체만 포함 IdentityRole 할 수 있습니다. 또한 제네릭을 사용하면 메모리의 리소스가 더 잘 처리됩니다.

다음으로, RoleManager 방금 만든 개체를 RoleStore 기반으로 개체가 만들어집니다. 개체는 RoleManager 에 대한 변경 내용을 자동으로 저장하는 데 사용할 수 있는 역할 관련 API를 노출합니다 RoleStore. RoleManager 코드에서 제네릭 형식을 사용하기 때문에 는 개체만 포함 IdentityRole<IdentityRole> 수 있습니다.

메서드를 RoleExists 호출하여 멤버 자격 데이터베이스에 "canEdit" 역할이 있는지 확인합니다. 그렇지 않은 경우 역할을 만듭니다.

개체를 UserManager 만드는 것은 컨트롤보다 RoleManager 더 복잡한 것처럼 보이지만 거의 동일합니다. 여러 줄이 아닌 한 줄로 코딩됩니다. 여기서 전달하는 매개 변수는 괄호에 포함된 새 개체로 인스턴스화됩니다.

다음으로 새 ApplicationUser 개체를 만들어 "canEditUser" 사용자를 만듭니다. 그런 다음 사용자를 성공적으로 만들면 사용자를 새 역할에 추가합니다.

참고

오류 처리는 이 자습서 시리즈의 뒷부분에 있는 "ASP.NET 오류 처리" 자습서 중에 업데이트됩니다.

다음에 애플리케이션이 시작될 때 "canEditUser"라는 사용자가 애플리케이션의 "canEdit"라는 역할로 추가됩니다. 이 자습서의 뒷부분에서는 "canEditUser" 사용자로 로그인하여 이 자습서에서 추가할 추가 기능을 표시합니다. ASP.NET ID에 대한 API 세부 정보는 Microsoft.AspNet.Identity 네임스페이스를 참조하세요. ASP.NET ID 시스템을 초기화하는 방법에 대한 자세한 내용은 AspnetIdentitySample을 참조하세요.

관리 페이지에 대한 액세스 제한

Wingtip Toys 샘플 애플리케이션을 사용하면 익명 사용자와 로그인한 사용자가 제품을 보고 구매할 수 있습니다. 그러나 사용자 지정 "canEdit" 역할이 있는 로그인한 사용자는 제품을 추가하고 제거하기 위해 제한된 페이지에 액세스할 수 있습니다.

관리 폴더 및 페이지 추가

다음으로 Wingtip Toys 샘플 애플리케이션의 사용자 지정 역할에 속하는 "canEditUser" 사용자에 대한 관리 폴더를 만듭니다.

  1. 솔루션 탐색기 프로젝트 이름(Wingtip Toys)을 마우스 오른쪽 단추로 클릭하고 추가 ->새 폴더를 선택합니다.
  2. 새 폴더 이름을 관리.
  3. 관리 폴더를 마우스 오른쪽 단추로 클릭한 다음 추가 ->새 항목을 선택합니다.
    새 항목 추가 대화 상자가 표시됩니다.
  4. 왼쪽에서 Visual C#->Web 템플릿 그룹을 선택합니다. 가운데 목록에서 마스터 페이지가 있는 웹 양식을 선택하고 이름을 AdminPage.aspx로 지정한 다음 추가를 선택합니다.
  5. Site.Master 파일을 master 페이지로 선택한 다음 확인을 선택합니다.

Web.config 파일 추가

관리 폴더에 Web.config 파일을 추가하여 폴더에 포함된 페이지에 대한 액세스를 제한할 수 있습니다.

  1. 관리 폴더를 마우스 오른쪽 단추로 클릭하고 추가 ->새 항목을 선택합니다.
    새 항목 추가 대화 상자가 표시됩니다.

  2. Visual C# 웹 템플릿 목록에서 가운데 목록에서 웹 구성 파일을선택하고 Web.config 기본 이름을 그대로 적용한 다음추가를 선택합니다.

  3. Web.config 파일의 기존 XML 콘텐츠를 다음으로 바꿉니다.

    <?xml version="1.0"?>
    <configuration>
      <system.web>
        <authorization>
          <allow roles="canEdit"/>
          <deny users="*"/>
        </authorization>
      </system.web>
    </configuration>
    

Web.config 파일을 저장합니다. Web.config 파일은 애플리케이션의 "canEdit" 역할에 속한 사용자만 관리 폴더에 포함된 페이지에 액세스할 수 있도록 지정합니다.

사용자 지정 역할 탐색 포함

사용자 지정 "canEdit" 역할의 사용자가 애플리케이션의 관리 섹션으로 이동할 수 있도록 하려면 Site.Master 페이지에 대한 링크를 추가해야 합니다. "canEdit" 역할에 속한 사용자만 관리 링크를 보고 관리 섹션에 액세스할 수 있습니다.

  1. 솔루션 탐색기 Site.Master 페이지를 찾아 엽니다.

  2. "canEdit" 역할의 사용자에 대한 링크를 만들려면 목록이 다음과 같이 표시되도록 순서가 지정되지 않은 다음 목록 <ul> 요소에 노란색으로 강조 표시된 태그를 추가합니다.

    <ul class="nav navbar-nav">
        <li><a runat="server" id="adminLink" visible="false" 
          href="~/Admin/AdminPage">Admin</a></li>
        <li><a runat="server" href="~/">Home</a></li>
        <li><a runat="server" href="~/About">About</a></li>
        <li><a runat="server" href="~/Contact">Contact</a></li>
        <li><a runat="server" href="~/ProductList">Products</a></li>
        <li><a runat="server" href="~/ShoppingCart" 
          ID="cartCount">&nbsp;</a></li>
    </ul>
    
  3. Site.Master.cs 파일을 엽니다. 처리기에 노란색으로 강조 표시된 코드를 추가하여 "canEditUser" 사용자에게만 관리 링크를 표시합니다Page_Load. 처리기는 Page_Load 다음과 같이 표시됩니다.

    protected void Page_Load(object sender, EventArgs e)
    {
        if (HttpContext.Current.User.IsInRole("canEdit"))
        {
            adminLink.Visible = true;
        }
    }
    

페이지가 로드되면 코드는 로그인한 사용자에게 "canEdit" 역할이 있는지 확인합니다. 사용자가 "canEdit" 역할에 속하는 경우 AdminPage.aspx 페이지(결과적으로 범위 내의 링크)에 대한 링크가 포함된 span 요소가 표시됩니다.

제품 관리 사용

지금까지 "canEdit" 역할을 만들고 "canEditUser" 사용자, 관리 폴더 및 관리 페이지를 추가했습니다. 관리 폴더 및 페이지에 대한 액세스 권한을 설정했으며 애플리케이션에 "canEdit" 역할의 사용자에 대한 탐색 링크를 추가했습니다. 다음으로 AdminPage.aspx 페이지에 태그를 추가하고 AdminPage.aspx.cs 코드 숨김 파일에 추가합니다. 그러면 "canEdit" 역할을 가진 사용자가 제품을 추가하고 제거할 수 있습니다.

  1. 솔루션 탐색기 관리 폴더에서 AdminPage.aspx 파일을 엽니다.

  2. 기존 태그를 다음으로 바꿉다.

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="AdminPage.aspx.cs" Inherits="WingtipToys.Admin.AdminPage" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <h1>Administration</h1>
        <hr />
        <h3>Add Product:</h3>
        <table>
            <tr>
                <td><asp:Label ID="LabelAddCategory" runat="server">Category:</asp:Label></td>
                <td>
                    <asp:DropDownList ID="DropDownAddCategory" runat="server" 
                        ItemType="WingtipToys.Models.Category" 
                        SelectMethod="GetCategories" DataTextField="CategoryName" 
                        DataValueField="CategoryID" >
                    </asp:DropDownList>
                </td>
            </tr>
            <tr>
                <td><asp:Label ID="LabelAddName" runat="server">Name:</asp:Label></td>
                <td>
                    <asp:TextBox ID="AddProductName" runat="server"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" Text="* Product name required." ControlToValidate="AddProductName" SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
                </td>
            </tr>
            <tr>
                <td><asp:Label ID="LabelAddDescription" runat="server">Description:</asp:Label></td>
                <td>
                    <asp:TextBox ID="AddProductDescription" runat="server"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" Text="* Description required." ControlToValidate="AddProductDescription" SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
                </td>
            </tr>
            <tr>
                <td><asp:Label ID="LabelAddPrice" runat="server">Price:</asp:Label></td>
                <td>
                    <asp:TextBox ID="AddProductPrice" runat="server"></asp:TextBox>
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" Text="* Price required." ControlToValidate="AddProductPrice" SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
                    <asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" Text="* Must be a valid price without $." ControlToValidate="AddProductPrice" SetFocusOnError="True" Display="Dynamic" ValidationExpression="^[0-9]*(\.)?[0-9]?[0-9]?$"></asp:RegularExpressionValidator>
                </td>
            </tr>
            <tr>
                <td><asp:Label ID="LabelAddImageFile" runat="server">Image File:</asp:Label></td>
                <td>
                    <asp:FileUpload ID="ProductImage" runat="server" />
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server" Text="* Image path required." ControlToValidate="ProductImage" SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
                </td>
            </tr>
        </table>
        <p></p>
        <p></p>
        <asp:Button ID="AddProductButton" runat="server" Text="Add Product" OnClick="AddProductButton_Click"  CausesValidation="true"/>
        <asp:Label ID="LabelAddStatus" runat="server" Text=""></asp:Label>
        <p></p>
        <h3>Remove Product:</h3>
        <table>
            <tr>
                <td><asp:Label ID="LabelRemoveProduct" runat="server">Product:</asp:Label></td>
                <td><asp:DropDownList ID="DropDownRemoveProduct" runat="server" ItemType="WingtipToys.Models.Product" 
                        SelectMethod="GetProducts" AppendDataBoundItems="true" 
                        DataTextField="ProductName" DataValueField="ProductID" >
                    </asp:DropDownList>
                </td>
            </tr>
        </table>
        <p></p>
        <asp:Button ID="RemoveProductButton" runat="server" Text="Remove Product" OnClick="RemoveProductButton_Click" CausesValidation="false"/>
        <asp:Label ID="LabelRemoveStatus" runat="server" Text=""></asp:Label>
    </asp:Content>
    
  3. 그런 다음 AdminPage.aspx를 마우스 오른쪽 단추로 클릭하고 코드 보기를 클릭하여 AdminPage.aspx.cs코드 숨김 파일을 엽니다.

  4. AdminPage.aspx.cs 코드 숨김 파일의 기존 코드를 다음 코드로 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using WingtipToys.Models;
    using WingtipToys.Logic;
    
    namespace WingtipToys.Admin
    {
      public partial class AdminPage : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
          string productAction = Request.QueryString["ProductAction"];
          if (productAction == "add")
          {
            LabelAddStatus.Text = "Product added!";
          }
    
          if (productAction == "remove")
          {
            LabelRemoveStatus.Text = "Product removed!";
          }
        }
    
        protected void AddProductButton_Click(object sender, EventArgs e)
        {
          Boolean fileOK = false;
          String path = Server.MapPath("~/Catalog/Images/");
          if (ProductImage.HasFile)
          {
            String fileExtension = System.IO.Path.GetExtension(ProductImage.FileName).ToLower();
            String[] allowedExtensions = { ".gif", ".png", ".jpeg", ".jpg" };
            for (int i = 0; i < allowedExtensions.Length; i++)
            {
              if (fileExtension == allowedExtensions[i])
              {
                fileOK = true;
              }
            }
          }
    
          if (fileOK)
          {
            try
            {
              // Save to Images folder.
              ProductImage.PostedFile.SaveAs(path + ProductImage.FileName);
              // Save to Images/Thumbs folder.
              ProductImage.PostedFile.SaveAs(path + "Thumbs/" + ProductImage.FileName);
            }
            catch (Exception ex)
            {
              LabelAddStatus.Text = ex.Message;
            }
    
            // Add product data to DB.
            AddProducts products = new AddProducts();
            bool addSuccess = products.AddProduct(AddProductName.Text, AddProductDescription.Text,
                AddProductPrice.Text, DropDownAddCategory.SelectedValue, ProductImage.FileName);
            if (addSuccess)
            {
              // Reload the page.
              string pageUrl = Request.Url.AbsoluteUri.Substring(0, Request.Url.AbsoluteUri.Count() - Request.Url.Query.Count());
              Response.Redirect(pageUrl + "?ProductAction=add");
            }
            else
            {
              LabelAddStatus.Text = "Unable to add new product to database.";
            }
          }
          else
          {
            LabelAddStatus.Text = "Unable to accept file type.";
          }
        }
    
        public IQueryable GetCategories()
        {
          var _db = new WingtipToys.Models.ProductContext();
          IQueryable query = _db.Categories;
          return query;
        }
    
        public IQueryable GetProducts()
        {
          var _db = new WingtipToys.Models.ProductContext();
          IQueryable query = _db.Products;
          return query;
        }
    
        protected void RemoveProductButton_Click(object sender, EventArgs e)
        {
          using (var _db = new WingtipToys.Models.ProductContext())
          {
            int productId = Convert.ToInt16(DropDownRemoveProduct.SelectedValue);
            var myItem = (from c in _db.Products where c.ProductID == productId select c).FirstOrDefault();
            if (myItem != null)
            {
              _db.Products.Remove(myItem);
              _db.SaveChanges();
    
              // Reload the page.
              string pageUrl = Request.Url.AbsoluteUri.Substring(0, Request.Url.AbsoluteUri.Count() - Request.Url.Query.Count());
              Response.Redirect(pageUrl + "?ProductAction=remove");
            }
            else
            {
              LabelRemoveStatus.Text = "Unable to locate product.";
            }
          }
        }
      }
    }
    

AdminPage.aspx.cs 코드 숨김 파일에 대해 입력한 코드에서 라는 AddProducts 클래스는 데이터베이스에 제품을 추가하는 실제 작업을 수행합니다. 이 클래스는 아직 존재하지 않으므로 지금 만듭니다.

  1. 솔루션 탐색기Logic 폴더를 마우스 오른쪽 단추로 클릭한 다음 추가 ->새 항목을 선택합니다.
    새 항목 추가 대화 상자가 표시됩니다.

  2. 왼쪽에서 Visual C# ->Code 템플릿 그룹을 선택합니다. 그런 다음 중간 목록에서 클래스를 선택하고 이름을 AddProducts.cs로 지정합니다.
    새 클래스 파일이 표시됩니다.

  3. 기존 코드를 다음으로 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using WingtipToys.Models;
    
    namespace WingtipToys.Logic
    {
        public class AddProducts
        {
            public bool AddProduct(string ProductName, string ProductDesc, string ProductPrice, string ProductCategory, string ProductImagePath)
            {
                var myProduct = new Product();
                myProduct.ProductName = ProductName;
                myProduct.Description = ProductDesc;
                myProduct.UnitPrice = Convert.ToDouble(ProductPrice);
                myProduct.ImagePath = ProductImagePath;
                myProduct.CategoryID = Convert.ToInt32(ProductCategory);
    
                using (ProductContext _db = new ProductContext())
                {
                    // Add product to DB.
                    _db.Products.Add(myProduct);
                    _db.SaveChanges();
                }
                // Success.
                return true;
            }
        }
    }
    

AdminPage.aspx 페이지에서는 "canEdit" 역할에 속한 사용자가 제품을 추가하고 제거할 수 있습니다. 새 제품이 추가되면 제품에 대한 세부 정보가 유효성을 검사한 다음 데이터베이스에 입력됩니다. 새 제품은 웹 애플리케이션의 모든 사용자가 즉시 사용할 수 있습니다.

눈에 거슬리지 않는 유효성 검사

사용자가 AdminPage.aspx 페이지에서 제공하는 제품 세부 정보는 유효성 검사 컨트롤(RequiredFieldValidatorRegularExpressionValidator)을 사용하여 유효성을 검사합니다. 이러한 컨트롤은 눈에 거슬리지 않는 유효성 검사를 자동으로 사용합니다. 눈에 거슬리지 않는 유효성 검사를 사용하면 유효성 검사 컨트롤이 클라이언트 쪽 유효성 검사 논리에 JavaScript를 사용할 수 있습니다. 즉, 페이지의 유효성을 검사하기 위해 서버로의 이동이 필요하지 않습니다. 기본적으로 눈에 거슬리지 않는 유효성 검사는 다음 구성 설정에 따라 Web.config 파일에 포함됩니다.

<add key="ValidationSettings:UnobtrusiveValidationMode" value="WebForms" />

정규식

AdminPage.aspx 페이지의 제품 가격은 RegularExpressionValidator 컨트롤을 사용하여 유효성을 검사합니다. 이 컨트롤은 연결된 입력 컨트롤의 값("AddProductPrice" TextBox)이 정규식에 지정된 패턴과 일치하는지 여부를 확인합니다. 정규식은 특정 문자 패턴을 빠르게 찾고 일치시킬 수 있는 패턴 일치 표기법입니다. RegularExpressionValidator 컨트롤에는 아래와 같이 가격 입력의 유효성을 검사하는 데 사용되는 정규식을 포함하는 라는 ValidationExpression 속성이 포함되어 있습니다.

<asp:RegularExpressionValidator 
    ID="RegularExpressionValidator1" runat="server"
    Text="* Must be a valid price without $." ControlToValidate="AddProductPrice" 
    SetFocusOnError="True" Display="Dynamic" 
    ValidationExpression="^[0-9]*(\.)?[0-9]?[0-9]?$">
</asp:RegularExpressionValidator>

FileUpload 컨트롤

입력 및 유효성 검사 컨트롤 외에도 AdminPage.aspx 페이지에 FileUpload 컨트롤을 추가했습니다. 이 컨트롤은 파일을 업로드하는 기능을 제공합니다. 이 경우 이미지 파일만 업로드할 수 있습니다. 코드 숨김 파일(AdminPage.aspx.cs)AddProductButton에서 를 클릭하면 코드는 FileUpload 컨트롤의 속성을 확인합니다HasFile. 컨트롤에 파일이 있고 파일 형식(파일 확장명 기준)이 허용되는 경우 이미지는 이미지 폴더와 애플리케이션의 Images/Thumbs 폴더에 저장됩니다.

모델 바인딩

이 자습서 시리즈의 앞부분에서 모델 바인딩을 사용하여 ListView 컨트롤, FormsView 컨트롤, GridView 컨트롤 및 DetailView 컨트롤을 채웠습니다. 이 자습서에서는 모델 바인딩을 사용하여 DropDownList 컨트롤을 제품 범주 목록으로 채웁습니다.

AdminPage.aspx 파일에 추가한 태그에는 라는 DropDownAddCategoryDropDownList 컨트롤이 포함되어 있습니다.

<asp:DropDownList ID="DropDownAddCategory" runat="server" 
        ItemType="WingtipToys.Models.Category" 
        SelectMethod="GetCategories" DataTextField="CategoryName" 
        DataValueField="CategoryID" >
    </asp:DropDownList>

모델 바인딩을 사용하여 특성 및 특성을 설정 ItemType 하여 이 DropDownListSelectMethod 채웁습니다. 특성은 ItemType 컨트롤을 채울 때 형식을 WingtipToys.Models.Category 사용하도록 지정합니다. 아래와 같이 클래스를 만들어 이 자습서 시리즈의 시작 부분에서 이 형식을 Category 정의했습니다. 클래스는 CategoryCategory.cs 파일 내의 Models 폴더에 있습니다.

public class Category
{
    [ScaffoldColumn(false)]
    public int CategoryID { get; set; }

    [Required, StringLength(100), Display(Name = "Name")]
    public string CategoryName { get; set; }

    [Display(Name = "Product Description")]
    public string Description { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

DropDownList 컨트롤의 특성은 SelectMethod 코드 숨김 파일(AdminPage.aspx.cs)에 포함된 메서드(아래 그림 참조)를 사용하도록 GetCategories 지정합니다.

public IQueryable GetCategories()
{
  var _db = new WingtipToys.Models.ProductContext();
  IQueryable query = _db.Categories;
  return query;
}

이 메서드는 인터페이스를 IQueryable 사용하여 형식에 대한 Category 쿼리를 평가하도록 지정합니다. 반환된 값은 페이지 태그(AdminPage.aspx)에서 DropDownList를 채우는 데 사용됩니다.

목록의 각 항목에 대해 표시되는 텍스트는 특성을 설정 DataTextField 하여 지정됩니다. 특성은 DataTextField 위의 클래스의 를 CategoryNameCategory 사용하여 DropDownList 컨트롤의 각 범주를 표시합니다. DropDownList 컨트롤에서 항목을 선택할 때 전달되는 실제 값은 특성을 기반으로 합니다DataValueField. 특성은 DataValueField 클래스에서 Category 정의한 CategoryID 대로 로 설정됩니다(위에 표시됨).

애플리케이션 작동 방식

"canEdit" 역할에 속한 사용자가 처음으로 DropDownAddCategory 페이지로 이동하면 위에서 설명한 대로 DropDownList 컨트롤이 채워집니다. DropDownRemoveProductDropDownList 컨트롤도 동일한 방법을 사용하는 제품으로 채워집니다. "canEdit" 역할에 속한 사용자는 범주 유형을 선택하고 제품 세부 정보(이름, 설명, 가격이미지 파일)를 추가합니다. "canEdit" 역할에 속한 사용자가 제품 추가 단추를 AddProductButton_Click 클릭하면 이벤트 처리기가 트리거됩니다. AddProductButton_Click 코드 숨김 파일(AdminPage.aspx.cs)에 있는 이벤트 처리기는 이미지 파일이 허용된 파일 형식(.gif,.png, .jpeg 또는 .jpg)과 일치하는지 확인 합니다. 그런 다음 이미지 파일이 Wingtip Toys 샘플 애플리케이션의 폴더에 저장됩니다. 다음으로 새 제품이 데이터베이스에 추가됩니다. 새 제품을 추가하기 위해 클래스의 AddProducts 새 instance 만들어지고 제품의 이름을 지정합니다. 클래스에는 AddProducts 라는 AddProduct메서드가 있으며 products 개체는 이 메서드를 호출하여 데이터베이스에 제품을 추가합니다.

// Add product data to DB.
AddProducts products = new AddProducts();
bool addSuccess = products.AddProduct(AddProductName.Text, AddProductDescription.Text,
    AddProductPrice.Text, DropDownAddCategory.SelectedValue, ProductImage.FileName);

코드가 새 제품을 데이터베이스에 성공적으로 추가하면 페이지가 쿼리 문자열 값 ProductAction=add으로 다시 로드됩니다.

Response.Redirect(pageUrl + "?ProductAction=add");

페이지가 다시 로드되면 쿼리 문자열이 URL에 포함됩니다. 페이지를 다시 로드하면 "canEdit" 역할에 속한 사용자는 AdminPage.aspx 페이지의 DropDownList 컨트롤에서 업데이트를 즉시 볼 수 있습니다. 또한 URL에 쿼리 문자열을 포함하면 페이지에 "canEdit" 역할에 속한 사용자에게 성공 메시지가 표시될 수 있습니다.

AdminPage.aspx 페이지가 다시 로드되면 Page_Load 이벤트가 호출됩니다.

protected void Page_Load(object sender, EventArgs e)
{
    string productAction = Request.QueryString["ProductAction"];
    if (productAction == "add")
    {
        LabelAddStatus.Text = "Product added!";
    }

    if (productAction == "remove")
    {
        LabelRemoveStatus.Text = "Product removed!";
    }
}

Page_Load 이벤트 처리기는 쿼리 문자열 값을 확인하고 성공 메시지를 표시할지 여부를 결정합니다.

애플리케이션 실행

이제 애플리케이션을 실행하여 쇼핑 카트에서 항목을 추가, 삭제 및 업데이트하는 방법을 확인할 수 있습니다. 장바구니 합계는 장바구니에 있는 모든 항목의 총 비용을 반영합니다.

  1. 솔루션 탐색기 F5 키를 눌러 Wingtip Toys 샘플 애플리케이션을 실행합니다.
    브라우저가 열리고 Default.aspx 페이지가 표시됩니다.

  2. 페이지 맨 위에 있는 로그인 링크를 클릭합니다.

    멤버 자격 및 관리 - 로그인 링크

    Login.aspx 페이지가 표시됩니다.

  3. 사용자 이름 및 암호를 입력합니다.

    멤버 자격 및 관리 - 로그인 페이지

  4. 페이지 아래쪽에 있는 로그인 단추를 클릭합니다.

  5. 다음 페이지의 맨 위에서 관리 링크를 선택하여 AdminPage.aspx 페이지로 이동합니다.

    멤버 자격 및 관리 - 관리 링크

  6. 입력 유효성 검사를 테스트하려면 제품 세부 정보를 추가하지 않고 제품 추가 단추를 클릭합니다.

    멤버 자격 및 관리 - 관리 페이지

    필수 필드 메시지가 표시됩니다.

  7. 새 제품에 대한 세부 정보를 추가한 다음 제품 추가 단추를 클릭합니다.

    멤버 자격 및 관리 - 제품 추가

  8. 위쪽 탐색 메뉴에서 제품을 선택하여 추가한 새 제품을 봅니다.

    멤버 자격 및 관리 - 새 제품 표시

  9. 관리 링크를 클릭하여 관리 페이지로 돌아갑니다.

  10. 페이지의 제품 제거 섹션에서 DropDownListBox에서 추가한 새 제품을 선택합니다.

  11. 제품 제거 단추를 클릭하여 애플리케이션에서 새 제품을 제거합니다.

    멤버 자격 및 관리 - 제품 제거

  12. 위쪽 탐색 메뉴에서 제품을 선택하여 제품이 제거되었는지 확인합니다.

  13. 기존 관리 모드로 로그오프 를 클릭합니다.
    위쪽 탐색 창에는 더 이상 관리 메뉴 항목이 표시되지 않습니다.

요약

이 자습서에서는 사용자 지정 역할 및 사용자 지정 역할에 속하는 사용자를 추가하고, 관리 폴더 및 페이지에 대한 액세스를 제한하고, 사용자 지정 역할에 속한 사용자에 대한 탐색을 제공했습니다. 모델 바인딩을 사용하여 DropDownList 컨트롤을 데이터로 채웠습니다. FileUpload 컨트롤 및 유효성 검사 컨트롤을 구현했습니다. 또한 데이터베이스에서 제품을 추가하고 제거하는 방법도 알아보았습니다. 다음 자습서에서는 ASP.NET 라우팅을 구현하는 방법을 알아봅니다.

추가 리소스

Web.config - authorization 요소
ASP.NET ID
멤버 자격, OAuth 및 SQL Database 사용하여 보안 ASP.NET Web Forms 앱을 Azure 웹 사이트에 배포
Microsoft Azure - 평가판