Blog

Posts written in 2010.

  • Published on
    -
    4 min read

    Multi Query Search Using Lucene.NET

    Over the last few days I have been doing some research on the best way to implement search functionality for a site I am currently building. The site will consists mainly of news articles. The client wanted a search that would allow a user to search across all fields that related to a news article.

    Originally, I envisaged writing my own SQL to query a few tables within my database to return some search results. But as I delved further into designing the database architecture in the early planning stages, I found that my original (somewhat closed minded) approach wouldn't be flexible nor scalable enough to search and extract all the information I required.

    From what I have researched, the general consensus is to either use SQL Full Text Search or Lucene.NET. Many have favoured the use of Lucene due to its richer querying language and generally more flexible since you have the ability to write a search index tailored to your project. From what I gather, Lucene can work with any type of text data. For example, you not only can index rows in your database but there are also solutions to support indexing physical files in your application. Neat!

    I have written some basic code (below) with a couple methods to get started in creating a search index and carrying out a multi-query search across your whole index. You would further enhance this code to only carry out a full index once all required records have been added. Most implementations of Lucene would use incremental indexing, where documents already in the index are just updated individually, rather than deleting the whole index and building a new one every time. I plan to hook up and optimise my Lucene code into a service that would be scheduled to carry out an incremental index every midnight.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Lucene;
    using Lucene.Net;
    using Lucene.Net.Store;
    using Lucene.Net.Analysis;
    using Lucene.Net.Analysis.Standard;
    using Lucene.Net.Index;
    using Lucene.Net.Documents;
    using Lucene.Net.QueryParsers;
    using Lucene.Net.Search;
    using System.Configuration; 
    
    namespace MES.DataManager.Search
    {
        public class Lucene
        {
            public static void IndexSite()
            {           
                    //The file location of the index
                    string indexLocation = @ConfigurationManager.AppSettings["SearchIndexPath"];
    
                    Directory searchDirectory = null;
    
                    if (System.IO.Directory.Exists(indexLocation))
                        searchDirectory = FSDirectory.GetDirectory(indexLocation, false);
                    else
                        searchDirectory = FSDirectory.GetDirectory(indexLocation, true); 
    
                    //Create an analyzer to process the text
                    Analyzer searchAnalyser = new StandardAnalyzer(); 
    
                    //Create the index writer with the directory and analyzer.
                    IndexWriter indexWriter = new IndexWriter(searchDirectory, searchAnalyser, true);
    
                    //Iterate through Article table and populate the index
                    foreach (Article a in ArticleBLL.GetArticleDetails())
                    {
                        Document doc = new Document();
    
                        doc.Add(new Field("id", a.ID.ToString(), Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.YES));
                        doc.Add(new Field("title", a.Title, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));
                        doc.Add(new Field("articletype", a.Type.TypeName, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES)); 
    
                        if (!String.IsNullOrEmpty(a.Summary))
                            doc.Add(new Field("summary", a.Summary, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));                
    
                        if (!String.IsNullOrEmpty(a.ByLineShort))
                            doc.Add(new Field("bylineshort", a.ByLineShort, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));                    
    
                        if (!String.IsNullOrEmpty(a.ByLineLong))
                            doc.Add(new Field("bylinelong", a.ByLineLong, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));                   
    
                        if (!String.IsNullOrEmpty(a.BasicWords))
                            doc.Add(new Field("basicwords", a.BasicWords, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));                   
    
                        if (!String.IsNullOrEmpty(a.MediumWords))
                            doc.Add(new Field("mediumwords", a.MediumWords, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));                   
    
                        if (!String.IsNullOrEmpty(a.LongWords))
                            doc.Add(new Field("longwords", a.LongWords, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));  
    
                        //Write the document to the index
                        indexWriter.AddDocument(doc);
                    }
                              
    
                    //Optimize and close the writer
                    indexWriter.Optimize();
                    indexWriter.Close();         
            }
    
            public static List<CoreArticleDetail> SearchArticles(string searchTerm)
            {
                Analyzer analyzer = new StandardAnalyzer(); 
    
                //Search by multiple fields
                MultiFieldQueryParser parser = new MultiFieldQueryParser(
                                                                    new string[]
                                                                    {
                                                                        "title",
                                                                        "summary",
                                                                        "bylineshort",
                                                                        "bylinelong",
                                                                        "basicwords",
                                                                        "mediumwords",
                                                                        "longwords"
                                                                    },
                                                                    analyzer); 
    
                Query query = parser.Parse(searchTerm); 
    
                //Create an index searcher that will perform the search
                IndexSearcher searcher = new IndexSearcher(@ConfigurationManager.AppSettings["SearchIndexPath"]); 
    
                //Execute the query
                Hits hits = searcher.Search(query);
    
                List<int> articleIDs = new List<int>(); 
    
                //Iterate through index and return all article id’s
                for (int i = 0; i < hits.Length(); i++)
                {
                    Document doc = hits.Doc(i);
    
                    articleIDs.Add(int.Parse(doc.Get("id")));
                } 
    
                return ArticleBLL.GetArticleSearchInformation(articleIDs);
            }
    
        }
    }
    

    As you can see, my example allows you to carry out a search across as many of your fields as you require which I am sure you will find useful. It took a lot of research to find out how to carry out a multi query search. Majority of the examples I found over the internet showed you how to search only one field.

    The main advantage I can see straight away from using Lucene is that since the search data is held on disk, there is hardly any need to query the database. The only downside I can see is problems being caused by the possibility a corrupt index.

    For more information on using Lucene, here are a couple of links that you may find useful to get started (I know I did):

    http://www.codeproject.com/KB/library/IntroducingLucene.aspx http://ifdefined.com/blog/post/Full-Text-Search-in-ASPNET-using-LuceneNET.aspx

  • Published on
    -
    4 min read

    Watermarking Images On The Fly Using ASP.NET

    Watermarking and general image manipulation within the .NET Framework has become quite an easy thing to carry out thanks to the features provided by the System.Drawing namespace. The System.Drawing namespace contains types to help you with…well…drawing and rendering images. I will not be covering the basic use of the System.Drawing class. But feel free to carry out a Google.

    My example consists of using a .NET (aspx) page and a Generic Handler (ashx). The .NET page will allow me to select an image, add a logo to the top left and some text. The Generic Handler will contain all the magic needed to manipulate the image based on selections made within the .NET page. The screenshot (below) shows my basic program in action.

    Image Watermarking

    Firstly, let me start off by showing you the code for the Generic Handler.

    ImageRenderJpeg.ashx

    using System;
    using System.Web;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Drawing.Drawing2D;
    
    public class ImageRenderJpeg : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "image/jpeg";
    
            //Retrieve image details
            string imageUrl = context.Request.QueryString["ImageUrl"].ToString();
            string imageComment = context.Request.QueryString["ImageComment"].ToString();
            string imageIconUrl = context.Request.QueryString["Icon"].ToString();
    
            if (!String.IsNullOrEmpty(imageUrl))
            {
                //Get the location of the image
                Image imagePhoto = Image.FromFile(imageUrl);
    
                // Get dimensions of image
                int imageHeight = imagePhoto.Height;
                int imageWidth = imagePhoto.Width;
    
                //Create a new Bitmap
                Bitmap oBitmap = new Bitmap(imageWidth, imageHeight, PixelFormat.Format24bppRgb);
    
                //Load Background Graphic from Image
                Graphics oGraphics = Graphics.FromImage(oBitmap);
                oGraphics.SmoothingMode = SmoothingMode.HighQuality;
                oGraphics.DrawImage(imagePhoto, new Rectangle(0, 0, imageWidth, imageHeight), 0, 0, imageWidth, imageHeight, GraphicsUnit.Pixel);
    
                //Layer 1: Add an Image Logo to the top left
                if (!String.IsNullOrEmpty(imageIconUrl))
                {
                    Image imageIcon = Image.FromFile(imageIconUrl);
                    oGraphics.DrawImage(imageIcon, new Rectangle(5, 5, 124, 48), 0, 0, imageIcon.Width, imageIcon.Height, GraphicsUnit.Pixel);
    
                    imageIcon.Dispose();
                }
                
                //Layer 2: Add Comment
                if (!String.IsNullOrEmpty(imageComment))
                {
                    Font commentFont = new Font("Arial", 14, FontStyle.Regular); //Font Style
                    StringFormat commentFormat = new StringFormat();
                    commentFormat.Alignment = StringAlignment.Near; //Align text in left of layer
    
                    SolidBrush commentBrush = new SolidBrush(Color.Black); //Font Colour
    
                    oGraphics.FillRectangle(Brushes.Beige, 5, imageHeight - 55, imageWidth - 15, 50); //Create a rectangle with white background
                    oGraphics.DrawString(imageComment, commentFont, commentBrush, new Rectangle(5, imageHeight - 55, imageWidth - 15, 50), commentFormat); //Add comment text inside rectangle
                }
                
                //Layer 3: Add Copyright watermark
                Font watermarkFont = new Font("Arial", 40, FontStyle.Bold); //Font Style
                SolidBrush semiTransBrush = new SolidBrush(Color.LightGray); //Font Colour
                StringFormat watermarkFormat = new StringFormat();
                watermarkFormat.Alignment = StringAlignment.Center; //Align text in center of image
    
                oGraphics.DrawString("Copyright",
                    watermarkFont,
                    semiTransBrush,
                    new PointF(imageWidth / 2, imageHeight / 2), watermarkFormat);
    
                //Dispose of graphic objects
                imagePhoto.Dispose();
                oGraphics.Dispose();
    
                //Output image
                oBitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);
            }
            else
            {
            }
    
        }
    
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
    

    You can see that I am manipulating my image based on the query string parameters I pass from my .NET page into my Generic Handler. Hopefully, my code is commented well enough to explain the general overview on what is going on.

    The following code displays how my aspx page parses all the parameters needed to generate an image on the page:

    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>Image Generator</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            Select an Image:
            <asp:DropDownList ID="ddlImage" runat="server">
                <asp:ListItem Text="*" Value="*">Select Image</asp:ListItem>
                <asp:ListItem Text="The Tumbler" Value="C:\Users\Surinder\Documents\Visual Studio 2010\WebSites\ImageCreator\Images\batmobile_Tumbler.jpg"></asp:ListItem>
                <asp:ListItem Text="Audi TT" Value="C:\Users\Surinder\Documents\Visual Studio 2010\WebSites\ImageCreator\Images\new-audi-tt-coupe.jpg"></asp:ListItem>
                <asp:ListItem Text="Volvo Concept" Value="C:\Users\Surinder\Documents\Visual Studio 2010\WebSites\ImageCreator\Images\volvo-s60-concept-interior1.jpg"></asp:ListItem>
            </asp:DropDownList>
            <br />
            <br />
            Add Logo: <asp:TextBox ID="txtImage" runat="server"></asp:TextBox>
            <br />
            <br />
            Add a comment:
            <asp:TextBox ID="txtComment" runat="server" TextMode="MultiLine" Width="500" Height="50"></asp:TextBox>
            <br />
            <br />
            <asp:Button ID="btnCreateImage" Text="Create Image" runat="server" onclick="btnCreateImage_Click" />
            <br />
            <br />
            <img id="imgRender" alt="Image Render" title="Image Render" runat="server" />        
        </div>
        </form>
    </body>
    </html>
    

    Default.aspx.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public partial class _Default : System.Web.UI.Page 
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (ddlImage.SelectedValue == "*")
            {
                imgRender.Visible = false;
            }
            else
            {
                imgRender.Visible = true;
            }
        }
    
        protected void btnCreateImage_Click(object sender, EventArgs e)
        {
            if (ddlImage.SelectedValue != "*")
            {
                //The Image source will be pointed to our Generic Handler to display the image.
                imgRender.Src = String.Format("ImageRenderJpeg.ashx?ImageUrl={0}&ImageComment={1}&Icon={2}", ddlImage.SelectedValue, txtComment.Text, txtImage.Text);
            }
        }
    }
    
  • Arrrgh!!! Microsoft has to be the yearly winner for the “Most Stupid Error Message” award for displaying the most excruciatingly annoying error messages in any of their products. The main reason for their annoyance is because majority of the error messages tells you something is wrong, but not the source of the error. A good example of this is: “Cannot delete file. This file is in use by another program or user”.

    I am not expecting the error message to tell me the exact cause of the error but at least some meaningful information on what could be the issue. Anyway, back to the error at hand…

    I found a really great bit of free software that fixes the problem. Its called Unlocker and you can download it here. It allows you to see exactly what processes are currently using the file you are trying to delete, edit or move. What’s even better is that Unlocker can kill the processes within its UI.

  • Published on
    -
    1 min read

    Making Calculations In LINQ

    I am currently working on an ASP.NET 4.0  e-commerce site using Entity Framework alongside LINQ. I came across a small issue when I needed to carry out some calculations based on product pricing and the discounts that would need to be applied based on a specific customers allowance.

    You maybe thinking, what’s the issue? Well I wanted to be able to make the calculations within my LINQ query since both product pricing and customer discount amounts are stored in the database. So initially wrote the following code:

    using (MyEntities myContext = new MyEntities())
    {
        int productPrice = (from p in myContext.Products
                            where p.ProductID == 1
                            select p.Price).SingleOrDefault(); 
     
        int customerDiscount = (from cd in myContext.CustomerDiscounts
                                where cd.CustomerID == 15
                                select cd.Discount).SingleOrDefault(); 
     
        int productDiscountedPrice = productPrice - ((productPrice * customerDiscount) / 100);
    }
    

    As you can see from my code above, I had to write two separate LINQ queries in order to get the values I wanted and then base my calculations on those values. But I was determined to carry out my calculations in one query. Luckily, LINQ has has a really cool keyword that I totally missed. It’s the “let” keyword which allows you to declare a variable and assign it a calculated value.

    using (MyEntities myContext = new MyEntities())
    {
        int productDiscount = (from cd in myContext.CustomerDiscounts
                               join p in myContext.Products on cd.ProductID equals cd.ProductID
                               where p.ProductID == 1 && cd.CustomerID == 15
                               let discountAmount = p.Price - ((p.Price * cd.Discount) / 100)
                               select discountAmount).SingleOrDefault();
    }
    

    Since my database schema allowed me to join my “CustomerDiscount” and “Products” table, I was able to join the two tables and retrieve values I required through one query.

  • Published on
    -
    1 min read

    Handling Unsupported Internet Explorer 6 Users

    Web browsers have come a long way since the days of Internet Explorer 6 release back in 2001. You would think 9 years on we would have all dumped this piece of software in the garbage heap by now. Alas, we still have users to this very date who still use IE6 either due to personal preference or by force (company IT policies).

    As everyone knows, developing a site to be compliant with main stream browsers in addition to carrying out additional fixes to fit in with the slim 6.7% of global users can be a real pain. So instead of trying to fit your site around the small number of IE6 users, why not just knock some common sense into them and notify them to upgrade.

    Thankfully, there is a really easy and polite way to do this. Go to http://code.google.com/p/ie6-upgrade-warning/ and download the JavaScript file and embed the following code to your webpage…

    <!--[if lte IE 6]>
        <script src="js/ie6/warning.js"></script>
        <script>window.onload=function(){e("js/ie6/")}</script>
    <![endif]-->
    

    …which outputs the following result:

    IE6 Upgrade Warning

    As great as this idea is I don’t see many web developers or web agencies implementing this on the sites they create unless really needed. Nevertheless, its step in the right direction to hopefully put a final nail into that IE6 coffin!

  • Published on
    -
    1 min read

    iPhone SDK Error: Base SDK Missing

    I am currently in the process of learning how to build applications for the iPhone. I have recently upgraded from the iPhone SDK 3.0 simulator to the iPhone SDK 4.0 simulator. But this caused some issues when trying to run some of my previous applications I developed prior to when I had the iPhone 3.0 simulator installed.

    Normally, the dropdown box within the XCode window allows you to select different simulators. For example: iPad Simulator 3.2 or iPhone Simulator 4.0. As you can see from my screenshot (below), none of these options were available.

    Base SDK Missing

    Apparently, the iPhone 4.0 SDK can still have the ability to run iPhone 3.0 applications and this is something we should be doing from now on. This requires a couple of changes to carry out in your older 3.0 projects.

    Firstly, you will need to go to Project > Edit Project Settings. When the window appears, click on the Build tab and change the “Base SDK” value to “iPhone Simulator 4.0”.

    Edit Project Settings

    Secondly, go to Project > Edit Active Target. When the window appears, you will have to carry out the same procedure as you carried out in the “Edit Project Settings” whereby you click on the Build tab and change the “Base SDK” value to “iPhone Simulator 4.0”.

    Edit Project Target If you have carried out the changes correctly, you should be able to Build and Run your project successfully. I admit this is not exactly ideal to do this if you have many iPhone 3.0 application projects. But I suppose this fix is better than nothing and plus its quite a quick change.

  • Published on
    -
    1 min read

    Do Not Ignore Android’s Low Memory Warning

    Android Memory I have a HTC Hero which was recently upgraded from Android 1.5 to 2.1 a few months back. It has definitely been a significant and worthwhile upgrade packing in lots of new extra features and most importantly extra applications to download from the Android Market.

    The only downside to the upgrade is that I now have less memory to play with and this can cause a detrimental effect if you get the “Phone memory is running low” warning. Since I received this warning I found that all my Google Synchronisation tasks stopped syncing automatically. Even if I tried manually starting the synchronisation service nothing would happen. In addition, I couldn’t even download any applications from the Android Market.

    Soon as I went on a massive clear out on my phone and resolved the low memory error, my Google Synchronisation worked instantaneously. All the problems I previously had were magically rectified. Its just a shame that all the applications get stored onto the phone memory rather than the external memory.

    The weirdest thing is that I still had around 14MB of free space on my phone prior to having my cleanup. I find it a little strange the low memory threshold is set so high.

    I guess its good to know that Google has rectified this issue by allowing applications to be stored on external memory in their Android 2.2 release. Unfortunately, it highly unlikely my HTC Hero will see this update.

  • Published on
    -
    1 min read

    Mac OS X Snow Leopard VMware Environment Freezing

    Over the last week or so, I have had the most frustrating time creating a Mac OS X Snow Leopard environment using VMware. I won’t go into the whole process I went through to create my Virtual Machine. There are many online articles for you to Google (or Bing :-P) that show you the step-by-step procedures on how to create a Mac OS virtual environment.

    All I can say it took a lot of blood, sweat and tears! You may find that you need to cross-reference between a few sites in order to get the winning combination for a working VMware environment.

    Anyway, if you are one of the lucky ones to have successfully built a Snow Leopard environment, you may have come across an issue whereby your VMware environment randomly freezes for no apparent reason. Now this is quite annoying. After much searching and constant VMware configuration changes, I could not get to the bottom of the issue. I knew that it could not have been to do with the setup, after all I had a fully functioning Mac environment.

    What I noticed is that my environment would never freeze whilst I was using it. It only froze if I left it idle for long periods of time. You are now probably thinking:

    GET TO THE POINT! HOW DID YOU FIX IT???

    Well the cause of the environment to freeze is due to the Energy Saver settings found under System Preferences in your Mac OS (Apple icon > System Preferences > Energy Saver). You will find that it is default to 15 minutes idle time before going into sleep mode. All you need to do is set both Computer Sleep and Display Sleep to Never. As a precaution I also unticked the “Put the hard disk(s) to sleep when possible"

    MacOSEnergySaver

  • Published on
    -
    1 min read

    How to Change Site Name In SharePoint 2003 URL

    In SharePoint 2003, you will notice when you change the name of a site, the change is not reflected in the intranet URL. Modifying the site name within “Site Settings” will only change the title that is displayed when you visit the site.

    You have two options to change the site name you see in the URL:

    1. Delete and recreate your site.
    2. Backup your current site and restore content elsewhere on the intranet.

    You really wouldn’t want to consider the first option if your SharePoint site currently stores high volume of information. The best option would be to carry out a backup and restore using SharePoint’s “stsadm” command prompt. The time it takes to run the backup and restore process will entirely depend on the size of your site.

    So here’s the scenario. We have an intranet that currently contains a site called “InsuranceClaims”. However, this site needs to add additional data relating to employee health schemes. The site name in the web address needs to be renamed to “InsuranceAndHealthClaims”. In order to make this change, the following needs to be carried out:

    1. Backup the “InsuranceClaims” site using the stsadm backup command. The site has been backed up to a file called insurancebackup.bak.
    stsadm.exe -o backup -url http://intranet.computing-studio.com/sites/insuranceclaims -filename C:\insurancebackup.bak
    
    1. Create a new site called “InsuranceAndHealthClaims” from the SharePoint intranet.
    2. Restore the contents of the backup to the new site using the stsadm restore command.
    stsadm.exe -o restore -url http://intranet.computing-studio.com/sites/insuranceandhealthclaims -filename C:\insurancebackup.bak
    

    Providing all goes well when you run the backup and restore stsadm commands, you should get a “Operation completed successfully” message.

  • Published on
    -
    2 min read

    Calling a ASP.NET Method Using jQuery

    Over the last few months I have had the ability to mess around with a bit of jQuery. Even though I don’t have the complete understanding on how it works, I can see the benefits of writing my code in jQuery compared to bashing out lots of lines of JavaScript to do the same thing.

    One the cool features I have used is calling one of my .NET methods using the “$.ajax” jQuery command. In my example (below), I have created two aspx pages. The code-behind of my first page  (jQueryMethodTest.aspx) will only contain a public static method called “WhatIsYourName”, which returns a string value.

    [WebMethod]
    public static string WhatIsYourName(string name)
    {
        if (!String.IsNullOrEmpty(name))
        {
            return String.Concat("Hello ", name, "!");
        }
        else
        {
            return String.Empty;
        }
    }
    

    Remember, the jQueryMethodTest.aspx page only needs to contain our method nothing else! Additional methods can be added. Just don’t add any web controls.

    The second page (jQueryAjax.aspx), will contain our jQuery code and some HTML to output our result from calling the “WhatIsYourName” method.

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <script type="text/javascript" language="javascript" src="javascript/jquery.js"></script>
    </head>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#btnSubmitName").click(function(event) {
                $.ajax({
                    type: "POST",
                    url: "jQueryMethodTest.aspx/WhatIsYourName",
                    data: "{'name': '" + $('#name').val() + "'}",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function(message) {
                        ShowPopup(message);
                    },
                    error: NameFailed
                });
            });
        });
    
        function ShowPopup(result) {
            if (result.d != "") {
                $("#Message").html(result.d);
            }
            else {
                $("#Message").html("I didn't get your name.");
            }
        }
    
        function NameFailed(result) {
            $("#Message").html(result.status + ' ' + result.statusText);
        }  
      </script>  
    
    <body>
        <form id="form1" runat="server">
        <div>
            <input id="name" name="name" type="text" />
            <br />
            <input id="btnSubmitName" name="btnSubmitName" type="button" value="Submit" />
            <br /><br />
            <span id="Message" style="color:Red;"></span>
        </div>
        </form>
    </body>
    </html>
    

    If all goes well, you should get the following result:

    Calling ASP Method Using jQuery

    The “$.ajax” jQuery command requires the following parameters in order to work:

    • url – links to where our .NET method is placed.
    • data – retrieves the value from some control in our page to pass to our method. Remember, the name of the parameter must be named the same as the parameter from our .NET method.
    • dataType – the response type.
    • contentType – the request content type.
    • success – the JavaScript function that gets fired on postback.
    • error – the Javascript function that gets fired if there is a failure. This is an optional parameter.

    I guess jQuery’s motto really is true: “write less, do more”.