Членство и администрирование

Эрик Рейтан

В этой серии учебников вы узнаете, как создавать приложение веб-форм ASP.NET с помощью ASP.NET 4.5 и Microsoft Visual Studio Express 2013 для Интернета. Проект Visual Studio 2013 с исходным кодом C# доступен для сопровождения этой серии учебников.

В этом руководстве показано, как обновить пример приложения Wingtip Toys, чтобы добавить настраиваемую роль и использовать ASP.NET Identity. В нем также показано, как реализовать страницу администрирования, из которой пользователь с пользовательской ролью может добавлять и удалять продукты с веб-сайта.

ASP.NET Identity — это система членства, используемая для создания веб-приложения ASP.NET и доступна в ASP.NET 4.5. ASP.NET Identity используется в шаблоне проекта Веб-форм Visual Studio 2013, а также в шаблонах для ASP.NET MVC, ASP.NET Web API и ASP.NET Single Page Application (SPA). Вы также можете специально установить систему удостоверений ASP.NET с помощью NuGet, начав с пустого веб-приложения. Однако, в этом руководстве вы используете шаблон проекта Web Forms, который включает систему идентификации ASP.NET. ASP.NET Identity упрощает интеграцию данных профиля конкретного пользователя с данными приложения. Кроме того, ASP.NET Identity позволяет выбрать модель сохраняемости для профилей пользователей в приложении. Данные можно хранить в базе данных SQL Server или другом хранилище данных, включая хранилища данных NoSQL , такие как таблицы хранилища Windows Azure.

Это руководство основывается на предыдущем руководстве под названием «Оформление заказа и оплата через PayPal» из цикла руководств Wingtip Toys.

Что вы узнаете:

  • Как использовать код для добавления пользовательской роли и пользователя в приложение.
  • Как ограничить доступ к папке администрирования и странице.
  • Как предоставить навигацию для пользователя, принадлежащего пользовательской роли.
  • Использование привязки модели для заполнения элемента управления DropDownList категориями продуктов.
  • Как отправить файл в веб-приложение с помощью элемента управления FileUpload .
  • Как использовать элементы управления проверки для реализации входной проверки.
  • Добавление и удаление продуктов из приложения.

Эти функции включены в учебник:

  • система идентификации ASP.NET
  • Настройка и авторизация
  • Привязка модели
  • Ненавязчивая проверка

ASP.NET веб-формы предоставляют возможности членства. Используя шаблон по умолчанию, у вас есть встроенные функции членства, которые можно сразу же использовать при запуске приложения. В этом руководстве показано, как использовать удостоверение ASP.NET для добавления настраиваемой роли и назначения пользователю этой роли. Вы узнаете, как ограничить доступ к папке администрирования. Вы добавите страницу в папку администрирования, которая позволяет пользователю с настраиваемой ролью добавлять и удалять продукты, а также просматривать продукт после его добавления.

Добавление настраиваемой роли

С помощью ASP.NET Identity можно добавить пользовательскую роль и назначить пользователю эту роль с помощью кода.

  1. В обозревателе решений щелкните правой кнопкой мыши папку логики и создайте новый класс.

  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" и щелкните элемент пользовательского интерфейса, позволяющий создать заглушку для метода AddUserAndRole.

    Членство и администрирование — создание заглушки метода

  8. Щелкните параметр с заголовком:
    Generate method stub for "AddUserAndRole" in "WingtipToys.Logic.RoleActions"

  9. Откройте файл RoleActions.cs из папки логики .
    Метод AddUserAndRole был добавлен в файл класса.

  10. Измените файл RoleActions.cs , удалив NotImplementedException и добавив код, выделенный желтым цветом, чтобы он отображалась следующим образом:

    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");
          }
        }
      }
    }
    

Приведенный выше код сначала устанавливает контекст базы данных для базы данных членства. База данных членства также хранится в виде файла .mdf в папке App_Data . Вы сможете просмотреть эту базу данных после входа первого пользователя в это веб-приложение.

Замечание

Если вы хотите сохранить данные членства вместе с данными продукта, можно использовать тот же DbContext , который использовался для хранения данных продукта в приведенном выше коде.

Внутреннее ключевое слово — это модификатор доступа для типов (например, классов) и элементов типа (таких как методы или свойства). Внутренние типы или члены доступны только в файлах, содержащихся в той же сборке (.dll файле). При сборке приложения создается файл сборки (.dll), содержащий код, выполняемый при запуске приложения.

Объект RoleStore , предоставляющий управление ролями, создается на основе контекста базы данных.

Замечание

Обратите внимание, что когда создается объект RoleStore, используется универсальный тип IdentityRole. Это означает, что RoleStore разрешено содержать только объекты IdentityRole. Кроме того, с помощью обобщений, ресурсы в памяти обрабатываются лучше.

RoleManager Затем объект создается на основе только что созданного RoleStore объекта. Объект RoleManager предоставляет ролевое API, которое можно использовать для автоматического сохранения изменений в RoleStore. Разрешено RoleManager содержать только объекты IdentityRole, так как код использует универсальный тип <IdentityRole>.

Вы вызываете метод RoleExists, чтобы определить, присутствует ли роль "canEdit" в базе данных членства. Если это не так, создайте эту роль.

UserManager Создание объекта представляется более сложным, чем RoleManager элемент управления, однако он почти тот же. Он просто закодирован на одной строке, а не на нескольких. Здесь параметр, который вы передаете, создается как новый объект, заключенный в скобки.

Затем вы создадите пользователя canEditUser, создав новый ApplicationUser объект. Затем, если пользователь успешно создан, добавьте его в новую роль.

Замечание

Обработка ошибок будет обновлена в ходе руководства по обработке ошибок ASP.NET позже в данной серии руководств.

При следующем запуске приложения пользователь с именем "canEditUser" будет добавлен в роль "canEdit" в этом приложении. Позднее в этом руководстве вы войдете в систему как пользователь "canEditUser", чтобы отобразить дополнительные возможности, которые вы добавите в ходе данного руководства. Дополнительные сведения об api ASP.NET Identity см. в пространстве имен Microsoft.AspNet.Identity. Дополнительные сведения об инициализации системы идентификации ASP.NET см. в aspnetIdentitySample.

Ограничение доступа к странице администрирования

Пример приложения Wingtip Toys позволяет анонимным пользователям и пользователям, вошедшим в систему, просматривать и приобретать продукты. Однако пользователь, вошедший в систему с настраиваемой ролью "canEdit", может получить доступ к ограниченной странице для добавления и удаления продуктов.

Добавление папки администрирования и страницы

Затем вы создадите папку с именем admin для пользователя canEditUser, относящегося к пользовательской роли примера приложения Wingtip Toys.

  1. Щелкните правой кнопкой мыши имя проекта (Wingtip Toys) в обозревателе решений и выберите "Добавить ->Создать папку".
  2. Назовите администратора новой папки.
  3. Щелкните правой кнопкой мыши папку "Администратор" , а затем выберите "Добавить ->Создать элемент".
    Откроется диалоговое окно Добавление нового элемента .
  4. Выберите группу шаблонов Visual C#->Web слева. В среднем списке выберите веб-форму с главной страницей, назовите ее AdminPage.aspx, а затем нажмите кнопку "Добавить".
  5. Выберите файл Site.Master в качестве главной страницы и нажмите кнопку "ОК".

Добавление файла Web.config

Добавив файлWeb.config в папку администрирования , вы можете ограничить доступ к странице, содержащейся в папке.

  1. Щелкните правой кнопкой мыши папку "Администратор" и выберите "Добавить ->Новый элемент".
    Откроется диалоговое окно Добавление нового элемента .

  2. В списке веб-шаблонов Visual C# выберите файл веб-конфигурациииз среднего списка, примите имя Web.config по умолчанию и нажмитекнопку "Добавить".

  3. Замените существующее XML-содержимое в файлеWeb.config следующим образом:

    <?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 (и, следовательно, ссылка внутри элемента ), становится видимым.

Активация управления продуктами

До сих пор вы создали роль "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.cs кодовой части, щелкнув правой кнопкой мыши на AdminPage.aspx и выбрав Просмотреть код.

  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. В обозревателе решений щелкните правой кнопкой мыши папку логики и выберите "Добавить ->Новый элемент".
    Откроется диалоговое окно Добавление нового элемента .

  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 , проверяются с помощью элементов управления проверки (RequiredFieldValidator и RegularExpressionValidator). Эти элементы управления автоматически используют ненавязчивую проверку. Ненавязчивая проверка позволяет элементам управления проверки использовать JavaScript для логики проверки на стороне клиента, что означает, что страница не требует проверки на сервер. По умолчанию ненавязчивая проверка включена в файл Web.config на основе следующего параметра конфигурации:

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

Регулярные выражения

Цена на продукт на странице AdminPage.aspx проверяется с помощью элемента управления RegularExpressionValidator . Этот элемент управления проверяет, соответствует ли значение связанного входного элемента управления (TextBox AddProductPrice) шаблону, указанному регулярным выражением. Регулярное выражение — это нотация сопоставления шаблонов, которая позволяет быстро находить и сопоставлять определенные шаблоны символов. Элемент управления 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

Помимо элементов управления входными и проверками, вы добавили элемент управления FileUpload на страницу AdminPage.aspx . Этот элемент управления предоставляет возможность отправки файлов. В этом случае вы разрешаете отправлять только файлы изображений. В файле программной части (AdminPage.aspx.cs), когда AddProductButton нажат, код проверяет свойство HasFile элемента управления FileUpload. Если элемент управления имеет файл, а тип файла (на основе расширения файла) разрешен, изображение сохраняется в папке "Изображения" и в папке "Изображения/Миниатюры" приложения.

Привязка модели

Ранее в этом руководстве вы использовали привязку модели для заполнения элемента управления ListView , элемента управления FormsView , элемента управления GridView и элемента управления DetailView . В этом руководстве вы используете привязку модели для заполнения элемента управления DropDownList списком категорий продуктов.

Разметка, которую вы добавили в файл AdminPage.aspx, содержит элемент управления DropDownList, называемый DropDownAddCategory.

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

Привязка модели используется для заполнения этого dropDownList путем задания атрибута ItemType и атрибута SelectMethod . Атрибут ItemType указывает, что при заполнении элемента управления используется тип WingtipToys.Models.Category. Вы определили этот тип в начале этой серии учебников, создав Category класс (показан ниже). Класс Category находится в папке Models внутри файла Category.cs .

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; }
}

Атрибут SelectMethod элемента управления DropDownList указывает на использование метода GetCategories (показанного ниже), который включен в файл программной части AdminPage.aspx.cs.

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

Этот метод указывает, что IQueryable интерфейс используется для оценки запроса по типу Category . Возвращаемое значение используется для заполнения DropDownList в разметке страницы (AdminPage.aspx).

Текст, отображаемый для каждого элемента в списке, указывается путем задания атрибута DataTextField . Атрибут DataTextField использует CategoryName класса Category (показан выше) для отображения каждой категории в элементе управления DropDownList. Фактическое значение, передаваемое при выборе элемента в элементе управления DropDownList , основано на атрибуте DataValueField . Атрибут DataValueField имеет значение CategoryID , как определено в Category классе (показано выше).

Как приложение будет работать

Когда пользователь, принадлежащий роли "canEdit", впервые переходит на страницу, элемент управления DropDownAddCategoryDropDownList заполняется, как описано выше. Элемент управления DropDownRemoveProductDropDownList также заполняется товарами с использованием того же подхода. Пользователь, принадлежащий роли CanEdit, выбирает тип категории и добавляет сведения о продукте (имя, описание, цена и файл изображения). Когда пользователь, принадлежащий роли "canEdit", нажимает кнопку "Добавить продукт ", AddProductButton_Click обработчик событий активируется. Обработчик AddProductButton_Click событий, расположенный в файле программной части (AdminPage.aspx.cs), проверяет файл изображения, чтобы убедиться, что он соответствует допустимым типам файлов (.gif, .png, .jpeg или .jpg). Затем файл изображения сохраняется в папке примера приложения Wingtip Toys. Затем новый продукт добавляется в базу данных. Для добавления нового продукта создается новый экземпляр класса AddProducts, который называется products. Класс 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, сразу же увидит обновления в элементах управления DropDownList на странице AdminPage.aspx . Кроме того, включив строку запроса с URL-адресом, на странице может отобразиться сообщение об успешном выполнении для пользователя, относящегося к роли CanEdit.

При перезагрузке страницыPage_Load AdminPage.aspx вызывается событие.

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 — элемент авторизации
ASP.NET Identity
Развертывание безопасного приложения веб-форм ASP.NET с членством, OAuth и базой данных SQL на веб-сайте Azure
Microsoft Azure — бесплатная пробная версия