Wednesday, April 16, 2008

Sending an Activation Email with ASP.NET 2.0 Expanded

I had a request to show an example that would build on my original "Sending an Activation Email with ASP.NET 2.0" to provide a user with a link to log them in. What follows shows how you can place a link on the final Account Details page that when clicked will take the user to a Login page with their username already pre-filled for them.

Activate.aspx

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Activate.aspx.cs" Inherits="Activate" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Activation Page</title>
</head>
<body>
<form id="form1" runat="server">
<br />
<asp:Table ID="Table1" runat="server" CellPadding="1" CellSpacing="0" GridLines="Both" BorderStyle="Groove" BackColor="BlanchedAlmond" Caption="Account Information">
<asp:TableRow>
<asp:TableCell HorizontalAlign="Right" runat="server">Username:</asp:TableCell>
<asp:TableCell HorizontalAlign="Left" runat="server"><asp:Label ID="ActiviationNameLabel" runat="server" Style="position: static"></asp:Label></asp:TableCell>
</asp:TableRow>
<asp:TableRow>
<asp:TableCell HorizontalAlign="Right" runat="server">Account Created:</asp:TableCell>
<asp:TableCell HorizontalAlign="Left" runat="server"><asp:Label ID="ActivationCreationDateLabel" runat="server" Style="position: static"></asp:Label></asp:TableCell>
</asp:TableRow>
<asp:TableRow>
<asp:TableCell HorizontalAlign="Right" runat="server">Account Status:</asp:TableCell>
<asp:TableCell HorizontalAlign="Left" runat="server"><asp:Label ID="ActivationStatusLabel" runat="server" style="position: static"></asp:Label></asp:TableCell>
</asp:TableRow>
<asp:TableRow>
<asp:TableCell HorizontalAlign="Right" runat="server">
<br />
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Login.aspx">Goto Login Page</asp:HyperLink>
</asp:TableCell>
</asp:TableRow>
</asp:Table>
</form>
</body>
</html>
Activate.aspx.cs

This updated code stores the username in a Session variable, so that it can be used to populate the Username field of the Login Control.

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string userID = Request.QueryString["ID"];
Guid gd = new Guid(userID);
MembershipUser user = Membership.GetUser(gd);
user.IsApproved = true;
Roles.AddUserToRole(user.ToString(), "Power Users");
Membership.UpdateUser(user);
ActiviationNameLabel.Text = user.UserName;
ActivationCreationDateLabel.Text = user.CreationDate.ToShortDateString();
if (user.IsApproved)
{
ActivationStatusLabel.Text = "Active";
}
else
{
ActivationStatusLabel.Text = "Pending";
}

Session["UserName"] = user.UserName;
}
}
Login.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Login Page</title>
</head>
<body>
<form id="form1" runat="server">
<div style="text-align: center">
<asp:Login ID="Login1" runat="server" BackColor="#F7F6F3" BorderColor="#E6E2D8" BorderPadding="4" BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana" Font-Size="0.8em" ForeColor="#333333" DestinationPageUrl="~/Main.aspx">
<TextBoxStyle Font-Size="0.8em" />
<LoginButtonStyle BackColor="#FFFBFF" BorderColor="#CCCCCC" BorderStyle="Solid" BorderWidth="1px"
Font-Names="Verdana" Font-Size="0.8em" ForeColor="#284775" />
<InstructionTextStyle Font-Italic="True" ForeColor="Black" />
<TitleTextStyle BackColor="#5D7B9D" Font-Bold="True" Font-Size="0.9em" ForeColor="White" />
</asp:Login>
</div>
</form>
</body>
</html>
Login.aspx.cs

This simple Login page retrieves the user's Username from the session and assigns it to the Login controls UserName TextBox. It first checks to see if the session variable is null or empty if it is then the Login Control's UserName TextBox is left blank.

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
if (!(String.IsNullOrEmpty((string)Session["UserName"])))
{
string username = Session["UserName"].ToString();
Login1.UserName = username;
}
else
{
Login1.UserName = string.Empty;
}
}
}
Main.aspx
Upon successful login the user is redirected to a simple welcome page called Main.aspx.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Main.aspx.cs" Inherits="Main" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Main Website Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LoginView ID="LoginView1" runat="server">
<LoggedInTemplate>
Welcome
<asp:LoginName ID="LoginName1" runat="server" />
!<br />
<br />
<asp:LoginStatus ID="LoginStatus1" runat="server" LogoutAction="RedirectToLoginPage"
LogoutPageUrl="~/Login.aspx" />
</LoggedInTemplate>
</asp:LoginView>
&nbsp;</div>
</form>
</body>
</html>




Tuesday, February 26, 2008

Sending an Activation Email with ASP.NET 2.0

Many sites as you've seen send out an email that contains a link to activate your account after you've filled out all requested information. This is primarily seen on Web Forum sites and other sites that require a membership. I'm going to show a quick example of how to do this using ASP.NET and sending the email via Gmail or some other SMTP server such as your hosting company's smtp server. It is assumed that you have already configured your ASPNETDB with Membership and Roles. This is just a basic email activation you can expand upon it and add other features you might want.

Start by dropping a standard CreateUserWizard Control on a page. I've dropped the control on a page called Default.aspx. You can format it later with any of the available Format templates Microsoft has provided or customize it using CSS if you like.

Below is the code-behind for the Default.aspx page. This code essentially grabs the Username, Password, and Email address that was entered through the CreateUserWizard Control puts the information into a StringBuilder object along with a link to the Activate.aspx page. The UserID is a Guid value that is appended to the Activate URL as a query string.

Using a conditional you can select to send the emails via your Hosting Companies SMTP server, a local SMTP server, or a Gmail account.

#define Gmail
#define SMTP

using System;
using System.Data;
using System.Configuration;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{

protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
{
StringBuilder bodyMsg = new StringBuilder();
TextBox username = (TextBox)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("UserName");
TextBox password = (TextBox)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("Password");
TextBox email = (TextBox)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("Email");

CreateUserWizard cuw = (CreateUserWizard)sender;
MembershipUser user = Membership.GetUser(cuw.UserName);
Guid userID = (Guid)user.ProviderUserKey;

bodyMsg.Append("Thank you for creating your account.\n\nPlease follow this link to activate: ");
bodyMsg.Append("<br /><br /><a href=http://yourserver/SendEmailConfirmationSample/Activate.aspx?ID=" + userID.ToString() + ">Activate Your Account</a>");
bodyMsg.Append("<br />");
bodyMsg.Append("<br />");
bodyMsg.AppendFormat("UserName: {0}", username.Text);
bodyMsg.Append("<br />");
bodyMsg.AppendFormat("Password: {0}", password.Text);
bodyMsg.Append("<br />");
bodyMsg.AppendFormat("Registered Email: {0}", email.Text);

#if SMTP
// Sending email via local or web hosts smtp server.
NetworkCredential loginInfo = new NetworkCredential("yourusername", "yourpassword");
MailMessage msg = new MailMessage();
msg.From = new MailAddress("youremailaddress");
msg.To.Add(new MailAddress(CreateUserWizard1.Email));
msg.Subject = "Account Information";
msg.Body = bodyMsg.ToString();
msg.IsBodyHtml = true;

SmtpClient client = new SmtpClient("smtpserver", 25);
client.Credentials = loginInfo;
client.Send(msg);
#endif

#if Gmail
// Sending email via Gmail.
NetworkCredential loginInfo = new NetworkCredential("yourUsername@gmail.com", "yourGmailPassword");
MailMessage msg = new MailMessage();
msg.From = new MailAddress("yourUsername@gmail.com");
msg.To.Add(new MailAddress(CreateUserWizard1.Email));
msg.Subject = "Account Information";
msg.Body = bodyMsg.ToString();
msg.IsBodyHtml = true;

SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = loginInfo;
client.Send(msg);
#endif

Response.Redirect("~/thankyoupage.aspx");
}
}


Signing Up For A New Account.



The Confirmation email that is sent.



Here you can see the email that I received in my Gmail Inbox.



Here are the contents of the email that was sent.



The Activate.aspx page's code behind gets the ID that was passed in the query string and uses it to link the user to the account that was created, as well as adds the user to the Power Users Role in ASPNETDB. The page then displays the Username, Date the account was created, and the Status of the user's account.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Activate.aspx.cs" Inherits="Activate" %>



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">



<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Activation Page</title>

</head>

<body>

<form id="form1" runat="server">

<br />

<asp:Table ID="Table1" runat="server" CellPadding="1" CellSpacing="0" GridLines="Both" BorderStyle="Groove" BackColor="BlanchedAlmond" Caption="Account Information">

<asp:TableRow runat="server">

<asp:TableCell HorizontalAlign="Right" runat="server">Username:</asp:TableCell>

<asp:TableCell HorizontalAlign="Left" runat="server"><asp:Label ID="ActiviationNameLabel" runat="server" Style="position: static"></asp:Label></asp:TableCell>

</asp:TableRow>

<asp:TableRow runat="server">

<asp:TableCell HorizontalAlign="Right" runat="server">Account Created:</asp:TableCell>

<asp:TableCell HorizontalAlign="Left" runat="server"><asp:Label ID="ActivationCreationDateLabel" runat="server" Style="position: static"></asp:Label></asp:TableCell>

</asp:TableRow>

<asp:TableRow runat="server">

<asp:TableCell HorizontalAlign="Right" runat="server">Account Status:</asp:TableCell>

<asp:TableCell HorizontalAlign="Left" runat="server"><asp:Label ID="ActivationStatusLabel" runat="server" style="position: static"></asp:Label></asp:TableCell>

</asp:TableRow>

</asp:Table>

</form>

</body>

</html>


using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;



public partial class Activate : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

if (!Page.IsPostBack)

{

string userID = Request.QueryString["ID"];

Guid gd = new Guid(userID);

MembershipUser user = Membership.GetUser(gd);

user.IsApproved = true;

Roles.AddUserToRole(user.ToString(), "Power Users");

Membership.UpdateUser(user);



ActiviationNameLabel.Text = user.UserName;

ActivationCreationDateLabel.Text = user.CreationDate.ToShortDateString();

if (user.IsApproved)

{

ActivationStatusLabel.Text = "Active";

}

else

{

ActivationStatusLabel.Text = "Pending";

}

}

}

}

Here are the final Account Details from the Activate.aspx screen.

Monday, January 28, 2008

How-To Auto Collapse Microsoft AJAX Collapsible Panel

Here's a quick tip on how to automatically collapse a Collapsible Panel through code. This is useful in a situation such as having a Collapsible Panel that contains a few controls used in data entry and once the user has entered the data and clicked on a button to submit their data you want the panel to collapse automatically.

You would think that just performing a (control name) CollapsiblePanelExtender1.collapse = True would collapse the panel; however, this will not work by itself. This is due to the fact that there is a short delay between the first rendering of the page and the running of the Javascript to modify it. To have the panel collapse you will need to add one more line, so your code will look like this.

CollapsiblePanelExtender1.Collapsed = True;
CollapsiblePanelExtender1.ClientState = "true";
You can also prevent the PopControlExtender from briefly showing controls it contains by placing the controls within a Panel Control and setting the Panel Control's visibility style to hidden. This will stop the annoying flickering that happens when the page is first rendered.

Thursday, January 10, 2008

Cheat Sheets

A co-worker gave me this very useful cheat-sheet resource.

Enjoy!

http://www.ilovejackdaniels.com/cheat-sheets/

Monday, December 31, 2007

Maintaining Control Values Between Pages

Here is a quick example of how you can maintain the values of controls when switching back and forth between different web pages by making use of Session variables. You can use ASP.NET Session variables to pass the values from one web page to another, but if you need to return to the previous page via a button for example the web page will loose the previous values it had. You can maintain those values just as if you had clicked your browser's back button by using Session variables.

Below is a short example that demonstrates this.

Default.aspx
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="FNLabel" runat="server" Text="First Name"></asp:Label>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
<asp:Label ID="LNLabel" runat="server" Text="Last Name"></asp:Label><br />
<asp:TextBox ID="FNTextBox" runat="server"></asp:TextBox>
<asp:TextBox ID="LNTextBox" runat="server"></asp:TextBox>&nbsp;<br />
<br />
<asp:DropDownList ID="IncomeDropDownList" runat="server" AutoPostBack="True">
<asp:ListItem>10K -30K</asp:ListItem>
<asp:ListItem>31K - 50K</asp:ListItem>
<asp:ListItem>51K - 70K</asp:ListItem>
<asp:ListItem>71K - 90K</asp:ListItem>
<asp:ListItem>91K+</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:RadioButtonList ID="ResidenceRadioButtonList" runat="server" AutoPostBack="True">
<asp:ListItem>Apartment</asp:ListItem>
<asp:ListItem>Mobile Home</asp:ListItem>
<asp:ListItem>Townhouse</asp:ListItem>
<asp:ListItem>Single Family House</asp:ListItem>
</asp:RadioButtonList><br />
<asp:Calendar ID="AcctStartCalendar" runat="server" BackColor="White" BorderColor="#999999" CellPadding="4" DayNameFormat="Shortest" Font-Names="Verdana" Font-Size="8pt" ForeColor="Black" Height="180px" Width="200px">
<SelectedDayStyle BackColor="Green" Font-Bold="True" ForeColor="White" />
<TodayDayStyle BackColor="#CCCCCC" ForeColor="Black" />
<SelectorStyle BackColor="#CCCCCC" />
<WeekendDayStyle BackColor="#FFFFCC" />
<OtherMonthDayStyle ForeColor="#808080" />
<NextPrevStyle VerticalAlign="Bottom" />
<DayHeaderStyle BackColor="#CCCCCC" Font-Bold="True" Font-Size="7pt" />
<TitleStyle BackColor="#999999" BorderColor="Black" Font-Bold="True" />
</asp:Calendar>
<br />
<asp:Button ID="SubmitButton"
runat="server" OnClick="Button1_Click" Text="Submit" /></div>
<br />
</form>
</body>
</html>
Default.aspx.cs
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
LoadExistingValues();
}
protected void Button1_Click(object sender, EventArgs e)
{
Session["value1"] = FNTextBox.Text;
Session["value2"] = LNTextBox.Text;
Session["value3"] = IncomeDropDownList.SelectedValue;
Session["value4"] = ResidenceRadioButtonList.SelectedValue;
Session["value5"] = AcctStartCalendar.SelectedDate;

Response.Redirect("~/Page2.aspx");
}

private void LoadExistingValues()
{
if (!Page.IsPostBack)
{
if (Session["value1"] != null)
{
FNTextBox.Text = Session["value1"].ToString();
LNTextBox.Text = Session["value2"].ToString();
IncomeDropDownList.SelectedValue = Session["value3"].ToString();
ResidenceRadioButtonList.SelectedValue = Session["value4"].ToString();

AcctStartCalendar.SelectedDate = Convert.ToDateTime((Session["value5"]));
}
}
}
}
Page2.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Page2.aspx.cs" Inherits="Page2" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="FNLabel" runat="server"></asp:Label>,
<asp:Label ID="LNLabel" runat="server"></asp:Label><br />
<br />
<asp:Label ID="IncomeLabel" runat="server"></asp:Label>
<br />
<asp:Label ID="ResidenceLabel" runat="server"></asp:Label><br />
<br />
<asp:Calendar ID="AcctSelectionCalendar" runat="server"></asp:Calendar>
<br />
<br />
&nbsp;
<asp:Button ID="PreButton" runat="server" OnClick="Button1_Click" Text="Return to previous page" /></div>
</form>
</body>
</html>
Page2.aspx.cs
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Page2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
FNLabel.Text = (Session["value1"]).ToString();
LNLabel.Text = (Session["value2"]).ToString();
IncomeLabel.Text = (Session["value3"]).ToString();
ResidenceLabel.Text = (Session["value4"]).ToString();
AcctSelectionCalendar.SelectedDate = Convert.ToDateTime((Session["value5"]));

}
protected void Button1_Click(object sender, EventArgs e)
{
Response.Redirect("~/Default.aspx", true);
}
}
This little example should show you how easy it is to maintain the values of controls when navigating back and forth between pages. I have not experimented extensively with other controls, so further tweaking may be required.



Wednesday, December 12, 2007

Running ASP.NET 2.0 in Integrated Mode on IIS 7

I just wanted to share this blog link that discusses the changes you'll need to be aware of when you running your ASP.NET 2.0 applications in Integrated Mode on IIS 7 on Vista or Windows Server 2008.

http://mvolo.com/blogs/serverside/archive/2007/12/08/IIS-7.0-Breaking-Changes-ASP.NET-2.0-applications-Integrated-mode.aspx

Friday, October 26, 2007

.NET Daily Tips

I stumbled across this website and thought I'd share it with everyone. Visit this site frequently for some little known tips you might not have ever known about regarding .NET

http://dotnettipoftheday.org/tips/