Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Calling a Web Service from an HTML page using AJAX

0.00/5 (No votes)
24 Aug 2008 1  
Calling a Web Service from an HTML page using AJAX. Sample Web Service application also included.

Introduction

This is a sample application which makes AJAX calls to a Web Service. This article discusses the server-side aspect of the application.

The Web Service performs the task of fetching and storing data from a SQL Server database in the server. This article explains the server-side aspect of the application. For discussion about how the UI layer works at the client-end, please read: Calling a Web Service from an HTML page (for all browsers).

Using the Code

The model used is as in the image shown below:

model.gif

The client side UI layer is discussed in the article Calling a Web Service from an HTML page (for all browsers).

The Application Logic layer has two layers: Business Object Layer (BL) and Data Access Layer (DAL). The DAL contains the class PollService. PollService is made as a Web Service class by exposing some of its methods as WebMethods.

There are two more details which are optional:

  1. Inheriting your Web Service class from the WebService class of the System.Web.Services namespace.
  2. Applying the WebService attribute to the class declaration.

This will give us an advantage of having access to these built-in ASP.NET objects: Application, Context, Server, Session, User. If we don't need to use these objects, we can skip these details.

Here, the PollService class exposes these methods: AddPoll, CastMyVote, CastVoteByPollId, GetAllPollResults, GetLatestPoll, GetListOfPolls, GetPollById, GetPollResultById as web methods to the web services interface. This is done by decorating their method declarations with the [WebMethod()] attribute.

A further important step is to specify the XML namespace. The XML namespace identifies your Web Service over the internet. When no XML namespace is provided for the class, .NET provides a default namespace, http://tempuri.org/, which is suitable for testing purposes only to. We give our Web Service a namespace with the following declaration:

[WebService(Namespace="http://mydummydomain.com/webservices/",
                Description="This is demo polling Web Service.")]
public class PollService : System.Web.Services.WebService
{

(Please make sure to be comfortable with the creation of Web Services beforehand as this is a demo project only and this article should not be considered as a complete tutorial for Web Services at all. This article by Chris Maunder would be a very good start.)

The web methods of our Web-Service class look somewhat like this:

namespace pollLogicalLayer.LogicalLayer.DAL
{
    public class PollService : System.Web.Services.WebService
    {
       ......
       [WebMethod()]
       public List<pollservicebo> GetListOfPolls()
       {
         //code to access database, fill the list
         //of PollServiceBO objects and return this list.
         //PollServiceBO is discussed below.
       }
       [WebMethod()]
       public PollServiceBO GetLatestPoll()
       {
         //............
       }
       [WebMethod()]
       public string CastVoteByPollId(string UserId,int PollId,
                                      Int16 SelectedOption)
       {
         .............
       }
       [WebMethod()]
       public PollServiceBO GetPollResultById(int PollId)
       {
         .............
       }
       [WebMethod()]
       public List<pollservicebo> GetAllPollResults()
       {
         ................
       }
       [WebMethod()]
       public PollServiceBO GetPollById(int PollId)
       {
         ..............
       }
       [WebMethod()]
       public int AddPoll(string Question,string option1, 
                  string option2,string option3,string option4)
       {
         .................
       }
       [WebMethod()]
       public string CastMyVote(string UserId, Int16 SelectedOption)
       {
         ...............
       }
    }
}

The above methods take simple parameters as arguments, like int, string, DateTime etc., as these are serializable data-types. The information is returned in the form of objects of the class PollServiceBO. The business object PollServiceBO is kept in the namespace pollLogicalLayer.LogicalLayer.BL. Generally, Web Service business objects are kept separate from the actual business objects. Web Service objects should then instantiate business objects for actual data access operations. The code for the PollServiceBO class is self-explanatory:

public class PollServiceBO 
{
    private int _id;
    private string _question;
    private string _option1;
    private string _option2;
    private string _option3;
    private string _option4;
    private DateTime _dateAdded;
    //the getters and setters for the above fields
}

The default database used for the Database Layer is the SQL Server file poll.mdf kept in the App_Data folder of the application. This layer contains simple Stored Procedures with the same names (AddPoll, CastMyVote, CastVoteByPollId....) as above for fetching/inserting data. The SQL script for the database (pollDb.sql) can be downloaded from above. If the poll database is to be changed to an alternate server, the connection string should be changed accordingly. Please make sure to place some data in the poll database before making a request to fetch. When the server is changed, the connection string can be changed like this:

<connectionStrings>
  <add name="pollConnectionString" 
    connectionString="Data Source={Target Server Name};
        Initial Catalog=poll;Integrated Security=SSPI;Connect Timeout=10"
    providerName="System.Data.OleDb" />
</connectionStrings>

If the application is set up, PollService.asmx can be viewed in the browser like this:

pollservice.gif

All the methods exposed by the Web Service are visible as in the image above. Please make sure to test the Web Service by invoking a web method, before using the UI, e.g., click on GetLatestPoll and press the Invoke button. If the XML response is visible, then the UI layer will be able to fetch the data.

If there is no response when the web method is invoked, please browse Default.aspx which checks the objects directly. The general cause for this is improper access to the database file.

If the XML response is visible but the UI is not able to fetch the data, please correct the location of the Web Service. For example: in the CastMyVote UI, we have the location of the Web Service as:

var url = "http://localhost/poll/PollService.asmx/CastMyVote";

This says that PollService.asmx is hosted in the poll folder on localhost, i.e., it is in the c:\inetput\wwwroot\poll directory. If we want to host it from Visual Studio's inbuilt web server or any other server, the location needs to be changed in all pages. E.g.:

"http://localhost:2080/poll/PollService.asmx/CastMyVote"
//above one is location when my inbuilt web server hosts my website on port 2080
"http://www.my_domain.com/poll/PollService.asmx/CastMyVote"
//this would be location if we host the PollService.asmx
//from a folder named poll in website www.my_domain.com

Index.htm is the start page. Some of the pages are based upon the webservice.htc approach which works for Internet Explorer only.

Note

Please note that this application exposes the functions of the data access layer directly to the UI for demonstration purposes only. The Web Service business objects are kept different from the application business objects. This is because to expose any field of the object returned by a Web Service, we will have to keep it as public read/write field. This is needed to keep this object serializable. We would never want to expose all the fields of our business objects and the methods of the Data Access Layer directly. Hence a more legible approach will have:

public class PollServiceBO
{
    public PollServiceBO(PollBO b)
    {
        this._id = b.ID;
        this._question = b.question;
        this._option1 = b.option1;
        this._option2 = b.option2;
        this._option3 = b.option3;
        this._option4 = b.option4;
        this._dateAdded = b.dateAdded;
    }
    /***** the usual getters and setters ****/
}

And, the Web Service class should use the Data Access Layer and the application business objects to interact with the application (after validation).

[WebService(Namespace="http://mydummydomain.com/webservices/",
            Description="This is demo polling Web Service.")]
public class PollService : System.Web.Services.WebService
{
    [WebMethod(CacheDuration = 30,Description="Returns list of latest 100 polls.")]
    public List<pollserviceBO> GetListOfPolls()
    {
        List<pollserviceBO> polls = PollDAL.GetListOfPolls();
        List<pollserviceBO> returnpolls = new List<pollserviceBO>();
        foreach (PollBO b in polls)
        {
            PollServiceBO pl = new PollServiceBO(b);
            returnpolls.Add(pl);
        }
        return returnpolls;
    }
    ....
}

Authentication, abstraction of the DAL from the UI Layer, and state-management (if required) are a matter of further important consideration.

Further, I have enabled HTTP GET and POST interaction for this application by modifying the Web.config file. I am processing the returned XML response using the UI JavaScript. However, if we do not want to do this and wish to enable session and authentication-authorization for this application, there is a workaround. We will need to create proxy classes using wsdl.exe or using Visual Studio using the Web Reference approach. We will write ASPX pages which consume our Web Service using the proxy classes created above. These ASPX pages collect simple parameters and return the XML response from and to our AJAX enabled UI interface.

The proxy class makes our life very simple as it takes care of generating the correct SOAP messages and sending them over HTTP. It also takes care of converting the response message to the corresponding .NET data types.

For information regarding how the UI layer works, please see the article: Calling a Web Service from an HTML page (for all browsers).

Links

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here