Membership and Administration
This tutorial shows you how to update the Wingtip Toys sample application to add an administrator role and use ASP.NET membership. It also shows you how to implement an administration page from which the administrator can add and remove products from the website. This tutorial builds on the previous tutorial in the Wingtip Toys tutorial series, Checkout and Payment with PayPal.
What you'll learn:
- How to use code to add an administrator role and a user to the application.
- How to restrict access to the administration folder and page.
- How to provide navigation for the administrator role.
- How to use model binding to populate a DropDownList control with product categories.
- How to upload a file to the web application using the FileUpload control.
- How to use validation controls to implement input validation.
- How to add and remove products from the application.
These features are included in the tutorial:
- ASP.NET Membership
- Configuration and Authorization
- Model Binding
- Unobtrusive Validation
ASP.NET Web Forms provides membership capabilities. By using the default template, you have built-in membership functionality that you can immediately use when the application runs. This tutorial shows you how to use ASP.NET membership to add an administrator role and assign a user to that role. You will learn how to restrict access to the administration folder. You'll add a page to the administration folder that allows an administrator to add and remove products, and to preview a product after it has been added.
Adding an Administrator
Using ASP.NET membership, it's easy to add an administrator role and assign a user to that role using code.
- First, verify that roles are enabled. In Solution Explorer, find and open the Web.config file at the root of the web application.

- Update the roleManager node to include the enabled attribute, so that it appears as follows:
<roleManager enabled="true" defaultProvider="DefaultRoleProvider">
- Now open the Global.asax.cs file and add the code highlighted in yellow to the Application_Start handler. The handler should appear as follows:
void Application_Start(object sender, EventArgs e) { // Code that runs on application startup BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterOpenAuth(); Database.SetInitializer<ProductContext>(new ProductDatabaseInitializer()); // Add Administrator. if (!Roles.RoleExists("Administrator")) { Roles.CreateRole("Administrator"); } if (Membership.GetUser("Admin") == null) { Membership.CreateUser("Admin", "Pa$$word", "Admin@contoso.com"); Roles.AddUserToRole("Admin", "Administrator"); } }
The next time the application starts, the Admin user will be added as the administrator of the application.
Restricting Access to the Administration Page
The Wingtip Toys sample application allows both anonymous users and logged-in users to view and purchase products. However, the logged-in administrator can access a restricted page in order to add and remove products.
Add an Administration Folder and Page
Next, you will create a folder named Admin for the administrator of the Wingtip Toys sample application.
- Right-click the project name (Wingtip Toys) in Solution Explorer and select Add à New Folder.

- Name the new folder Admin.
- Right-click the Admin folder and then select Add à New Item.
The Add New Item dialog box is displayed. - Select the Visual C# > Web templates group on the left. From the middle list, select Web Form using Master Page, and name it AdminPage.aspx.
- Select the Site.Master file as the master page, and then choose OK.
Add a Web.config File
By adding a Web.config file to the Admin folder, you can restrict access to the page contained in the folder.
- 1. Right-click the Admin folder and select Add à New Item.
The Add New Item dialog box is displayed. - 2. From the list of Visual C# web templates, select Web Configuration File from the middle list, accept the default name of Web.config, and then select Add.
- 3. Replace the existing XML content in the Web.config file with the following:
<?xml version="1.0"?> <configuration> <system.web> <authorization> <allow roles="Administrator"/> <deny users="*"/> </authorization> </system.web> </configuration>
Save the Web.config file. The Web.config file specifies that only administrators of the application can access the page contained in the Admin folder.
Including Administrator Navigation
To enable the administrator to navigate to the administration section of the application, you must add a link to the Site.Master page. Only users that belong to the administrator role will be able to see the Admin link and access the administration section.
- 1. In Solution Explorer, find and open the Site.Master page.
- 2. To create a link for administrators, add the markup highlighted in yellow to the nav element so that the result appears as follows:
<nav> <ul id="menu"> <li> <span id="adminLink" runat="server" visible="false"> <a href="/Admin/AdminPage.aspx">Admin</a> </span> </li> <li><a href="/">Home</a></li> <li><a href="/About.aspx">About</a></li> <li><a href="/Contact.aspx">Contact</a></li> <li><a href="/ProductList.aspx">Products</a></li> </ul> </nav> - Open the Site.Master.cs file and make the Admin link visible only to administrators by adding the code highlighted in yellow to the Page_Load handler.
The Page_Load handler will appear as follows:
protected void Page_Load(object sender, EventArgs e) { if (HttpContext.Current.User.IsInRole("Administrator")) { adminLink.Visible = true; } }
When the page loads, the code checks whether the logged-in user has the role of Administrator. If the user is an administrator, the span element containing the link to the AdminPage.aspx page (and consequently the link inside the span) is made visible.
Enabling Product Administration
So far, you have created the administrator role and added an administrator user, an administration folder, and an administration page. You have set access rights for the administration folder and page, and have added a navigation link for the administrator to the application. Next, you will add markup to the AdminPage.aspx page and code to the AdminPage.aspx.cs code-behind file that will enable the administrator to add and remove products.
- Next, open the AdminPage.aspx.cs code-behind file by right-clicking the AdminPage.aspx and clicking View Code.
- Replace the existing code in the AdminPage.aspx.cs code-behind file with the following code:
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 IQueryableGetCategories() { 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) { 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."; } } }}
In Solution Explorer, open the AdminPage.aspx file from the Admin folder.
Replace the existing markup with the following:
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="AdminPage.aspx.cs" Inherits="WingtipToys.Admin.AdminPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="FeaturedContent" 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>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
</asp:Content>
In the code that you entered for the AdminPage.aspx.cs code-behind file, a class called AddProducts does the actual work of adding products to the database. This class doesn't exist yet, so you will create it now.
- In Solution Explorer, right-click the Logic folder and then select Add à New Item.
The Add New Item dialog box is displayed. - Select the Visual C# > Code templates group on the left. Then, select Class from the middle list and name it AddProducts.cs.
The new class file is displayed. - Replace the existing code with the following:
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); // Get DB context. ProductContext _db = new ProductContext(); // Add product to DB. _db.Products.Add(myProduct); _db.SaveChanges(); // Success. return true; } } }
The AdminPage.aspx page allows the administrator to add and remove products. When a new product is added, the details about the product are validated and then entered into the database. The new product is immediately available to all users of the web application.
Unobtrusive Validation
The product details that the user provides on the AdminPage.aspx page are validated using validation controls (RequiredFieldValidator and RegularExpressionValidator). These controls automatically use unobtrusive validation. Unobtrusive validation allows the validation controls to use JavaScript for client-side validation logic, which means the page does require a trip to the server to be validated. By default, unobtrusive validation is included in the Web.config file based on the following configuration setting:
<add key="ValidationSettings:UnobtrusiveValidationMode" value="WebForms" />
Regular Expressions
The product price on the AdminPage.aspx page is validated using a RegularExpressionValidator control. This control validates whether the value of the associated input control (the "AddProductPrice" TextBox) matches the pattern specified by the regular expression. A regular expression is a pattern-matching notation that enables you to quickly find and match specific character patterns. The RegularExpressionValidator control includes a property named ValidationExpression that contains the regular expression used to validate price input, as shown below:
<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 Control
In addition to the input and validation controls, you added the FileUpload control to the AdminPage.aspx page. This control provides the capability to upload files. In this case, you are only allowing image files to be uploaded. In the code-behind file (AdminPage.aspx.cs), when the AddProductButton is clicked, the code checks the HasFile property of the FileUpload control. If the control has a file and if the file type (based on file extension) is allowed, the image is saved to the Images folder and the Images/Thumbs folder of the application.
Model Binding
Earlier in this tutorial series you used model binding to populate a ListView control, a FormsView control, a GridView control, and a DetailView control. In this tutorial, you use model binding to populate a DropDownList control with a list of product categories.
The markup that you added to the AdminPage.aspx file contains a DropDownList control called DropDownAddCategory:
<asp:DropDownList ID="DropDownAddCategory" runat="server"
ItemType="WingtipToys.Models.Category"
SelectMethod="GetCategories" DataTextField="CategoryName"
DataValueField="CategoryID" >
</asp:DropDownList>
You use model binding to populate this DropDownList by setting the ItemType attribute and the SelectMethod attribute. The ItemType attribute specifies that you use the WingtipToys.Models.Category type when populating the control. You defined this type at the beginning of this tutorial series by creating the Category class (shown below). The Category class is in the Models folder inside the Category.cs file.
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; }
}
The SelectMethod attribute of the DropDownList control specifies that you use the GetCategories method (shown below) that is included in the code-behind file (AdminPage.aspx.cs).
public IQueryable<Category> GetCategories()
{
var db = new WingtipToys.Models.ProductContext();
IQueryable<Category> query = db.Categories;
return query;
}
This method specifies that an IQueryable interface is used to evaluate a query against a Category type. The returned value is used to populate the DropDownList in the markup of the page (AdminPage.aspx).
The text displayed for each item in the list is specified by setting the DataTextField attribute. The DataTextField attribute uses the CategoryName of the Category Class (shown above) to display each category in the DropDownList control. The actual value that is passed when an item is selected in the DropDownList control is based on the DataValueField attribute. The DataValueField attribute is set to the CategoryID as define in the Category class (shown above).
How the Application Will Work
When the administrator navigates to the page for the first time, the DropDownAddCategory DropDownList control is populated as described above. The DropDownRemoveProduct DropDownList control is also populated with products using the same approach. The administrator selects the category type and adds product details (Name, Description, Price, and Image File). When the administrator clicks the Add Product button, the AddProductButton_Click event handler is triggered. The AddProductButton_Click event handler located in the code-behind file (AdminPage.aspx.cs) checks the image file to make sure it matches the allowed file types (.gif, .png, .jpeg, or .jpg). Then, the image file is saved into a folder of the Wingtip Toys sample application. Next, the new product is added to the database. To accomplish adding a new product, a new instance of the AddProducts class is created and named products. The AddProducts class has a method named AddProduct, and the products object calls this method to add products to the database.
// Add product data to DB.
AddProducts products = new AddProducts();
bool addSuccess = products.AddProduct(AddProductName.Text, AddProductDescription.Text,
AddProductPrice.Text, DropDownAddCategory.SelectedValue, ProductImage.FileName);
If the code successfully adds the new product to the database, the page is reloaded with the query string value ProductAction=add.
Response.Redirect(pageUrl + "?ProductAction=add");
When the page reloads, the query string is included in the URL. By reloading the page, the administrator can immediately see the updates in the DropDownList controls on the AdminPage.aspx page. Also, by including the query string with the URL, the page can display a success message to the administrator.
When the AdminPage.aspx page reloads, the Page_Load event is called.
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!";
}
}
The Page_Load event handler checks the query string value and determines whether to show a success message.
Running the Application
You can run the application now to see how you can add, delete, and update items in the shopping cart. The shopping cart total will reflect the total cost of all items in the shopping cart.
- In Solution Explorer, press Ctrl+F5 to run the Wingtip Toys sample application.
The browser opens and shows the Default.aspx page. - Click the Log in link at the top of the page.

The Login.aspx page is displayed. - Use the following administrator user name and password:
User name: Admin
Password: Pa$$word

- Click the Log in button at the bottom of the page.
- At the top of the next page, select the Admin link to navigate to the AdminPage.aspx page.

- To test the input validation, click the Add Product button without adding any product details.

- Add the details for a new product, and then click the Add Product button.

- Select Products from the top navigation menu to view the new product you added.

- Click the Admin link to return to the administration page.
- In the Remove Product section of the page, select the new product you added in the DropDownListBox.
- Click the Remove Product button to remove the new product from the application.

- Select Products from the top navigation menu to confirm that the product has been removed.
Summary
In this tutorial, you added an administrator role and an administrative user, restricted access to the administration folder and page, and provided navigation for the administrator role. You used model binding to populate a DropDownList control with data. You implemented the FileUpload control and validation controls. Also, you have learned how to add and remove products from a database. In the next tutorial, you'll learn how to implement ASP.NET routing.

Comments (0) RSS Feed