Hi,

I would like to know the idea behind one issue. In some sites, when you register using your email id, an automatically generated email is receieved in your inbox, which contains a link that you must click to activate your membership. How is this done? Can anyone help me out.

Prashanth

Recommended Answers

All 8 Replies

I've never actually done it for a website, so you may want to take this with a grain of salt.

The concept is that as a user is added to the 'database' of users, you generate a random 'validation value' that is also stored with the user. You then generate an SMTP messsage (assuming your web host will let you) which sends the user's registered email address a message which identifies the user that is registering and includes a link to another page on your website. The link includes at least 2 pieces of information, one should be enough to 'find' the user in the database again, the second is the previously randomly generated validation value.

The web page that you link to will look at the parameter data, find the user record and confirm that the validation string matches. If it does, someone who can read messages sent to that email address agreed that the registration was valid, so you mark the record as having a valid email address.

Is that what you were looking for or did you want something more specific?

Well fundamentally yes, that is what I am looking for. But I am afraid I dont know how the part about the SMTP works??

moreover, when you say you havent actually tried for a website, what do you mean. have you tried it for any application created in visual studio?

Also, can you tell me if something like this can be done using visual studio

I have done that for a password reset but conceptually it is the same thing for signing up. In this case the site is an internal project so I actually send the email when you click the "Submit" button but you should insert a record in to an SQL database for a mail queue in case the mail send fails so you can retry it later. In my case its for devs and other tech savvy people so if the mail fails they need to get up and fix the exchange server :P

This code example has miles of dependant abstraction classes I use so it won't compile as-is but it should be enough to see how you can go about doing it.
You could also have an error if the calls to NewGuid(), by chance, make a duplicate password reset URL. This is a rarely used feature for this particular site so I ignored it. In order for the code to fail three consecutive calls to NewGuid() must generate the same URL within a 24 hour period. I wasn't really worried about this.

The page:

private void SendEmail()
    {
      if (string.IsNullOrEmpty(TextBoxEmail.Text))
      {
        return;
      }

      try
      {
        MailAddress To = new MailAddress(TextBoxEmail.Text);
      }
      catch
      {
        CustomValidatorEmail.IsValid = false;
        CustomValidatorEmail.ErrorMessage = "Invalid email address. You must use the format mailbox@domain.com";
        return;
      }

      PasswordReset reset = PasswordReset.NewResetRequest(Request.UserHostAddress, TextBoxEmail.Text);
      if (reset == null)
      {
        CustomValidatorEmail.IsValid = false;
        CustomValidatorEmail.ErrorMessage = "Account not found.";
        return;
      }


      string URL = "https://" + WebConfigurationVariables.SiteName + Pages.GetURLPasswordReset(PageNames.Members_PasswordRecovery, reset.RequestString);

      using (MailMessage msg = new MailMessage())
      {
        msg.From = new MailAddress("community@webapp.com", "Password Reset");
        msg.To.Add(new MailAddress(reset.Account.Email, reset.Account.NameFirst + " " + reset.Account.NameLast));
        msg.Subject = "Password Recovery";
        string sHTML = Server.MapPath(@"~/App_Data/ResetPassword_HTML.txt");
        string sTxt = Server.MapPath(@"~/App_Data/ResetPassword_TXT.txt");
        MemoryStream msHTML = null;
        AlternateView viewHTML = null, viewTXT = null;

        try
        {
          Hashtable templateVars = new Hashtable();
          templateVars.Add("FIRSTNAME", reset.Account.NameFirst);
          templateVars.Add("URL", URL);
          templateVars.Add("SITENAME", WebConfigurationVariables.SiteName);
          Parser parser = new Parser(sHTML, templateVars);
          msHTML = new MemoryStream(ASCIIEncoding.ASCII.GetBytes(parser.Parse()));
          msHTML.Position = 0;
          msHTML.Seek(0, SeekOrigin.Begin);


          viewHTML = new AlternateView(msHTML, "text/html");
          viewHTML.TransferEncoding = TransferEncoding.QuotedPrintable;
          msg.AlternateViews.Add(viewHTML);

          viewTXT = AlternateView.CreateAlternateViewFromString(
            File.ReadAllText(sTxt).Replace(@"##FIRSTNAME##", reset.Account.NameFirst).Replace(@"##URL##", URL).Replace(@"##SITENAME##", WebConfigurationVariables.SiteName),
            new ContentType("text/plain"));
          viewTXT.TransferEncoding = TransferEncoding.QuotedPrintable;
          msg.AlternateViews.Add(viewTXT);
          
          SmtpClient smtp = SMTPHelper.GetSmtpClient();
          
          smtp.Send(msg);
          reset.EmailSent = true;
          reset.Save();
          Response.Redirect(Pages.GetURL(PageNames.Members_ForgotPassword) + "?sent=true");
        }
        finally
        {
          if (msHTML != null)
          {
            msHTML.Close();
            msHTML.Dispose();
          }
          if (viewHTML != null)
            viewHTML.Dispose();
          if (viewTXT != null)
            viewTXT.Dispose();
        }
      }
    }

The PasswordReset class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using WebApp.Common.AcctProf;
using WebApp.Common;
using WebApp.Extensions;
using WebApp.Data;

namespace WebApp.Common
{
  /// <summary>
  /// This class handles the password reset URL generation
  /// </summary>
  [DBTableInfo("PasswordReset")]
  public sealed class PasswordReset : SqlObject
  {
    /// <summary>
    /// Number of days a reset request is valid for, before it expires
    /// </summary>
    public const int DaysValidFor = 1;
    /* -------------------------------------------------------------------- */
    private AcctInfo _acct;
    /* -------------------------------------------------------------------- */
    [DBFieldInfo("PasswordResetId", SqlDbType.Int, Identity = true, PrimaryKey = true)]
    private int _passwordResetId;
    [DBFieldInfo("RequestIP", SqlDbType.VarChar, Size = DataLength.RequestIP)]
    private string _requestIP;
    [DBFieldInfo("RequestDate", SqlDbType.DateTime)]
    private DateTime _requestDate;
    [DBFieldInfo("RequestString", SqlDbType.VarChar, Size = DataLength.RequestString, Unique = true)]
    private string _requestString;
    [DBFieldInfo("Email", SqlDbType.VarChar, Size = DataLength.Email)]
    private string _email;
    [DBFieldInfo("AcctId", SqlDbType.Int)]
    private int _acctId;
    [DBFieldInfo("ResetIP", SqlDbType.VarChar, Size = DataLength.ResetIP)]
    private string _resetIP;
    [DBFieldInfo("ResetDate", SqlDbType.DateTime)]
    private DateTime _resetDate;
    [DBFieldInfo("Successful", SqlDbType.Bit)]
    private bool _successful;
    [DBFieldInfo("EmailSent", SqlDbType.Bit)]
    private bool _emailSent;
    /* -------------------------------------------------------------------- */
    /// <summary>
    /// Identity column for the password reset
    /// </summary>
    public int PasswordResetId
    {
      get { return _passwordResetId; }
      //set { _passwordResetId = value; }
    }
    /// <summary>
    /// IP Address of the person requesting an email be sent
    /// </summary>
    public string RequestIP
    {
      get { return _requestIP; }
      //set { _requestIP = value; }
    }
    /// <summary>
    /// Date the password reset email was sent
    /// </summary>
    public DateTime RequestDate
    {
      get { return _requestDate; }
      //set { _requestDate = value; }
    }
    /// <summary>
    /// The URL parameter value for the password reset
    /// </summary>
    public string RequestString
    {
      get { return _requestString; }
      //set { _requestString = value; }
    }
    /// <summary>
    /// The E-Mail address on the account requesting the reset
    /// </summary>
    public string Email
    {
      get { return _email; }
      //set { _email = value; }
    }
    /// <summary>
    /// Account id the reset was requested for
    /// </summary>
    public int AcctId
    {
      get { return _acctId; }
      //set { _acctId = value; }
    }
    /// <summary>
    /// The IP address that clicked the link in the email sent
    /// </summary>
    public string ResetIP
    {
      get { return _resetIP; }
      //set { _resetIP = value; }
    }
    /// <summary>
    /// The date the password was sucessfully reset
    /// </summary>
    public DateTime ResetDate
    {
      get { return _resetDate; }
      //set { _resetDate = value; }
    }
    /// <summary>
    /// True if the password was reset, marking the request as historical only.
    /// </summary>
    public bool Successful
    {
      get { return _successful; }
      //set { _successful = value; }
    }
    /// <summary>
    /// Indicates if the email was sent. Set false if an exception was thrown.
    /// </summary>
    public bool EmailSent
    {
      get { return _emailSent; }
      set { _emailSent = value; }
    }
    public AcctInfo Account
    {
      get
      {
        if ((_acct == null) && (_acctId > 0))
        {
          AcctInfo acct = new AcctInfo();
          if (acct.Fetch(_acctId))
            _acct = acct;
        }
        return _acct;
      }
    }
    /* -------------------------------------------------------------------- */
    private PasswordReset()
    {
      _passwordResetId = default(int);
    }
    /* -------------------------------------------------------------------- */
    /// <summary>
    /// Generates a password reset request if needed.
    /// Returns NULL if the email was not found.
    /// </summary>
    /// <param name="IP">IP Address of client requesting the reset</param>
    /// <param name="Email">E-Mail address of the account</param>
    /// <returns></returns>
    public static PasswordReset NewResetRequest(string IP, string Email)
    {
      AcctInfo acct = AcctInfo.Fetch(Email);
      if (acct == null) //the account was not found
        return null; 

      PasswordReset result = GetPendingRequest(Email);
      if (result != null) 
      {
        return result; //they have a pending request, just re-use it.
      }
      else
      {
        result = new PasswordReset();
        result._requestIP = IP;
        result._email = Email;
        result._acctId = acct.AcctId;
        result._requestDate = DateTime.Now;
        result._requestString = (Guid.NewGuid().ToString() + Guid.NewGuid().ToString() + Guid.NewGuid().ToString()).Replace("-", string.Empty);
        
        if (result._requestString.Length != DataLength.RequestString)
          throw new InvalidOperationException("Error creating request string");
        
        result.Save();
        return result;
      }
    }
    /* -------------------------------------------------------------------- */
    /// <summary>
    /// Looks up a pending request. Returns null
    /// </summary>
    /// <param name="RequestString"></param>
    /// <returns></returns>
    public static PasswordReset LookupPendingRequestString(string RequestString)
    {
      if (string.IsNullOrEmpty(RequestString))
        RequestString = string.Empty;

      List<string> Sql = new List<string>();
      Sql.Add("Declare @dt DateTime");
      Sql.Add("Set @dt = GetDate()-@ValidFor");
      Sql.Add("Select *");
      Sql.Add("From PasswordReset (NOLOCK)");
      Sql.Add("Where RequestDate >= @dt and (Successful is null or Successful = 0) and");
      Sql.Add("Cast(RequestString as varbinary) = Cast(@RequestString as varbinary)"); //case sensitive lookup
      string query = Sql.GetText();
      List<DataParameter> lst = new List<DataParameter>();
      lst.Add(new DataParameter("@RequestString", SqlDbType.VarChar, RequestString));
      lst.Add(new DataParameter("@ValidFor", SqlDbType.Int, DaysValidFor));
      using (DataTable dt = SQL.Main.QueryDataTable(query, lst))
      {
        if (dt.Rows.Count > 0)
        {
          PasswordReset result = new PasswordReset();
          result.Deserialize(dt);
          result.LoadCustomData();
          if (result.Account == null)
            return null; //the account has been deleted
          else
            return result;
        }
      }
      return null;
    }
    /* -------------------------------------------------------------------- */
    /// <summary>
    /// Gets any pending requests for the user in the period allowed.
    /// Returns NULL if one cannot be found.
    /// </summary>
    /// <param name="Email">Email Address requesting a reset</param>
    /// <returns></returns>
    private static PasswordReset GetPendingRequest(string Email)
    {
      List<string> Sql = new List<string>();
      Sql.Add("Declare @dt DateTime");
      Sql.Add("Set @dt = GetDate()-@ValidFor");
      Sql.Add("Select *");
      Sql.Add("From PasswordReset (NOLOCK)");
      Sql.Add("Where RequestDate >= @dt and (Successful is null or Successful = 0) and Email = @Email");
      string query = Sql.GetText();
      List<DataParameter> lst = new List<DataParameter>();
      lst.Add(new DataParameter("@Email", SqlDbType.VarChar, Email));
      lst.Add(new DataParameter("@ValidFor", SqlDbType.Int, DaysValidFor));
      using (DataTable dt = SQL.Main.QueryDataTable(query, lst))
      {
        if (dt.Rows.Count > 0) //it should only ever be *1*
        {
          PasswordReset result = new PasswordReset();
          result.Deserialize(dt);
          return result;
        }
      }
      return null;
    }
    /* -------------------------------------------------------------------- */
    /// <summary>
    /// Resets the password for the account
    /// </summary>
    /// <param name="IP">IP Address of the client</param>
    /// <param name="NewPassword">New Password for the account</param>
    public void ResetPassword(string IP, string NewPassword)
    {
      if (this.Account == null) //the account has been deleted
        return;

      this.Account.Password = NewPassword;
      this.Account.Save();
      _resetIP = IP;
      _resetDate = DateTime.Now;
      _successful = true;
      this.Save();
    }
    /* -------------------------------------------------------------------- */
    public static class DataLength
    {
      public const int RequestIP = 15;
      public const int RequestString = 96;
      public const int Email = 150;
      public const int ResetIP = 15;
    }
    /* -------------------------------------------------------------------- */
  }
}

The page they land on from the email:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WebApp.Common;
using WebApp.Common.AcctProf;

namespace WebApp.Web.members
{
  public partial class PasswordRecovery : SecurePage
  {
    /* -------------------------------------------------------------------- */
    internal override string PageTitle { get { return @"{0} - Password Recovery"; } }
    internal override string MetaKeywords { get { return string.Empty; } }
    internal override string MetaDescription { get { return string.Empty; } }
    private PasswordReset reset = null;
    /* -------------------------------------------------------------------- */
    protected void Page_Load(object sender, EventArgs e)
    {
      //Log them out if they're on this page for any reason
      DoLogout();

      this.Form.DefaultButton = ButtonSubmit.UniqueID;
      this.Form.DefaultFocus = TextBoxPassword.ClientID;

      string reqStr = Convert.ToString(Request.QueryString["account"]);

      if (Request.QueryString["changed"] == "true")
      {
        panelInvalid.Visible = false;
        panelSubmit.Visible = false;
        panelPasswordUpdated.Visible = true;
        return;
      }

      if (string.IsNullOrEmpty(reqStr))
      {
        Response.Redirect(Pages.GetURL(PageNames.Members_ForgotPassword));
        return;
      }
      
      reset = PasswordReset.LookupPendingRequestString(reqStr);
      if (reset == null)
      {
        panelInvalid.Visible = true;
        panelSubmit.Visible = false;
        panelPasswordUpdated.Visible = false;
      }
      else
      {
        panelInvalid.Visible = false;
        panelSubmit.Visible = true;
        panelPasswordUpdated.Visible = false;
      }
    }
    /* -------------------------------------------------------------------- */
    protected void ButtonSubmit_Click(object sender, EventArgs e)
    {
      if (IsValid)
      {
        if (AcctInfo.IsStrongPassword(TextBoxPassword.Text))
        {
          CustomValidatorPassword.IsValid = true;
        }
        else
        {
          CustomValidatorPassword.IsValid = false;
        }
      }

      if (IsValid)
      {
        reset.ResetPassword(Request.UserHostAddress, TextBoxPassword.Text);
        Response.Redirect(Pages.GetURL(PageNames.Members_PasswordRecovery) + "?changed=true");
      }
    }
    /* -------------------------------------------------------------------- */
  }
}

SMTPHelper :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Mail;
using System.Net;
using System.Net.Mime;

namespace WebApp.Web.Code.Mail
{
  public static class SMTPHelper
  {
    /// <summary>
    /// Gets an SMTP client configured from the web.config variables
    /// </summary>
    /// <returns></returns>
    public static SmtpClient GetSmtpClient()
    {
      SmtpClient smtp = new SmtpClient(WebConfigurationVariables.SMTPServer);
      if (WebConfigurationVariables.SMTPUseAuth)
      {
        smtp.Credentials = new NetworkCredential(WebConfigurationVariables.SMTPUsername, WebConfigurationVariables.SMTPPassword);
      }
      return smtp;
    }
  }
}

Emails can have alternative views for plain-text and HTML. I send both out to be friendly to all clients.

HTML Email:

<html>
<head>
<style>
p {
  font-family: Verdana, Arial, Helvetica, sans-serif;
  font-size: 12px;
}
.SmallFont {
  font-size: 10px;
}
</style>
</head>
<body>
<p>Hello ##FIRSTNAME##</p>
<p>To reset your password click <a href="##URL##" title="Reset Password">here</a>, or copy this link in to your browser:</p>
<p class="SmallFont">##URL##</p>
<br />
<br />
<p>This link will expire in 24 hours.</p>
<p>WebApp<br />
<a href="http://www.webapp.com/">http://www.webapp.com</a></p>
</body>

Text email:

Hello ##FIRSTNAME##,

To reset your password please copy this link in to your browser and follow the instructions:
##URL##


This link will expire in 24 hours.

Web App team
http://www.webapp.com/

The template class for creating an HTML email. I got this code off codeproject or somewhere.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Collections;

namespace WebApp.Web.Code.Mail
{
  public sealed class Parser
  {
    private string _strTemplateBlock;
    private Hashtable _hstValues;
    private Hashtable _ErrorMessage = new Hashtable();
    private string _ParsedBlock;

    private Dictionary<string, Parser> _Blocks = new Dictionary<string, Parser>();

    private string VariableTagBegin = "##";
    private string VariableTagEnd = "##";

    private string ModificatorTag = ":";
    private string ModificatorParamSep = ",";

    private string ConditionTagIfBegin = "##If--";
    private string ConditionTagIfEnd = "##";
    private string ConditionTagElseBegin = "##Else--";
    private string ConditionTagElseEnd = "##";
    private string ConditionTagEndIfBegin = "##EndIf--";
    private string ConditionTagEndIfEnd = "##";

    private string BlockTagBeginBegin = "##BlockBegin--";
    private string BlockTagBeginEnd = "##";
    private string BlockTagEndBegin = "##BlockEnd--";
    private string BlockTagEndEnd = "##";

    /// <value>Template block</value>
    public string TemplateBlock
    {
      get { return this._strTemplateBlock; }
      set
      {
        this._strTemplateBlock = value;
        ParseBlocks();
      }
    }

    /// <value>Template Variables</value>
    public Hashtable Variables
    {
      get { return this._hstValues; }
      set { this._hstValues = value; }
    }

    /// <value>Error Massage</value>
    public Hashtable ErrorMessage
    {
      get { return _ErrorMessage; }
    }

    /// <value>Blocks inside template</value>
    public Dictionary<string, Parser> Blocks
    {
      get { return _Blocks; }
    }

    /// <summary>
    /// Creates a new instance of TemplateParser
    /// </summary>

    #region Contructors
    public Parser()
    {
      this._strTemplateBlock = "";
    }

    public Parser(string FilePath)
    {
      ReadTemplateFromFile(FilePath);
      ParseBlocks();
    }

    public Parser(Hashtable Variables)
    {
      this._hstValues = Variables;
    }

    public Parser(string FilePath, Hashtable Variables)
    {
      ReadTemplateFromFile(FilePath);
      this._hstValues = Variables;
      ParseBlocks();
    }
    #endregion

    /// <summary>
    /// Setup template from specified file
    /// </summary>
    /// <param name="FilePath">Full phisical path to template file</param>
    public void SetTemplateFromFile(string FilePath)
    {
      ReadTemplateFromFile(FilePath);
    }

    /// <summary>
    /// Setup template as string block
    /// </summary>
    /// <param name="TemplateBlock">String template block</param>
    public void SetTemplate(string TemplateBlock)
    {
      this.TemplateBlock = TemplateBlock;
    }

    /// <summary>
    /// Parse template after setuping Template and Variables
    /// </summary>
    /// <returns>
    /// Parsed Block for Whole Template
    /// </returns>
    public string Parse()
    {
      ParseConditions();
      ParseVariables();
      return this._ParsedBlock;
    }

    /// <summary>
    /// Parse Template Block
    /// </summary>
    /// <returns>
    /// Parsed Block for Specified BlockName
    /// </returns>
    public string ParseBlock(string BlockName, Hashtable Variables)
    {
      if (!this._Blocks.ContainsKey(BlockName))
      {
        throw new ArgumentException(String.Format("Could not find Block with Name '{0}'", BlockName));
      }

      this._Blocks[BlockName].Variables = Variables;
      return this._Blocks[BlockName].Parse();
    }

    /// <summary>
    /// Parse template and save result into specified file
    /// </summary>
    /// <param name="FilePath">Full physical path to file</param>
    /// <param name="ReplaceIfExists">If true file which already exists
    /// will be replaced</param>
    /// <returns>True if new content has been written</returns>
    public bool ParseToFile(string FilePath, bool ReplaceIfExists)
    {
      if (File.Exists(FilePath) && !ReplaceIfExists)
      {
        return false;
      }
      else
      {
        StreamWriter sr = File.CreateText(FilePath);
        sr.Write(Parse());
        sr.Close();
        return true;
      }
    }

    /// <summary>
    /// Read template content from specified file
    /// </summary>
    /// <param name="FilePath">Full physical path to template file</param>
    private void ReadTemplateFromFile(string FilePath)
    {
      if (!File.Exists(FilePath))
      {
        throw new ArgumentException("Template file does not exist.");
      }

      StreamReader reader = new StreamReader(FilePath);
      this.TemplateBlock = reader.ReadToEnd();
      reader.Close();
    }

    /// <summary>
    /// Parse all blocks in template
    /// </summary>
    private void ParseBlocks()
    {
      //int idxPrevious = 0;
      int idxCurrent = 0;
      while ((idxCurrent = this._strTemplateBlock.IndexOf(this.BlockTagBeginBegin, idxCurrent)) != -1)
      {
        string BlockName;
        int idxBlockBeginBegin, idxBlockBeginEnd, idxBlockEndBegin;

        idxBlockBeginBegin = idxCurrent;
        idxCurrent += this.BlockTagBeginBegin.Length;

        // Searching for BlockBeginEnd Index

        idxBlockBeginEnd = this._strTemplateBlock.IndexOf(this.BlockTagBeginEnd, idxCurrent);
        if (idxBlockBeginEnd == -1) throw new Exception("Could not find BlockTagBeginEnd");

        // Getting Block Name

        BlockName = this._strTemplateBlock.Substring(idxCurrent, (idxBlockBeginEnd - idxCurrent));
        idxCurrent = idxBlockBeginEnd + this.BlockTagBeginEnd.Length;

        // Getting End of Block index

        string EndBlockStatment = this.BlockTagEndBegin + BlockName + this.BlockTagEndEnd;
        idxBlockEndBegin = this._strTemplateBlock.IndexOf(EndBlockStatment, idxCurrent);
        if (idxBlockEndBegin == -1) throw new Exception("Could not find End of Block with name '" + BlockName + "'");

        // Add Block to Dictionary

        Parser block = new Parser();
        block.TemplateBlock = this._strTemplateBlock.Substring(idxCurrent, (idxBlockEndBegin - idxCurrent));
        this._Blocks.Add(BlockName, block);

        // Remove Block Declaration From Template

        this._strTemplateBlock = this._strTemplateBlock.Remove(idxBlockBeginBegin, (idxBlockEndBegin - idxBlockBeginBegin));

        idxCurrent = idxBlockBeginBegin;
      }
    }

    /// <summary>
    /// Parse all conditions in template
    /// </summary>
    private void ParseConditions()
    {
      int idxPrevious = 0;
      int idxCurrent = 0;
      this._ParsedBlock = "";
      while ((idxCurrent = this._strTemplateBlock.IndexOf(this.ConditionTagIfBegin, idxCurrent)) != -1)
      {
        string VarName;
        string TrueBlock, FalseBlock;
        string ElseStatment, EndIfStatment;
        int idxIfBegin, idxIfEnd, idxElseBegin, idxEndIfBegin;
        bool boolValue;

        idxIfBegin = idxCurrent;
        idxCurrent += this.ConditionTagIfBegin.Length;

        // Searching for EndIf Index

        idxIfEnd = this._strTemplateBlock.IndexOf(this.ConditionTagIfEnd, idxCurrent);
        if (idxIfEnd == -1) throw new Exception("Could not find ConditionTagIfEnd");

        // Getting Value Name

        VarName = this._strTemplateBlock.Substring(idxCurrent, (idxIfEnd - idxCurrent));

        idxCurrent = idxIfEnd + this.ConditionTagIfEnd.Length;

        // Compare ElseIf and EndIf Indexes

        ElseStatment = this.ConditionTagElseBegin + VarName + this.ConditionTagElseEnd;
        EndIfStatment = this.ConditionTagEndIfBegin + VarName + this.ConditionTagEndIfEnd;
        idxElseBegin = this._strTemplateBlock.IndexOf(ElseStatment, idxCurrent);
        idxEndIfBegin = this._strTemplateBlock.IndexOf(EndIfStatment, idxCurrent);
        if (idxElseBegin > idxEndIfBegin) throw new Exception("Condition Else Tag placed after Condition Tag EndIf for '" + VarName + "'");

        // Getting True and False Condition Blocks

        if (idxElseBegin != -1)
        {
          TrueBlock = this._strTemplateBlock.Substring(idxCurrent, (idxElseBegin - idxCurrent));
          FalseBlock = this._strTemplateBlock.Substring((idxElseBegin + ElseStatment.Length), (idxEndIfBegin - idxElseBegin - ElseStatment.Length));
        }
        else
        {
          TrueBlock = this._strTemplateBlock.Substring(idxCurrent, (idxEndIfBegin - idxCurrent));
          FalseBlock = "";
        }

        // Parse Condition

        try
        {
          boolValue = Convert.ToBoolean(this._hstValues[VarName]);
        }
        catch
        {
          boolValue = false;
        }

        string BeforeBlock = this._strTemplateBlock.Substring(idxPrevious, (idxIfBegin - idxPrevious));

        if (this._hstValues.ContainsKey(VarName) && boolValue)
        {
          this._ParsedBlock += BeforeBlock + TrueBlock.Trim();
        }
        else
        {
          this._ParsedBlock += BeforeBlock + FalseBlock.Trim();
        }

        idxCurrent = idxEndIfBegin + EndIfStatment.Length;
        idxPrevious = idxCurrent;
      }
      this._ParsedBlock += this._strTemplateBlock.Substring(idxPrevious);
    }

    /// <summary>
    /// Parse all variables in template
    /// </summary>
    private void ParseVariables()
    {
      int idxCurrent = 0;
      while ((idxCurrent = this._ParsedBlock.IndexOf(this.VariableTagBegin, idxCurrent)) != -1)
      {
        string VarName, VarValue;
        int idxVarTagEnd;

        idxVarTagEnd = this._ParsedBlock.IndexOf(this.VariableTagEnd, (idxCurrent + this.VariableTagBegin.Length));
        if (idxVarTagEnd == -1) throw new Exception(String.Format("Index {0}: could not find Variable End Tag", idxCurrent));

        // Getting Variable Name

        VarName = this._ParsedBlock.Substring((idxCurrent + this.VariableTagBegin.Length), (idxVarTagEnd - idxCurrent - this.VariableTagBegin.Length));

        // Checking for Modificators

        string[] VarParts = VarName.Split(this.ModificatorTag.ToCharArray());
        VarName = VarParts[0];

        // Getting Variable Value
        // If Variable doesn't exist in _hstValue then
        // Variable Value equal empty string

        // [added 6/6/2006] If variable is null than it will also has empty string

        VarValue = String.Empty;
        if (this._hstValues.ContainsKey(VarName) && this._hstValues[VarName] != null)
        {
          VarValue = this._hstValues[VarName].ToString();
        }

        // Apply All Modificators to Variable Value

        for (int i = 1; i < VarParts.Length; i++)
          this.ApplyModificator(ref VarValue, VarParts[i]);

        // Replace Variable in Template

        this._ParsedBlock = this._ParsedBlock.Substring(0, idxCurrent) + VarValue + this._ParsedBlock.Substring(idxVarTagEnd + this.VariableTagEnd.Length);

        // Add Length of added value to Current index 
        // to prevent looking for variables in the added value
        // Fixed Date: April 5, 2006
        idxCurrent += VarValue.Length;
      }
    }

    /// <summary>
    /// Method for applying modificators to variable value
    /// </summary>
    /// <param name="Value">Variable value</param>
    /// <param name="Modificator">Determination statment</param>
    private void ApplyModificator(ref string Value, string Modificator)
    {
      // Checking for parameters

      string strModificatorName = "";
      string strParameters = "";
      int idxStartBrackets, idxEndBrackets;
      if ((idxStartBrackets = Modificator.IndexOf("(")) != -1)
      {
        idxEndBrackets = Modificator.IndexOf(")", idxStartBrackets);
        if (idxEndBrackets == -1)
        {
          throw new Exception("Incorrect modificator expression");
        }
        else
        {
          strModificatorName = Modificator.Substring(0, idxStartBrackets).ToUpper();
          strParameters = Modificator.Substring(idxStartBrackets + 1, (idxEndBrackets - idxStartBrackets - 1));
        }
      }
      else
      {
        strModificatorName = Modificator.ToUpper();
      }
      string[] arrParameters = strParameters.Split(this.ModificatorParamSep.ToCharArray());
      for (int i = 0; i < arrParameters.Length; i++)
        arrParameters[i] = arrParameters[i].Trim();

      try
      {
        Type typeModificator = Type.GetType("TemplateParser.Modificators." + strModificatorName);
        if (typeModificator.IsSubclassOf(Type.GetType("TemplateParser.Modificators.Modificator")))
        {
          Modificator objModificator = (Modificator)Activator.CreateInstance(typeModificator);
          objModificator.Apply(ref Value, arrParameters);
        }
      }
      catch
      {
        throw new Exception(String.Format("Could not find modificator '{0}'", strModificatorName));
      }
    }
  }
}

Dependant class of the one above:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;

namespace WebApp.Web.Code.Mail
{
  /// <summary>
  /// Abstract class for Modificators
  /// </summary>
  public abstract class Modificator
  {
    protected Hashtable _parameters = new Hashtable();

    public Hashtable Parameters
    {
      get { return _parameters; }
    }

    public abstract void Apply(ref string Value, params string[] Parameters);
  }

  class NL2BR : Modificator
  {
    public override void Apply(ref string Value, params string[] Parameters)
    {
      Value = Value.Replace("\n", "<br>");
    }
  }

  class HTMLENCODE : Modificator
  {
    public override void Apply(ref string Value, params string[] Parameters)
    {
      Value = Value.Replace("&", "&amp;");
      Value = Value.Replace("<", "&lt;");
      Value = Value.Replace(">", "&gt;");
    }
  }

  class UPPER : Modificator
  {
    public override void Apply(ref string Value, params string[] Parameters)
    {
      Value = Value.ToUpper();
    }
  }

  class LOWER : Modificator
  {
    public override void Apply(ref string Value, params string[] Parameters)
    {
      Value = Value.ToLower();
    }
  }

  class TRIM : Modificator
  {
    public override void Apply(ref string Value, params string[] Parameters)
    {
      Value = Value.Trim();
    }
  }

  class TRIMEND : Modificator
  {
    public override void Apply(ref string Value, params string[] Parameters)
    {
      Value = Value.TrimEnd();
    }
  }

  class TRIMSTART : Modificator
  {
    public override void Apply(ref string Value, params string[] Parameters)
    {
      Value = Value.TrimStart();
    }
  }

  class DEFAULT : Modificator
  {
    public override void Apply(ref string Value, params string[] Parameters)
    {
      if (Value == null || Value.Trim() == string.Empty)
        Value = Parameters[0];
    }
  }
}

You should be ready to rock and roll :)

commented: Wow! This definitely rocks! +5

wow scott, although i havent tried any such mammoth thing, i think this will suit me perfectly.. i shall try to implement it today.. thnx a heavy bunch..

Unfortunately it is a lot of plumbing to hook up. Be sure to upload your project if you have any questions about implementing it. ASP.NET is such a hard language to support on the forums because you're usually dealing with html, ajax stuff, javascript, a browser, sql, c#, email/smtp, etc.

I hope you get it working and good luck!

thanks a lot scott. will def post it when done

Hello,

I finally got started on this project.. But with regards to the code given by scott, I really have no clue as to where to start and how to proceed. any help or advice in this regard would be welcome

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.