Członkostwo i administracja

Autor: Erik Reitan

W tej serii samouczków przedstawiono podstawy tworzenia aplikacji ASP.NET Web Forms przy użyciu ASP.NET 4.5 i Microsoft Visual Studio Express 2013 for Web. Projekt Visual Studio 2013 z kodem źródłowym języka C# jest dostępny do dołączenia do tej serii samouczków.

W tym samouczku pokazano, jak zaktualizować przykładową aplikację Wingtip Toys, aby dodać rolę niestandardową i użyć ASP.NET Identity. Pokazano również, jak zaimplementować stronę administracyjną, z której użytkownik z rolą niestandardową może dodawać i usuwać produkty z witryny internetowej.

ASP.NET Identity to system członkostwa używany do tworzenia aplikacji internetowej ASP.NET i jest dostępny w ASP.NET 4.5. usługa ASP.NET Identity jest używana w szablonie projektu Visual Studio 2013 Web Forms, a także szablony dla ASP.NET MVC, ASP.NET internetowego interfejsu API i aplikacji jednostronicowej ASP.NET. Można również zainstalować system ASP.NET Identity przy użyciu narzędzia NuGet podczas uruchamiania z pustą aplikacją internetową. Jednak w tej serii samouczków używasz Web Forms projecttemplate, który obejmuje system ASP.NET Identity. ASP.NET Identity ułatwia integrowanie danych profilu specyficznego dla użytkownika z danymi aplikacji. Ponadto usługa ASP.NET Identity umożliwia wybranie modelu trwałości profilów użytkowników w aplikacji. Dane można przechowywać w bazie danych SQL Server lub innym magazynie danych, w tym magazynach danych NoSQL, takich jak tabele usługi Windows Azure Storage.

Ten samouczek opiera się na poprzednim samouczku zatytułowanym "Wyewidencjonowanie i płatność za pomocą usługi PayPal" w serii samouczków Wingtip Toys.

Zawartość:

  • Jak używać kodu do dodawania roli niestandardowej i użytkownika do aplikacji.
  • Jak ograniczyć dostęp do folderu administracyjnego i strony.
  • Jak zapewnić nawigację dla użytkownika należącego do roli niestandardowej.
  • Jak używać powiązania modelu do wypełniania kontrolki DropDownList kategoriami produktów.
  • Jak przekazać plik do aplikacji internetowej przy użyciu kontrolki FileUpload .
  • Jak używać kontrolek walidacji do implementowania walidacji danych wejściowych.
  • Jak dodawać i usuwać produkty z aplikacji.

Te funkcje są uwzględnione w samouczku:

  • ASP.NET Identity
  • Konfiguracja i autoryzacja
  • Powiązanie modelu
  • Nieuprawnia walidacja

ASP.NET Web Forms zapewnia możliwości członkostwa. Korzystając z szablonu domyślnego, masz wbudowaną funkcję członkostwa, której można natychmiast użyć podczas uruchamiania aplikacji. W tym samouczku pokazano, jak używać tożsamości ASP.NET do dodawania roli niestandardowej i przypisywania użytkownika do tej roli. Dowiesz się, jak ograniczyć dostęp do folderu administracyjnego. Dodasz stronę do folderu administracyjnego, który umożliwia użytkownikowi z rolą niestandardową dodawanie i usuwanie produktów oraz wyświetlanie podglądu produktu po jego dodaniu.

Dodawanie roli niestandardowej

Za pomocą ASP.NET Identity można dodać rolę niestandardową i przypisać użytkownika do tej roli przy użyciu kodu.

  1. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Logic i utwórz nową klasę.

  2. Nadaj nowej klasie nazwę RoleActions.cs.

  3. Zmodyfikuj kod tak, aby był wyświetlany w następujący sposób:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace WingtipToys.Logic
    {
        internal class RoleActions
        {
        }
    }
    
  4. W Eksplorator rozwiązań otwórz plik Global.asax.cs.

  5. Zmodyfikuj plik Global.asax.cs , dodając kod wyróżniony kolorem żółtym, aby był wyświetlany w następujący sposób:

    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. Zwróć uwagę, że AddUserAndRole jest podkreślony na czerwono. Kliknij dwukrotnie kod AddUserAndRole.
    Litera "A" na początku wyróżnionej metody zostanie podkreślona.

  7. Umieść kursor nad literą "A" i kliknij interfejs użytkownika, który umożliwia wygenerowanie wycinku AddUserAndRole metody dla metody.

    Członkostwo i administracja — generowanie wycinków metody

  8. Kliknij opcję zatytułowaną:
    Generate method stub for "AddUserAndRole" in "WingtipToys.Logic.RoleActions"

  9. Otwórz plik RoleActions.cs z folderu Logika .
    Metoda AddUserAndRole została dodana do pliku klasy.

  10. Zmodyfikuj plik RoleActions.cs , usuwając NotImplementedException i dodając kod wyróżniony kolorem żółtym, tak aby był wyświetlany w następujący sposób:

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

Powyższy kod najpierw ustanawia kontekst bazy danych dla bazy danych członkostwa. Baza danych członkostwa jest również przechowywana jako plik mdf w folderze App_Data . Po zalogowaniu się pierwszego użytkownika do tej aplikacji internetowej będzie można wyświetlić tę bazę danych.

Uwaga

Jeśli chcesz przechowywać dane członkostwa wraz z danymi produktu, możesz rozważyć użycie tego samego elementu DbContext użytego do przechowywania danych produktu w powyższym kodzie.

Słowo kluczowe wewnętrzne jest modyfikatorem dostępu dla typów (takich jak klasy) i składowych typów (takich jak metody lub właściwości). Typy wewnętrzne lub elementy członkowskie są dostępne tylko w plikach zawartych w tym samym zestawie (plik .dll ). Podczas tworzenia aplikacji tworzony jest plik zestawu (.dll), który zawiera kod wykonywany podczas uruchamiania aplikacji.

RoleStore Obiekt, który zapewnia zarządzanie rolami, jest tworzony na podstawie kontekstu bazy danych.

Uwaga

Zwróć uwagę, że po utworzeniu RoleStore obiektu jest używany typ ogólny IdentityRole . Oznacza to, że RoleStore obiekt może zawierać IdentityRole tylko obiekty. Ponadto przy użyciu typów ogólnych zasoby w pamięci są obsługiwane lepiej.

RoleManager Następnie obiekt zostanie utworzony na podstawie właśnie utworzonego RoleStore obiektu. RoleManager obiekt uwidacznia interfejs API powiązany z rolą, który może służyć do automatycznego zapisywania zmian w obiekcie RoleStore. Obiekt RoleManager może zawierać IdentityRole tylko obiekty, ponieważ kod używa <IdentityRole> typu Ogólnego.

Wywołasz metodę , RoleExists aby określić, czy rola "canEdit" jest obecna w bazie danych członkostwa. Jeśli tak nie jest, należy utworzyć rolę.

UserManager Tworzenie obiektu wydaje się być bardziej skomplikowane niż kontrolkaRoleManager, jednak jest prawie takie samo. Jest on po prostu zakodowany w jednym wierszu, a nie na kilku. W tym miejscu przekazywany parametr tworzy wystąpienie nowego obiektu znajdującego się w nawiasie.

Następnie utworzysz użytkownika "canEditUser", tworząc nowy ApplicationUser obiekt. Następnie, jeśli pomyślnie utworzysz użytkownika, dodaj użytkownika do nowej roli.

Uwaga

Obsługa błędów zostanie zaktualizowana podczas samouczka "obsługa błędów ASP.NET" w dalszej części tej serii samouczków.

Przy następnym uruchomieniu aplikacji użytkownik o nazwie "canEditUser" zostanie dodany jako rola o nazwie "canEdit" aplikacji. W dalszej części tego samouczka zalogujesz się jako użytkownik "canEditUser", aby wyświetlić dodatkowe możliwości dodane podczas tego samouczka. Aby uzyskać szczegółowe informacje o ASP.NET Identity, zobacz przestrzeń nazw Microsoft.AspNet.Identity. Aby uzyskać dodatkowe informacje na temat inicjowania systemu ASP.NET Identity, zobacz AspnetIdentitySample.

Ograniczanie dostępu do strony administracyjnej

Przykładowa aplikacja Wingtip Toys umożliwia użytkownikom anonimowym i zalogowanym użytkownikom wyświetlanie i kupowanie produktów. Jednak zalogowany użytkownik z niestandardową rolą "canEdit" może uzyskać dostęp do strony z ograniczeniami, aby dodawać i usuwać produkty.

Dodawanie folderu administracyjnego i strony

Następnie utworzysz folder o nazwie Administracja dla użytkownika "canEditUser" należącego do roli niestandardowej przykładowej aplikacji Wingtip Toys.

  1. Kliknij prawym przyciskiem myszy nazwę projektu (Wingtip Toys) w Eksplorator rozwiązań i wybierz polecenie Dodaj ->Nowy folder.
  2. Nazwij nowy folder Administracja.
  3. Kliknij prawym przyciskiem myszy folder Administracja, a następnie wybierz polecenie Dodaj ->Nowy element.
    Zostanie wyświetlone okno dialogowe Dodaj nowy element.
  4. Wybierz grupę Szablony języka Visual C#->Web po lewej stronie. Na środkowej liście wybierz pozycję Formularz internetowy ze stroną wzorcową, nadaj jej nazwę AdminPage.aspx, a następnie wybierz pozycję Dodaj.
  5. Wybierz plik Site.Master jako stronę wzorcową, a następnie wybierz przycisk OK.

Dodawanie pliku Web.config

Dodając plik Web.config do folderu Administracja, można ograniczyć dostęp do strony zawartej w folderze.

  1. Kliknij prawym przyciskiem myszy folder Administracja i wybierz polecenie Dodaj ->Nowy element.
    Zostanie wyświetlone okno dialogowe Dodaj nowy element.

  2. Z listy szablonów sieci Web visual C# wybierz pozycję Plik konfiguracji sieci Webz środkowej listy, zaakceptuj domyślną nazwę Web.config, a następnie wybierz pozycję Dodaj.

  3. Zastąp istniejącą zawartość XML w pliku Web.config następującym kodem:

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

Zapisz plik Web.config . Plik Web.config określa, że tylko użytkownik należący do roli "canEdit" aplikacji może uzyskać dostęp do strony zawartej w folderze Administracja.

Dołączanie nawigacji roli niestandardowej

Aby umożliwić użytkownikowi niestandardowej roli "canEdit" przejście do sekcji administracyjnej aplikacji, należy dodać link do strony Site.Master . Tylko użytkownicy należący do roli "canEdit" będą mogli wyświetlić link Administracja i uzyskać dostęp do sekcji administracja.

  1. W Eksplorator rozwiązań znajdź i otwórz stronę Site.Master.

  2. Aby utworzyć link dla użytkownika roli "canEdit", dodaj znacznik wyróżniony w kolorze żółtym do następującego nieurządkowanego elementu listy <ul> , aby lista pojawiła się w następujący sposób:

    <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. Otwórz plik Site.Master.cs . Utwórz link Administracja widoczny tylko dla użytkownika "canEditUser", dodając kod wyróżniony kolorem żółtym Page_Load do procedury obsługi. Procedura obsługi będzie wyświetlana Page_Load w następujący sposób:

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

Po załadowaniu strony kod sprawdza, czy zalogowany użytkownik ma rolę "canEdit". Jeśli użytkownik należy do roli "canEdit", element span zawierający link do strony AdminPage.aspx (a w związku z tym link wewnątrz zakresu) jest widoczny.

Włączanie administrowania produktami

Do tej pory utworzono rolę "canEdit" i dodano użytkownika "canEditUser", folderu administracyjnego i strony administracyjnej. Masz ustawione prawa dostępu dla folderu i strony administracyjnej i dodano link nawigacyjny dla użytkownika roli "canEdit" do aplikacji. Następnie dodasz znaczniki do strony AdminPage.aspx i kodu do pliku AdminPage.aspx.cs code-behind, który umożliwi użytkownikowi rolę "canEdit", aby dodać i usunąć produkty.

  1. W Eksplorator rozwiązań otwórz plik AdminPage.aspx z folderu Administracja.

  2. Zastąp istniejące znaczniki następującymi elementami:

    <%@ 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. Następnie otwórz plik AdminPage.aspx.cs , klikając prawym przyciskiem myszy plik AdminPage.aspx i klikając polecenie Wyświetl kod.

  4. Zastąp istniejący kod w pliku AdminPage.aspx.cs code-behind następującym kodem:

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

W kodzie wprowadzonym dla pliku AdminPage.aspx.cs code-behind klasa o nazwie AddProducts wykonuje rzeczywistą pracę dodawania produktów do bazy danych. Ta klasa jeszcze nie istnieje, więc utworzysz ją teraz.

  1. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Logika, a następnie wybierz polecenie Dodaj ->Nowy element.
    Zostanie wyświetlone okno dialogowe Dodaj nowy element.

  2. Wybierz grupę Visual C# ->Code templates (Szablony kodu) po lewej stronie. Następnie wybierz pozycję Klasaz listy środkowej i nadaj jej nazwę AddProducts.cs.
    Zostanie wyświetlony nowy plik klasy.

  3. Zastąp istniejący kod następującym kodem:

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

Strona AdminPage.aspx umożliwia użytkownikowi należącemu do roli "canEdit" dodawanie i usuwanie produktów. Po dodaniu nowego produktu szczegóły dotyczące produktu zostaną zweryfikowane, a następnie wprowadzone do bazy danych. Nowy produkt jest natychmiast dostępny dla wszystkich użytkowników aplikacji internetowej.

Nieuprawnia walidacja

Szczegóły produktu, które użytkownik udostępnia na stronie AdminPage.aspx , są weryfikowane przy użyciu kontrolek weryfikacji (RequiredFieldValidator i RegularExpressionValidator). Te kontrolki automatycznie używają nieautoryzowanej weryfikacji. Walidacja niestruzyjna umożliwia kontrolek walidacji do używania języka JavaScript dla logiki weryfikacji po stronie klienta, co oznacza, że strona nie wymaga sprawdzenia poprawności podróży do serwera. Domyślnie walidacja niestruktywna jest uwzględniana w pliku Web.config na podstawie następującego ustawienia konfiguracji:

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

Wyrażenia regularne

Cena produktu na stronie AdminPage.aspx jest weryfikowana przy użyciu kontrolki RegularExpressionValidator . Ta kontrolka sprawdza, czy wartość skojarzonej kontrolki wejściowej (AddProductPrice" TextBox) jest zgodna ze wzorcem określonym przez wyrażenie regularne. Wyrażenie regularne to notacja dopasowania wzorca, która umożliwia szybkie znajdowanie i dopasowywanie określonych wzorców znaków. Kontrolka RegularExpressionValidator zawiera właściwość o nazwie ValidationExpression , która zawiera wyrażenie regularne używane do weryfikowania danych wejściowych cen, jak pokazano poniżej:

<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, kontrolka

Oprócz kontrolek wejściowych i sprawdzania poprawności dodano kontrolkę FileUpload do strony AdminPage.aspx . Ta kontrolka zapewnia możliwość przekazywania plików. W takim przypadku zezwalasz tylko na przekazywanie plików obrazów. W pliku za kodem (AdminPage.aspx.cs) po AddProductButton kliknięciu kodu kod sprawdza HasFile właściwość kontrolki FileUpload . Jeśli kontrolka ma plik, a typ pliku (na podstawie rozszerzenia pliku) jest dozwolony, obraz jest zapisywany w folderze Images i folder Images/Thumbs aplikacji.

Powiązanie modelu

Wcześniej w tej serii samouczków użyto powiązania modelu do wypełnienia kontrolki ListView , kontrolki FormsView , kontrolki GridView i kontrolki DetailView . W tym samouczku użyjesz powiązania modelu, aby wypełnić kontrolkę DropDownList listą kategorii produktów.

Znacznik dodany do pliku AdminPage.aspx zawiera kontrolkę DropDownList o nazwie DropDownAddCategory:

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

Powiązanie modelu służy do wypełniania tej listy rozwijanej przez ustawienie atrybutu ItemType i atrybutu SelectMethod . Atrybut ItemType określa, że używasz WingtipToys.Models.Category typu podczas wypełniania kontrolki. Ten typ został zdefiniowany na początku tej serii samouczków, tworząc klasę Category (pokazaną poniżej). Klasa Category znajduje się w folderze Models w pliku 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; }
}

Atrybut SelectMethod kontrolki DropDownList określa, że używasz GetCategories metody (pokazanej poniżej), która znajduje się w pliku za kodem (AdminPage.aspx.cs).

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

Ta metoda określa, że IQueryable interfejs jest używany do oceny zapytania względem Category typu. Zwrócona wartość jest używana do wypełniania listy rozwijanej w znaczniku strony (AdminPage.aspx).

Tekst wyświetlany dla każdego elementu na liście jest określony przez ustawienie atrybutu DataTextField . Atrybut DataTextField używa CategoryNameCategory klasy (pokazanej powyżej), aby wyświetlić każdą kategorię w kontrolce DropDownList . Rzeczywista wartość przekazywana po wybraniu elementu w kontrolce DropDownList jest oparta na atrybucie DataValueField . Atrybut DataValueField jest ustawiony na wartość zdefiniowaną CategoryID w Category klasie (pokazano powyżej).

Jak działa aplikacja

Gdy użytkownik należący do roli "canEdit" po raz pierwszy przechodzi do strony, kontrolka DropDownAddCategoryDropDownList jest wypełniana zgodnie z powyższym opisem. Kontrolka DropDownRemoveProductDropDownList jest również wypełniana produktami przy użyciu tego samego podejścia. Użytkownik należący do roli "canEdit" wybiera typ kategorii i dodaje szczegóły produktu (Nazwa, Opis, Cena i Plik obrazu). Gdy użytkownik należący do roli "canEdit" kliknie przycisk Dodaj produkt , AddProductButton_Click zostanie wyzwolony program obsługi zdarzeń. Procedura AddProductButton_Click obsługi zdarzeń znajdująca się w pliku za kodem (AdminPage.aspx.cs) sprawdza plik obrazu, aby upewnić się, że jest zgodny z dozwolonymi typami plików (.gif, .png, jpeg lub .jpg). Następnie plik obrazu jest zapisywany w folderze przykładowej aplikacji Wingtip Toys. Następnie nowy produkt zostanie dodany do bazy danych. W celu dodania nowego produktu zostanie utworzone nowe wystąpienie AddProducts klasy i nazwane produkty. Klasa AddProducts ma metodę o nazwie AddProduct, a obiekt products wywołuje tę metodę, aby dodać produkty do bazy danych.

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

Jeśli kod pomyślnie doda nowy produkt do bazy danych, strona zostanie ponownie załadowana z wartością ProductAction=addciągu zapytania .

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

Gdy strona zostanie ponownie załadowana, ciąg zapytania zostanie uwzględniony w adresie URL. Po ponownym załadowaniu strony użytkownik należący do roli "canEdit" może natychmiast zobaczyć aktualizacje w kontrolkach DropDownList na stronie AdminPage.aspx . Ponadto, uwzględniając ciąg zapytania z adresem URL, strona może wyświetlić komunikat o powodzeniu dla użytkownika należącego do roli "canEdit".

Po ponownym załadowaniu strony AdminPage.aspx zdarzenie jest wywoływane 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!";
    }
}

Procedura Page_Load obsługi zdarzeń sprawdza wartość ciągu zapytania i określa, czy ma być wyświetlany komunikat o powodzeniu.

Uruchamianie aplikacji

Teraz możesz uruchomić aplikację, aby zobaczyć, jak można dodawać, usuwać i aktualizować elementy w koszyku. Łączna kwota koszyka będzie odzwierciedlać całkowity koszt wszystkich przedmiotów w koszyku.

  1. W Eksplorator rozwiązań naciśnij klawisz F5, aby uruchomić przykładową aplikację Wingtip Toys.
    Zostanie otwarta przeglądarka i zostanie wyświetlona strona Default.aspx .

  2. Kliknij link Zaloguj w górnej części strony.

    Członkostwo i administracja — link logowania

    Zostanie wyświetlona strona Login.aspx .

  3. Wprowadź nazwę użytkownika i hasło.

    Członkostwo i administracja — strona logowania

  4. Kliknij przycisk Zaloguj się w dolnej części strony.

  5. W górnej części następnej strony wybierz link Administracja, aby przejść do strony AdminPage.aspx.

    Członkostwo i administracja — link Administracja

  6. Aby przetestować walidację danych wejściowych, kliknij przycisk Dodaj produkt bez dodawania szczegółów produktu.

    Członkostwo i administracja — strona Administracja

    Zwróć uwagę, że wyświetlane są wymagane komunikaty pól.

  7. Dodaj szczegóły nowego produktu, a następnie kliknij przycisk Dodaj produkt .

    Członkostwo i administracja — dodawanie produktu

  8. Wybierz pozycję Produkty z górnego menu nawigacyjnego, aby wyświetlić dodany nowy produkt.

    Członkostwo i administracja — pokaż nowy produkt

  9. Kliknij link Administracja, aby powrócić do strony administracyjnej.

  10. W sekcji Usuń produkt na stronie wybierz nowy produkt dodany w polu DropDownListBox.

  11. Kliknij przycisk Usuń produkt , aby usunąć nowy produkt z aplikacji.

    Członkostwo i administracja — usuwanie produktu

  12. Wybierz pozycję Produkty z górnego menu nawigacyjnego, aby potwierdzić, że produkt został usunięty.

  13. Kliknij przycisk Wyloguj się , aby istnieć tryb administracyjny.
    Zwróć uwagę, że górne okienko nawigacji nie pokazuje już elementu menu Administracja.

Podsumowanie

W tym samouczku dodano rolę niestandardową i użytkownika należącego do roli niestandardowej, ograniczony dostęp do folderu administracyjnego i strony oraz udostępniono nawigację dla użytkownika należącego do roli niestandardowej. Powiązanie modelu zostało użyte do wypełnienia kontrolki DropDownList danymi. Zaimplementowano kontrolkę FileUpload i kontrolki walidacji. Wiesz również, jak dodawać i usuwać produkty z bazy danych. W następnym samouczku dowiesz się, jak zaimplementować routing ASP.NET.

Dodatkowe zasoby

Web.config — element autoryzacji
ASP.NET Identity
Wdrażanie bezpiecznej aplikacji ASP.NET Web Forms z członkostwem, uwierzytelnianiem OAuth i SQL Database w witrynie internetowej platformy Azure
Microsoft Azure — bezpłatna wersja próbna