Tuesday, November 18, 2014

Email Availability Control using Microsoft AJAX and Json WCF

Hi Guys,

If you are a web developer, I am sure you would have encountered a scenario where you have to check the email/username availability. So I thought of making a control which will call a WCF service through Microsoft AJAX and let the user know whether the email/username is already taken or not. Hope you like it.
















Solution

1) Create a Solution like following,


- One is a web site
- Other is a Class Library





















2) Open AjaxEnabledControls -> EmailTextBox.cs and paste the following code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace AjaxEnabled
{
    public class EmailTextBox : TextBox,IScriptControl
    {
        private ScriptManager sMgr;
        public string ServiceUrl;
        

        protected virtual IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            ScriptControlDescriptor descriptor =
            new ScriptControlDescriptor("AjaxEnabled.EmailTextBox", this.ClientID);
            descriptor.AddProperty("serviceUrl", this.ServiceUrl);
            
            return new ScriptDescriptor[] { descriptor };
        }

        protected virtual IEnumerable<ScriptReference> GetScriptReferences()
        {
            ScriptReference reference = new ScriptReference();
            reference.Assembly = "AjaxEnabled";
            reference.Name = "AjaxEnabled.EmailTextBox.js";
            return new ScriptReference[] { reference };
        }

        protected override void OnPreRender(EventArgs e)
        {
            if (!this.DesignMode)
            {
                //test for the existence of a ScriptManager
                sMgr = ScriptManager.GetCurrent(Page);
                if (sMgr == null)
                    throw new HttpException(
                    "A ScriptManager control must exist on the page.");
                sMgr.RegisterScriptControl(this);
            }
            base.OnPreRender(e);
        }
        protected override void Render(HtmlTextWriter writer)
        {
            if (!this.DesignMode)
                sMgr.RegisterScriptDescriptors(this);
            base.Render(writer);
            writer.WriteLine(string.Format(@"<br /><div><input type=""hidden"" id=""{0}""/> 
                <div id=""{1}"" style=""float:left""></div><span class=""emailTextboxSpan"" id=""{2}""></span></div><br />",
                this.ClientID + "_Hidden",
                this.ClientID + "_Image", 
                this.ClientID + "_Status"));
        }
        IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
        {
            return GetScriptReferences();
        }
        IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
        {
            return GetScriptDescriptors();
        }
    }

}


3) Open AjaxEnabledControls -> EmailTextBox.js and paste the following code

/// <reference name="MicrosoftAjax.js"/>
Type.registerNamespace("AjaxEnabled");

//create constructor
AjaxEnabled.EmailTextBox = function (element) {
    AjaxEnabled.EmailTextBox.initializeBase(this, [element]);
    this._serviceUrl = null;
    this._spanControlId = '';
    this._imageControlId = '';
    this._hiddenControlId = '';
    this._isEmailAvailable = true;
}

//define class
AjaxEnabled.EmailTextBox.prototype = {
    //initialize the UI control
    initialize: function () {
        AjaxEnabled.EmailTextBox.callBaseMethod(this, 'initialize');
        this._onKeyupHandler = Function.createDelegate(this, this._onKeyup);
        this._onTextChangeHandler = Function.createDelegate(this, this._onTextChange);
        $addHandlers(this.get_element(), { 'keyup': this._onKeyup, 'change': this._onTextChange }, this);
    },
    dispose: function () {
        $clearHandlers(this.get_element());
        AjaxEnabled.EmailTextBox.callBaseMethod(this, 'dispose');
    },
    //define keystroke event
    _onKeyup: function (e) {
        this.validateEmail(e);
    },
    _onTextChange: function (e) {
        this.validateEmail(e);
    },
    validateEmail: function (e) {
        //get email text

        var emailValid = true;

        var x = this.get_element().value;
        var email = x;
        var atpos = x.indexOf("@");
        var dotpos = x.lastIndexOf(".");
        if (atpos < 1 || dotpos < atpos + 2 || dotpos + 2 >= x.length) {
            emailValid = false;
        }
        this._spanControlId = this.get_element().id + '_Status';
        this._imageControlId = this.get_element().id + '_Image';
        this._hiddenControlId = this.get_element().id + '_Hidden';
        var spanEmail = $get(this._spanControlId);
        var imageElement = $get(this._imageControlId);
        if (emailValid) {

            this.returnEmailAvailable(email);

        }
        else {
            this.get_element().className = '';
            imageElement.className = '';
            spanEmail.innerHTML = '';
            this._isEmailAvailable = false;
        }

    },
    //define properties
    get_serviceUrl: function () {
        return this._serviceUrl;
    },
    set_serviceUrl: function (value) {
        this._serviceUrl = value;
    },

    get_isEmailAvailable: function () {
        return this._isEmailAvailable;
    },
    OnWebRequestCompleted: function onWebRequestCompleted(executor, eventArgs) {
        if (executor.get_responseAvailable()) {

            var userContext = executor.get_webRequest().get_userContext();
            userContext.DisplayWebRequestBody(executor);
        }
        else {
            if (executor.get_timedOut())
                alert("Timed Out");
            else
                if (executor.get_aborted())
                    alert("Aborted");
        }
    },
    DisplayWebRequestBody: function displayWebRequestBody(executor) {

        var userContext = executor.get_webRequest().get_userContext();
        var displayElement = $get(userContext._spanControlId);

        displayElement.innerHTML =
        "Email Address is ";

        var isAvailable = executor.get_responseData() == "true" ? true : false
        var content = (isAvailable) ? "Available" : "Taken";
        if (document.all)
            displayElement.innerText += content;
        else
        // Firefox
            displayElement.textContent += content;

        userContext.get_element().className = content + "CssClass";
        userContext._isEmailAvailable = isAvailable;
        var imageElement = $get(userContext._imageControlId);
        var hiddenElement = $get(userContext._hiddenControlId);
        imageElement.className = content + "ImageCssClass";
        hiddenElement.value = isAvailable.toString();

    },

    returnEmailAvailable: function (email) {

        // Instantiate the WebRequest object.
        var wRequest = new Sys.Net.WebRequest();

        // Set the request Url.  
        wRequest.set_url(this._serviceUrl + email);

        // Set the request verb.
        wRequest.set_httpVerb("GET");

        // Set user's context
        wRequest.set_userContext(this);

        // Set the web request completed event handler,
        // for processing return data.
        wRequest.add_completed(this.OnWebRequestCompleted);

        // Execute the request.
        wRequest.invoke();


    }

}

//register class as a Sys.Control
AjaxEnabled.EmailTextBox.registerClass('AjaxEnabled.EmailTextBox',
Sys.UI.Control);
//notify loaded
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

4) Open AjaxEnabled WebSite -> App_Code -> IEmailService.cs and paste the following code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IEmailService" in both code and config file together.
[ServiceContract]
public interface IEmailService
{
[OperationContract]
    [WebGet(UriTemplate = "/CheckEmail?email={email}",
            ResponseFormat = WebMessageFormat.Json)]
bool CheckEmail(string email);
}

5) Open AjaxEnabled WebSite -> App_Code -> EmailService.cs and paste the following code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "EmailService" in code, svc and config file together.
public class EmailService : IEmailService
{
    public bool CheckEmail(string email)
{
        if (email.Trim().ToLower() == "shahim@dummy.com")
            return false;
        else
            return true;
}
}

6) Open AjaxEnabled WebSite -> Styles -> Site.css and paste the following styles

.weak
{
border: medium solid #008000;
}
.medium
{
border: thin solid #FFFF00;
}
.strong
{
border: medium solid #FF0000;
}
.emailTextboxSpan
{
    font-style : oblique;
}
.TakenCssClass
{
     border : 1px solid red;
}
.AvailableCssClass
{
    border : 1px solid green;
}

.TakenImageCssClass
{
    background-image : url('../Images/Taken.png');
    background-repeat : no-repeat;
    padding-top : 2px;
    width:24px;
    height:24px;
}
.AvailableImageCssClass
{
    background-image : url('../Images/Available.png');
    background-repeat : no-repeat;
    padding-top : 2px;
     width:24px;
    height:24px;
}

7) Finally add the following mark up in AjaxEnabled WebSite -> Default.aspx

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeFile="Default.aspx.cs" Inherits="_Default" %>
    <%@ Register Assembly="AjaxEnabled" Namespace="AjaxEnabled"
TagPrefix="ajaxEnabled" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">

<script type="text/javascript">
    function ClientValidate(source, arguments) {

        var available = document.getElementById("MainContent_emailTextBox1_Hidden").value;
        if (available != '')
            arguments.IsValid = (available == "true") ? true : false;
        else
            arguments.IsValid = true;

    }
</script>

<asp:ScriptManager ID="ScriptManager1" runat="server">

</asp:ScriptManager>
   
        Email Validator TextBox using Microsoft AJAX
       <br />
       <br />

  <ajaxEnabled:EmailTextBox ID="emailTextBox1" serviceUrl="./EmailService.svc/CheckEmail?email="  
   runat="server" width="200" ></ajaxEnabled:EmailTextBox>
   <br />
   <br />

   <asp:Button ID="btnSubmit" runat="server" Text="Submit" ValidationGroup="vgSubmit"/>
   <br />
   <br />
   <asp:CustomValidator 
       ID="cvEmail" runat="server" ErrorMessage="Email Address is already Taken. Please change to Proceed!"
       ClientValidationFunction="ClientValidate" ValidationGroup="vgSubmit"></asp:CustomValidator>

    
</asp:Content>