Create Your Own Web Site Administration Tool in ASP.NET
Objective
The objective of this tutorial is to show the steps you have to follow to create your own WAT (Web site Administration tool) in ASP.NET.
Pre-requirements
In order to follow this tutorial, you have to meet the below conditions:
- IIS 5.0/6.0 web server installed on your PC;
- .NET 2.0 framework or above installed on your PC;
- An ASP.NET site (authentication is done via forms);
- A SQL server database (aspnetdb.mdf in our case) in the App_data folder of the application; This db must have the sql schema for membership,
profiles and roles.
Introduction to WAT (Web site administration tool)
ASP.NET 2.0 already includes a WAT that is available from the Visual Studio 2005 Website menu via the ASP.NET Configuration menu option.
This WAT allows only local websites to be administered. So, restrictions appear when you have your web site remotely hosting with a web hosting company.
The solution is to create your own WAT tool from the beginning as part of your web site.
So, with this tool you can administrate the users and the roles in a web site. Note, if you don't like to build this application from the beginning, you can download Web Site Administration Visual Studio Project, used in this tutorial
Membership management
The principal class of the ASP.NET 2.0 is System.Web.Security.Membership, which exposes a number of static methods to administrate the users from a web
site. In order to have a complete description of these methods please consult the MSDN's documentation related to this issue.
The provider for the Membership system is configured in the web.config. Most of the default settings are hard-coded in the ASP.NET runtime due to
improve performance. So, by configuring the provider in the web.config file, you override the defult setting with your own.
Please add the code below to your web.config file:
<connectionStrings>
<remove
name="LocalSqlServer"/>
<add
name="LocalSqlServer"
connectionString="Data
Source=.\SQLExpress;Integrated Security=True;User
Instance=True;AttachDBFilename=|DataDirectory|aspnetdb.mdf"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<!--
other settings...
-->
<membership
defaultProvider="MyMembershipProvider"
userIsOnlineTimeWindow="15">
<providers>
<add
name="MyMembershipProvider"
connectionStringName="LocalSqlServer"
applicationName="/"
enablePasswordRetrieval="true"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
requiresUniqueEmail="true"
passwordFormat="Clear"
maxInvalidPasswordAttempts="5"
passwordAttemptWindow="10"
minRequiredPasswordLength="5"
minRequiredNonalphanumericCharacters="0"
type="System.Web.Security.SqlMembershipProvider,
System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
</providers>
</membership>
<!--
other settings...
-->
</system.web>
First of all, I configured in the <connectionStrings> section the connection string the application will use to
connect to the db. In our case the name of the db is aspnetdb.mdf and is placed in the App_Code folder.
As you can see here you can configure how many password attempts there will be, the password's length and other settings
important for the Membership system.
Roles in ASP.NET
A system that supports authentication/authorization will have a support for roles too. The purpose of roles is to group
users together for assigning a set of permissions, or authorizations. In this way the administrator's task is much easier.
Like in the Membership system, ASP.NET 2.0 has built-in support for roles, with regard to performance, security, and
flexibility. There is a default provider for SQL Server, but if you want to customize it you can write your own provider.
The role management is disabled by default to improve performance for sites that don't need roles. In order to enable it,
please enter the code below in the web.config file.
<system.web>
<!--
other settings...
-->
<roleManager
enabled="true"
cacheRolesInCookie="true"
cookieName="MYROLES"
defaultProvider="MyRoleProvider">
<providers>
<add
name="MyRoleProvider"
connectionStringName="LocalSqlServer"
applicationName="/"
type="System.Web.Security.SqlRoleProvider,
System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
</providers>
</roleManager>
<!--
other settings...
-->
</system.web>
With this code you enabled the roles management system and configured your own provider.
System.Web.Security.Roles is the class that allows you to access and manage role information programmatically.
In order to have a complete description of these methods please consult the MSDN's documentation related to this issue.
User profile
ASP.NET 2.0 comes with a built-in mechanism to manage user profiles, in an easy, yet very complete and flexible, way.
The Profile module is easy to be implemented - for this you need to configure what the profile will contain.
For every property, you have to define the property name and its type. So, if we want to add a BirthDate profile property,
we must add the <add name="BirthDate" type="DateTime"/> code.
Please add the below code you your web.config file.
<system.web>
<!--
other settings...
-->
<profile
defaultProvider="MyProfileProvider">
<providers>
<add
name="MyProfileProvider"
connectionStringName="LocalSqlServer"
applicationName="/"
type="System.Web.Profile.SqlProfileProvider,
System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
</providers>
<properties>
<add
name="FirstName"
type="String"
/>
<add
name="LastName"
type="String"
/>
<add
name="Gender"
type="String"
/>
<add
name="BirthDate"
type="DateTime"
/>
<add
name="Occupation"
type="String"
/>
<add
name="Website"
type="String"
/>
<group
name="Address">
<add
name="Street"
type="String"
/>
<add
name="PostalCode"
type="String"
/>
<add
name="City"
type="String"
/>
<add
name="State"
type="String"
/>
</group>
<group
name="Contacts">
<add
name="Phone"
type="String"
/>
<add
name="Fax"
type="String"
/>
</group>
</properties>
</profile>
<!--
other settings...
-->
</system.web>
SQL Server data store
All data about users, their profiles and roles are stored in SQL Server data store.
ASP.NET 2.0 comes with a pre-built and ready to go data store structure for users, profiles and roles. It also provides
default providers: SqlMembershipProvider, SqlProfileProvider and SqlRoleProvider.
As I already specified, there is a pre-build data store structure. So, you don't have to lose precious time creating
tables, relations between tables and stored procedures. The membership system uses the next tables: aspnet_Applications,
aspnet_Users and aspnet_Membership. For role management we have two more tables: aspnet_Roles and aspnet_UsersInRoles.
For the profile system, tables are created after you specify the profile properties in the web.config file.
Create your own Website Administration Tool: The ManageUsers Administrative Page
Let's name this page ManageUsers.aspx. The user interface for this page can be divided into three parts:
The first part shows the number of registered users. It also shows how many of them are currently online.
The second part provides features for searching and listing the users. There is an "alphabet bar" with all the
letters of the alphabet; when one is clicked, a grid is filled with all the users having names starting with that letter.
There is also a facility to search for the users by providing a partial username or e-mail address.
In he third part with the help of a grid you can lists users and some of their profile properties.
The code below shows how you can implement the first two parts:
<%@
Page Language="C#"
AutoEventWireup="true"
CodeFile="ManageUsers.aspx.cs"
Inherits="ManageUsers"
%>
<html
xmlns="http://www.w3.org/1999/xhtml">
<head
id="Head1"
runat="server">
<title>Untitled
Page</title>
</head>
<body>
<form
id="form2"
runat="server">
<div>Users
Account Management</div>
<p></p>
<b>-
The total registered users is: <asp:Literal
runat="server"
ID="lblTotalUsers"
/><br
/>
- The total online
users at this moment: <asp:Literal
runat="server"
ID="lblOnlineUsers"
/></b>
<p></p>
In order to display
all users whose name begins with letter click on the link letter:
<p></p>
<asp:Repeater
runat="server"
ID="rptAlphabetBar"
OnItemCommand="rptAlphabetBar_ItemCommand">
<ItemTemplate><asp:LinkButton
ID="LinkButton1"
runat="server"
Text='<%#
Container.DataItem %>'
CommandArgument='<%#
Container.DataItem %>'
/>
</ItemTemplate>
</asp:Repeater>
<p></p>
Use the below feature
to search users by partial username or e-mail:
<p></p>
<asp:DropDownList
runat="server"
ID="ddlUserSearchTypes">
<asp:ListItem
Text="UserName"
Selected="true"
/>
<asp:ListItem
Text="E-mail"
/>
</asp:DropDownList>
contains
<asp:TextBox
runat="server"
ID="txtSearchText"
/>
<asp:Button
runat="server"
ID="btnSearch"
Text="Search"
OnClick="btnSearch_Click"
/>
For the alphabet bar I used a Repeater control, instead of a fixed list of links. To this Repeater control I bounded an
array of characters that will finally be displayed as links. So, if later you want to remove certain characters from your
alphabet bar, you will only have to remove those letters from that array.
The third part of the page contains a Gridview that will lists users and some of their properties.
All we need is to specify the number and the type of columns for this grid. Below you will find the description for each column:
For the username, the creation date and last access date we will use BoundField columns. These values for these data will be displayed as strings.
For IsApproved property (read-only) use a CheckBoxField column.
For user's e-mail use a HyperLinkField to show the as an active link that uses the mailto: protocol.
To redirect the administrator to a page called EditUsers.aspx use another HyperLinkField column to show an edit image. This link will have the username
as a querystring value and will allow the administrator to edit a user's profile.
To delete a user use a ButtonField column to create a graphical Delete button. To do this set the column's ButtonType property to "Image"
The code below shows how you should define this grid:
<asp:GridView
ID="gvUsers"
runat="server"
AutoGenerateColumns="false"
DataKeyNames="UserName"
OnRowCreated="gvUsers_RowCreated"
OnRowDeleting="gvUsers_RowDeleting">
<Columns>
<asp:BoundField
HeaderText="UserName"
DataField="UserName"
/>
<asp:HyperLinkField
HeaderText="E-mail"
DataTextField="Email"
DataNavigateUrlFormatString="mailto:{0}"
DataNavigateUrlFields="Email"
/>
<asp:BoundField
HeaderText="Created"
DataField="CreationDate"
DataFormatString="{0:MM/dd/yy
h:mm tt}" />
<asp:BoundField
HeaderText="Last
activity" DataField="LastActivityDate"
DataFormatString="{0:MM/dd/yy
h:mm tt}" />
<asp:CheckBoxField
HeaderText="Approved"
DataField="IsApproved"
HeaderStyle-HorizontalAlign="Center"
ItemStyle-HorizontalAlign="Center"
/>
<asp:HyperLinkField
Text="<img
src='../images/edit.gif' border='0' />"
DataNavigateUrlFormatString="EditUsers.aspx?UserName={0}"
DataNavigateUrlFields="UserName"
/>
<asp:ButtonField
CommandName="Delete"
ButtonType="Image"
ImageUrl="~/images/delete.gif"
/>
</Columns>
<EmptyDataTemplate>No
users found.</EmptyDataTemplate>
</asp:GridView>
If no users were found, you can customize your result with the <EmptyDataTemplate> section. This new feature was introduces only for
ASP.NET 2.0.
In the page's code-behind file there is MemershipUserCollection object. This object is initialized with all the user information returned by
Membership.GetAllUsers static method. In the Load event of this page we will use the Count property of this collection to display the total number of
registered users and also the number of online users. I also created an array that contains letters that will be bound to the Repeater control in order to
create the alphabet.
public
partial class
ManageUsers :
Page
{
private
MembershipUserCollection allRegisteredUsers =
Membership.GetAllUsers();
protected void
Page_Load(object sender,
EventArgs e)
{
if (!this.IsPostBack)
{
lblOnlineUsers.Text = Membership.GetNumberOfUsersOnline().ToString();
lblTotalUsers.Text = allRegisteredUsers.Count.ToString();
string[] alph =
"A;B;C;D;E;F;G;J;K;L;M;N;O;P;Q;R;S;T;U;V;W;X;Y;Z;All".Split(';');
rptAlphabetBar.DataSource = alph;
rptAlphabetBar.DataBind();
}
}
// other methods and event handlers go here...
}
When the administrator will click a letter link, the ItemCommand event of the Repeater control will raise. Here we will retrieve that letter
and search for all users with the name that starts with that letter. When you click the All link, the gridview will show all the users. There are two
search modes: SearchByEmail and SearchByText. Because in this case we will use a "SerachByText" search mode, the "SearchByEmail" mode
is put to false. This search mode is stored in the Attributes collection of the gridview so that it is persisted in the view state, and doesn't get lost
during a postback. Here's the code:
protected
void rptAlphabetBar_ItemCommand(object
source, RepeaterCommandEventArgs e)
{
gvUsers.Attributes.Add("SearchByEmail",
false.ToString());
if (e.CommandArgument.ToString().Length == 1)
{
gvUsers.Attributes.Add("SearchText",
e.CommandArgument.ToString() + "%");
this.BindAllUsers(false);
}
else
{
gvUsers.Attributes.Add("SearchText",
"");
this.BindAllUsers(false);
}
}
In this event the BindAllUsers method is called. The Boolean value that is passed as an input parameter indicates if the allRegisteredUsers collection
must be repopulated (especially when a user is deleted). The text to search for and the search mode are retrieved from the grid's Attributes collection.
Below is the code:
private
void BindAllUsers(bool
reloadAllUsers)
{
MembershipUserCollection allUsers =
null;
if (reloadAllUsers)
allUsers =
Membership.GetAllUsers();
string searchText =
"";
if (!string.IsNullOrEmpty(gvUsers.Attributes["SearchText"]))
searchText =
gvUsers.Attributes["SearchText"];
bool searchByEmail =
false;
if (!string.IsNullOrEmpty(gvUsers.Attributes["SearchByEmail"]))
searchByEmail
= bool.Parse(gvUsers.Attributes["SearchByEmail"]);
if (searchText.Length > 0)
{
if (searchByEmail)
allUsers =
Membership.FindUsersByEmail(searchText);
else
allUsers =
Membership.FindUsersByName(searchText);
}
else
{
allUsers =
allRegisteredUsers;
}
gvUsers.DataSource
= allUsers;
gvUsers.DataBind();
}
This BindAllUsers method is also called when the Search button is clicked. In this case, the search mode will be set according to the value selected
in the ddlUserSearchTypes dropdown list control. If you choose the "SearchText" search mode, to the entered search string will be added at the
beginning and at the end the "%" character, so LIKE query will be performed:
protected
void btnSearch_Click(object
sender, EventArgs e)
{
bool searchByEmail =
(ddlUserSearchTypes.SelectedValue == "E-mail");
gvUsers.Attributes.Add("SearchText",
"%" + txtSearchText.Text +
"%");
gvUsers.Attributes.Add("SearchByEmail",
searchByEmail.ToString());
BindAllUsers(false);
}
If you want to delete a user you have to click the trashcan icon. For this the GridView raises the RowDeleting event because the column's CommandName
property is set to Delete. Inside this event handler you will use the static methods of the Membership and ProfileManager classes to delete the
user account and its accompanying profile. BindAllUser method is called (with true as a parameter), so that the collection of all users is refreshed,
and the new information is displayed:
protected
void gvUsers_RowDeleting(object
sender, GridViewDeleteEventArgs e)
{
string userName =
gvUsers.DataKeys[e.RowIndex].Value.ToString();
ProfileManager.DeleteProfile(userName);
Membership.DeleteUser(userName);
BindAllUsers(true);
lblTotalUsers.Text
= allRegisteredUsers.Count.ToString();
}
If you delete a user you cannot undo this action. This is why you should have the administrator confirm this action before proceeding.
Through the button's OnClientClick property you can add a "confirm" JavaScript in the link's onclick client-side event.
All these can be done in the gridview's RowCreated event to get a reference to each link as soon as its parent row and all its contents are created.
Here's the code:
protected
void gvUsers_RowCreated(object
sender, GridViewRowEventArgs e)
{
if (e.Row.RowType ==
DataControlRowType.DataRow)
{
ImageButton btn = e.Row.Cells[6].Controls[0]
as ImageButton;
btn.OnClientClick = "if (confirm('Are you sure you
want to delete this user?') == false) return false;";
}
}
This script is added only for rows of type DataRow. In this way we will avoid to add this script to the header, footer, and pagination bars.
The UserProfile user control
After registering every user has to fill in some forms with his profile. Due to flexibility I grouped all these forms and controls into a user control.
In this way I can use the same user control in the administration section to edit the profile for a user.
So, the profile proprieties that we configured in web.config file will receive the values from these forms.
Please see below the mark-up code for this user control.
<%@
Control Language="C#"
AutoEventWireup="true"
CodeFile="UserProfile.ascx.cs"
Inherits="UserProfile"
%>
<table
cellpadding="2">
<tr>
<td
width="130">First
name:</td>
<td
width="300">
<asp:TextBox
ID="txtFirstName"
runat="server"
Width="99%"></asp:TextBox>
</td>
</tr>
<tr>
<td
>Last name:</td>
<td>
<asp:TextBox
ID="txtLastName"
runat="server"
Width="99%"
/>
</td>
</tr>
<tr>
<td
>Gender:</td>
<td>
<asp:DropDownList
runat="server"
ID="ddlGenders">
<asp:ListItem
Text="Please select
one..." Value=""
Selected="True"
/>
<asp:ListItem
Text="Male"
Value="M"
/>
<asp:ListItem
Text="Female"
Value="F"
/>
</asp:DropDownList>
</td>
</tr>
<tr>
<td>Birth
date:</td>
<td>
<asp:TextBox
ID="txtBirthDate"
runat="server"
Width="99%"></asp:TextBox>
<asp:CompareValidator
runat="server"
ID="valBirthDateFormat"
ControlToValidate="txtBirthDate"
SetFocusOnError="true"
Display="Dynamic"
Operator="DataTypeCheck"
Type="Date"
ErrorMessage="The format
of the birth date is not valid."
ValidationGroup="EditProfile">
<br
/>The format of the birth date is not valid.
</asp:CompareValidator>
</td>
</tr>
<tr>
<td>Occupation:</td>
<td>
<asp:DropDownList
ID="ddlOccupations"
runat="server"
Width="99%">
<asp:ListItem
Text="Please select
one..." Value=""
Selected="True"
/>
<asp:ListItem
Text="Academic"
/>
<asp:ListItem
Text="Accountant"
/>
<asp:ListItem
Text="Actor"
/>
<asp:ListItem
Text="Architect"
/>
<asp:ListItem
Text="Artist"
/>
<asp:ListItem
Text="Business Manager"
/>
<%-- other
options... --%>
<asp:ListItem
Text="Other"
/>
</asp:DropDownList>
</td>
</tr>
<tr>
<td>Website:</td>
<td>
<asp:TextBox
ID="txtWebsite"
runat="server"
Width="99%"
/>
</td>
</tr>
</table>
<p></p>
<div
>Address</div>
<p></p>
<table
cellpadding="2">
<tr>
<td
width="130"
class="fieldname">Street:</td>
<td
width="300">
<asp:TextBox
runat="server"
ID="txtStreet"
Width="99%"
/>
</td>
</tr>
<tr>
<td>City:</td>
<td><asp:TextBox
runat="server"
ID="txtCity"
Width="99%"
/></td>
</tr>
<tr>
<td>Zip
/ Postal code:</td>
<td><asp:TextBox
runat="server"
ID="txtPostalCode"
Width="99%"
/></td>
</tr>
<tr>
<td>State
/ Region:</td>
<td><asp:TextBox
runat="server"
ID="txtState"
Width="99%"
/></td>
</tr>
</table>
<p></p>
<div
>Other contacts</div>
<p></p>
<table
cellpadding="2">
<tr>
<td
width="130">Phone:</td>
<td
width="300"><asp:TextBox
runat="server"
ID="txtPhone"
Width="99%"
/></td>
</tr>
<tr>
<td>Fax:</td>
<td><asp:TextBox
runat="server"
ID="txtFax"
Width="99%"
/></td>
</tr>
</table>
In the user control's load event the first thing we have to do is to retrieve the profile for the user and to update the forms with these details.
protected
void Page_Load(object
sender, EventArgs e)
{
if (!this.IsPostBack)
{
// if the UserName property contains an emtpy string,
retrieve the profile
// for the current user, otherwise for the specified
user
ProfileCommon
profile = this.Profile;
if (this.UserName.Length
> 0)
profile =
this.Profile.GetProfile(this.UserName);
txtFirstName.Text = profile.FirstName;
txtLastName.Text = profile.LastName;
ddlGenders.SelectedValue = profile.Gender;
if (profile.BirthDate !=
DateTime.MinValue)
txtBirthDate.Text = profile.BirthDate.ToShortDateString();
ddlOccupations.SelectedValue = profile.Occupation;
txtWebsite.Text = profile.Website;
txtStreet.Text
= profile.Address.Street;
txtCity.Text =
profile.Address.City;
txtPostalCode.Text = profile.Address.PostalCode;
txtState.Text
= profile.Address.State;
txtPhone.Text
= profile.Contacts.Phone;
txtFax.Text =
profile.Contacts.Fax;
} }
The most important method is the Save method. It has the purpose to save in the user's profile the values from the forms.
public
void Save()
{
// if the UserName property contains an emtpy string,
save the current user's
// profile, othwerwise save the profile for the
specified user
ProfileCommon
profile = this.Profile;
if (this.UserName.Length
> 0)
profile =
this.Profile.GetProfile(this.UserName);
profile.FirstName
= txtFirstName.Text;
profile.LastName =
txtLastName.Text;
profile.Gender =
ddlGenders.SelectedValue;
if (txtBirthDate.Text.Trim().Length > 0)
profile.BirthDate = DateTime.Parse(txtBirthDate.Text);
profile.Occupation
= ddlOccupations.SelectedValue;
profile.Website =
txtWebsite.Text;
profile.Address.Street = txtStreet.Text;
profile.Address.City = txtCity.Text;
profile.Address.PostalCode = txtPostalCode.Text;
profile.Address.State = txtState.Text;
profile.Contacts.Phone = txtPhone.Text;
profile.Contacts.Fax = txtFax.Text;
profile.Save(); }
It is important that this user control to benefit of the ViewState facility, but we might have problems if we place this
user control in a page that has the ViewState disabled. To resolve this problem we have to use the ControlState facility.
It does mainly the same thing like Viewstate, but the difference is that it will be always enabled no matter of the ViewState
from the web page. To implement the ControlState facility we have to write the code below:
private
string _userName =
"";
public
string UserName
{
get { return
_userName; }
set { _userName = value;
}
}
protected
void Page_Init(object
sender, EventArgs e)
{
this.Page.RegisterRequiresControlState(this);
}
protected
override void
LoadControlState(object savedState)
{
object[] ctlState = (object[])savedState;
base.LoadControlState(ctlState[0]);
_userName = (string)ctlState[1];
}
protected
override object
SaveControlState()
{
object[] ctlState = new
object[2];
ctlState[0] =
base.SaveControlState();
ctlState[1] =
_userName;
return ctlState; }
The EditUsers Administrative Page
You can access the EditUsers.aspx page clicking the edit image for a user in the ManageUsers.aspx grid. The username of that user is passed as a
querystring value. This page allows an administrator to see all the membership details about that user and to edit the user's personal profile.
The user interface of the page is simple and is divided in three parts:
The first part displays the details from MembershipUser. All controls are read-only, except for those that are bound to the IsApproved and IsLockedOut
properties. Through the IsLockedOut property you can unlock a user account.
The second part contains a CheckBoxList that displays all the roles created for this application. Here you can add and remove users to and from roles.
There is also a TextBox control and a button to create a new role.
In the third part you can edit a user's profile with the help of the user control we have created.
Below you can find the mark-up code for the EditUsers.aspx web page:
<%@
Page Language="C#"
AutoEventWireup="true"
CodeFile="EditUsers.aspx.cs"
Inherits="EditUsers"
%>
<%@
Register Src="UserProfile.ascx"
TagName="UserProfile"
TagPrefix="mb"
%>
<html
xmlns="http://www.w3.org/1999/xhtml">
<head
id="Head1"
runat="server">
<title>Untitled
Page</title>
</head>
<body>
<form
id="form1"
runat="server">
<div>General
user information</div>
<p></p>
<table
cellpadding="2">
<tr>
<td
width="130">UserName:</td>
<td
width="300"><asp:Literal
runat="server"
ID="lblUserName"
/></td>
</tr>
<tr>
<td>E-mail
address:</td>
<td><asp:HyperLink
ID="lnkEmailAddress"
runat="server"
/></td>
</tr>
<tr>
<td>Registered:</td>
<td><asp:Literal
ID="lblRegistered"
runat="server"
/></td>
</tr>
<tr>
<td>Last
Login:</td>
<td><asp:Literal
ID="lblLastLogin"
runat="server"
/></td>
</tr>
<tr>
<td>Last
Activity:</td>
<td><asp:Literal
ID="lblLastActivity"
runat="server"
/></td>
</tr>
<tr>
<td>Online
Now:</td>
<td><asp:CheckBox
ID="chkIsOnlineNow"
Enabled="false"
runat="server"
/></td>
</tr>
<tr>
<td>Approved:</td>
<td><asp:CheckBox
ID="chkIsApproved"
AutoPostBack="true"
OnCheckedChanged="chkIsApproved_CheckedChanged"
runat="server"/></td>
</tr>
<tr>
<td>Locked
Out:</td>
<td><asp:CheckBox
ID="chkIsLockedOut"
AutoPostBack="true"
OnCheckedChanged="chkIsLockedOut_CheckedChanged"
runat="server"/></td>
</tr>
</table>
<p></p>
<p></p>
<div>User's
roles</div>
<p></p>
<asp:CheckBoxList
runat="server"
ID="chklRoles"
RepeatColumns="5"
CellSpacing="4"
/>
<table
cellpadding="2"
width="450">
<tr><td
align="right">
<asp:Label
runat="server"
ID="lblRolesOK"
Text="Roles were
successfully updated" Visible="false"
/>
<asp:Button
ID="btnUpdate"
Text="Update"
OnClick="btnUpdate_Click"
runat="server"/>
</td></tr>
<tr><td
align="right">
<small>Create
new role: </small>
<asp:TextBox
ID="txtNewRole"
runat="server"/>
<asp:RequiredFieldValidator
ID="validatorRequireRole"
ControlToValidate="txtNewRole"
SetFocusOnError="true"
ErrorMessage="Role name
is required." ValidationGroup="CreateRole"
runat="server">
</asp:RequiredFieldValidator>
<asp:Button
runat="server"
ID="btnCreate"
Text="Create"
ValidationGroup="CreateRole"
OnClick="btnCreate_Click"
/>
</td></tr>
</table>
<p></p>
<div>Edit
user's profile</div>
<p></p>
<mb:UserProfile
ID="UserProfile1"
runat="server"
/>
<table
cellpadding="2"
width="400">
<tr><td
align="right">
<asp:Label
ID="lblProfileOK"
Text="Profile was
successfully updated" Visible="false"
runat="server"/>
<asp:Button
ID="btnUpdateProfile"
Text="Update"
runat="server"
ValidationGroup="EditProfile"
OnClick="btnUpdateProfile_Click"/>
</td></tr>
</table>
</form>
</body>
</html>
In the Page_Load event handler the username is retrieved from the querystring and a MembershipUser instance is created for that user.
Now, all profile proprieties are shown in the first part of the page:
public
partial class
EditUsers : Page
{
string userName = "";
protected void
Page_Load(object sender,
EventArgs e)
{
// retrieve the username from the querystring
userName =
this.Request.QueryString["UserName"];
lblRolesOK.Visible = false;
lblProfileOK.Visible = false;
if (!this.IsPostBack)
{
UserProfile1.UserName = userName;
MembershipUser user = Membership.GetUser(userName);
lblUserName.Text = user.UserName;
lnkEmailAddress.Text = user.Email;
lnkEmailAddress.NavigateUrl = "mailto:" +
user.Email;
lblRegistered.Text = user.CreationDate.ToString("f");
lblLastLogin.Text = user.LastLoginDate.ToString("f");
lblLastActivity.Text = user.LastActivityDate.ToString("f");
chkIsLockedOut.Checked = user.IsLockedOut;
chkIsLockedOut.Enabled = user.IsLockedOut;
chkIsOnlineNow.Checked = user.IsOnline;
chkIsApproved.Checked = user.IsApproved;
BindRoles();
}
} }
The purpose of the BindRoles method is to fill the CheckBoxList with all the available roles and to check the ones the user belongs to:
private
void BindRoles()
{
chklRoles.DataSource = Roles.GetAllRoles();
chklRoles.DataBind();
foreach (string
role in Roles.GetRolesForUser(userName))
chklRoles.Items.FindByText(role).Selected = true;
}
When the Update Roles button is pressed, the first thing to do is to remove the user from all his roles and after that to add him to the selected ones.
We have to remove the users from all the roles because we will receive an exception if we try to add a user in a role he is already a member of.
Please see the below code:
protected
void btnUpdate_Click(object
sender, EventArgs e)
{
// first remove the user from all roles...
string[] currentRoles =
Roles.GetRolesForUser(userName);
if (currentRoles.Length > 0)
Roles.RemoveUserFromRoles(userName, currentRoles);
// and then add the user to the selected roles
List<string>
newRoles = new List<string>();
foreach (ListItem item
in chklRoles.Items)
{
if (item.Selected)
newRoles.Add(item.Text);
}
Roles.AddUserToRoles(userName, newRoles.ToArray());
lblRolesOK.Visible
= true; }
As you see, we used Roles.AddUserToRoles method instead of the Roles.AddUserToRole method. For this we created first a list with all the new roles
the user will belong.
Below you can find the code for creating a new role. First we check to see if there is a role with the same name. If there isn't, we can create it.
The BindRoles method is called to refresh the list of available roles:
protected
void btnCreate_Click(object
sender, EventArgs e) {
if (!Roles.RoleExists(txtNewRole.Text.Trim()))
{
Roles.CreateRole(txtNewRole.Text.Trim());
BindRoles();
} }
When the Approved checkbox is clicked, the event handler updates the MembershipUser object's IsApproved property according to the checkbox's value,
and then save the change:
protected
void chkIsApproved_CheckedChanged(object
sender, EventArgs e) {
MembershipUser
user = Membership.GetUser(userName);
user.IsApproved =
chkIsApproved.Checked;
Membership.UpdateUser(user); }
You can unlock a user in the same way. For this we will use the UnlockUser method of the MembershipUser object. After that, the checkbox is made
read-only because you can't lock out a user. Please see the below code:
protected
void chkIsLockedOut_CheckedChanged(object
sender, EventArgs e) {
if (!chkIsLockedOut.Checked)
{
MembershipUser
user = Membership.GetUser(userName);
user.UnlockUser();
chkIsLockedOut.Enabled = false;
} }
When the profile box's Update button is clicked, a call to the UserProfile's Save method is made and the user’s profile is updated:
protected
void btnUpdateProfile_Click(object
sender, EventArgs e)
{
UserProfile1.Save();
lblProfileOK.Visible = true; }
This tutorial is written by
Adrian Tarjoianu.
Tutorial toolbar: Tell A Friend | Add to favorites | Feedback |
|