Building a Public Address Book Web Service

only for RuBoard

This section shows you how to build a fictitious web service that provides RPC-oriented operations to store and manage users' Address Book Details. Developers can integrate this service into their applications and quickly provide an Address Book Management feature to attract the users of their application. These client application developers in turn can pay a licensing fee to use the Address Book service. (Note that the example provided in this section doesn't cover any of the details regarding licensing.)

The Address Book consists of address entries. Each address entry consists of an individual's name , nickname, email address, phone number, and address. The service defines the AddressEntry object that represents an individual address entry.

Table 11.4 contains the operations provided by the Address Book web service.

Table 11.4. Operations Provided by the Address Book Web Service

Operation

Description

AddUser(userName,password)

token= LogonUser

(userName,password)

Adds an new user .

Authenticates the user's credentials and returns a token if the credentials supplied are valid. For a call with invalid credentials, this operation sends a SOAP fault to the client.

The token is an encrypted string that the client needs to cache and send with all subsequent requests to the web service. This token expires after 20 minutes and the requests to an operation will fail. In such a situation, the client should call the LogonUser() operation to obtain a fresh token and retry the operation with the new token.

addrList = GetAddressList(token)

Returns all the address entries in the user's Address Book.

This operation does not return all the fields in an address entry but only a summary that contains the name, email, and phone number. Other details can be obtained by using the AddAddressEntry() operation for a single address entry.

addrEntry = GetAddressEntry

(token, addrEntryID)

Returns all the details of an address entry, including name, nickname, email, phone number, and address.

AddAddressEntry(token,addrEntry)

Adds a new address entry to the user's Address Book. It checks for a duplicate nickname and sends SOAP fault in the case of a duplicate nickname.

UpdateAddressEntry

(token,addrEntry)

Updates an existing address entry in the user's Address Book. It checks for a duplicate nickname and sends a SOAP fault in the case of a duplicate nickname.

DeleteAddressEntry

(token,addrEntryID)

Deletes an existing address entry in the user's Address Book.

Table 11.5 contains the application specific errors returned by the web service.

Table 11.5. Application-Specific Errors Returned by the Web Service

Error Code

Messsage

Description

1001

Invalid User

This error is sent in the following cases:

  • The client sends an invalid username and password during logon.

  • The token is invalid and expired .

  • During registration, the client sends a username that's already in use.

1002

Duplicate Nickname

This error is sent when the client sends a nickname that already exists.

The Address Book web service stores the data on a SQL Server 7.0 (or later) database. Figure 11.16 shows the two tables, Users and AddressBook , used by this web service.

Figure 11.16. The Users and AddressBook tables in SQL Server.
graphics/11fig16.gif

Listing 11.8 shows the Address Book web service. The code shows the web service class AddressBookService with the two custom SOAP Exception classes and a database configuration information class. The AddressBookService class is designed to handle the business processes and the two classes, AddressEntry and AddressBookUser , represent the business data.

Listing 11.8 The Address Book Web Service ( AddressBookService.asmx )
 <%@ WebService Language="c#" Class="Service.AddressBookService" %>  using System;  using System.Web.Services;  using System.Web.Services.Protocols;  using System.Xml;  namespace Service  { [WebService(Namespace="http://newriders.com/webservices/")]  public class AddressBookService : WebService  { //Add a New Users of the Web service  [WebMethod]  public bool AddUser(string userName,string password)  {      return AddressBookUser.CreateUser(userName, password );  }//AddUser  [WebMethod]  public string LogonUser(string userName,string password)  {      int userID ;       if( (userID = AddressBookUser.Authenticate(userName,password))== 0 )            throw new  InvalidAddressBookUserException(Context.Request.Url.AbsoluteUri);       return AddressBookUser.GetToken( userID );  }//AddUser  [WebMethod]  public bool AddAddressEntry(string token, AddressEntry addrEntry)  {      int userID = 0;       if( ( userID = AddressBookUser.Authenticate(token) )==0)          throw new  InvalidAddressBookUserException(Context.Request.Url.AbsoluteUri);       try       {           if (AddressEntry.Create(  userID,  addrEntry ))            return true;            else            return false;       }       catch(Exception ex )       {           if( ex.Message.Equals("Duplicate Nickname") )                 throw new  DuplicateNickNameException(Context.Request.Url.AbsoluteUri);            else                 throw ex;       }  }  [WebMethod]  public bool UpdateAddressEntry(string token, AddressEntry addrEntry)  {      int userID = 0;       if( ( userID = AddressBookUser.Authenticate(token) )==0)          throw new  InvalidAddressBookUserException(Context.Request.Url.AbsoluteUri);       try       {           if (AddressEntry.Update(  userID,  addrEntry ))                 return true;            else                 return false;       }       catch(Exception ex )       {           if( ex.Message.Equals("Duplicate Nickname") )                 throw new  DuplicateNickNameException(Context.Request.Url.AbsoluteUri);            else                 throw ex;       }  }  [WebMethod]  public bool DeleteAddressEntry(string token, int addrEntryID )  {      int userID = 0;       if( ( userID = AddressBookUser.Authenticate(token) )==0)            throw new  InvalidAddressBookUserException(Context.Request.Url.AbsoluteUri);       if (AddressEntry.Delete( userID, addrEntryID ))            return true;       else            return false;  }  [WebMethod]  public AddressEntry GetAddressEntry(string token, int addrEntryID)  {      if(  AddressBookUser.Authenticate(token) == 0 )            throw new  InvalidAddressBookUserException(Context.Request.Url.AbsoluteUri);       return new AddressEntry( addrEntryID ) ;  }  [WebMethod]  public AddressEntry[] GetAddressList(string token)  {      int userID = 0;       if( ( userID = AddressBookUser.Authenticate(token) )==0)            throw new  InvalidAddressBookUserException(Context.Request.Url.AbsoluteUri);       return  AddressEntry.GetAddressList(userID );  }  }       //Database configuration details       public class DBConfig       {           public static string CONNECT_STRING            {                get                 {                     return  "Server=NewRiders;uid=sa;pwd=;database=AddressBook";                 }            }       }       //Exception thrown on Invalid Logon credentials or an Expired Token       public class InvalidAddressBookUserException : SoapException       {           private static XmlNode node;            static InvalidAddressBookUserException()            {           XmlDocument doc = new System.Xml.XmlDocument();            node = doc.CreateNode(XmlNodeType.Element,                 SoapException.DetailElementName.Name,                 SoapException.DetailElementName.Namespace);            //node.InnerText = "Invalid User";            node.InnerXml =            "<e:myfaultdetails xmlns:e='http://newriders.com/webservices/addressbook/ graphics/ccc.gif faults' >"            +"     <message>Invalid User</message>"            +"        <errorcode>1001</errorcode>"            +"</e:myfaultdetails>";            }            public InvalidAddressBookUserException(string actor):             base("Invalid User", SoapException.ClientFaultCode,actor,node )            {           }       }       //Exception thrown for a create request with an already existing       //NickName       public class DuplicateNickNameException : SoapException       {           private static XmlNode node;            static DuplicateNickNameException()            {           XmlDocument doc = new System.Xml.XmlDocument();            node = doc.CreateNode(XmlNodeType.Element,                 SoapException.DetailElementName.Name,                 SoapException.DetailElementName.Namespace);            //node.InnerText = "Duplicate Nickname";            node.InnerXml =            "<e:myfaultdetails xmlns:e='http://newriders.com/webservices/addressbook/ graphics/ccc.gif faults' >"            +"     <message>Duplicate Nickname</message>"            +"        <errorcode>1002</errorcode>"            +"</e:myfaultdetails>";            }            public DuplicateNickNameException(string actor):             base("Duplicate Nickname", SoapException.ClientFaultCode,actor,node )            {           }       }  } 

The preceding two custom SOAP Exception classes, InvalidAddressBookUser Exception and DuplicateNickNameException inherits from the System.Web. Services.Protocols.SoapException class and creates the application-specific error information in the detail element within the SOAP Fault element.

Listing 11.9 shows the AddressBookUser class used by the web service for user management and authentication.

Listing 11.9 The AddressBookUser Class ( AddressBookUser.cs )
 using System;  using System.Data.SqlClient ;  using System.Web.Services.Protocols;  namespace Service  { public class AddressBookUser  { //Create new User with a unique userName  public static bool CreateUser(string userName,string password)  {      bool created = false ;       SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);       SqlCommand command  = conn.CreateCommand();       command.CommandText = "SELECT count(*) FROM Users WHERE UserName='"+userName+"'";       conn.Open();       if (  (int) command.ExecuteScalar() == 0   )       {           //Add the User            command.CommandText =  "INSERT INTO Users  (UserName,Password) VALUES "                 + "('"+ userName +"','"+ password +"')";            command.ExecuteNonQuery();            created = true;       }       command.Dispose();       conn.Close();       return created;  }  //Authenticate user credentials  public static int Authenticate(string userName,string password)  {      int userID = 0;       SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);       SqlCommand command  = conn.CreateCommand();       command.CommandText = "SELECT UserID FROM Users WHERE  UserName='"+userName+"'"            + "AND Password= '"+password+"'";       conn.Open();       SqlDataReader reader = command.ExecuteReader();       if( reader.Read() )       {           userID = reader.GetInt32(0);       }       reader.Close();       conn.Close();       return  userID;  }  //Authenticate user credentials using the token and check for an expired  //token  public static int Authenticate(string token )  {      int userID = 0;       token = Decrypt(token);       DateTime dtToken = Convert.ToDateTime(token);       DateTime dtNow = DateTime.Now;       if(     dtNow.Subtract(dtToken).TotalMinutes > 20  )//expire after 20 mins       {           return userID;       }       Object tempID ;       SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);       SqlCommand command  = conn.CreateCommand();       command.CommandText = "SELECT UserID FROM Users WHERE Token='"+token+"'";       conn.Open();       tempID =  command.ExecuteScalar();       if (tempID!=null)       {           userID = (int) tempID;       }       conn.Close();       return  userID;  }  //Fetch a fresh token  public static string GetToken( int  userID )  {      //For the token you can use the combination       //"System.DateTime.Now.ToString()+userName+password"       //to make it unique and secure. Here we only use the current time       string token = Encrypt(System.DateTime.Now.ToString() );       SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);       SqlCommand command  = conn.CreateCommand();       command.CommandText = "UPDATE Users SET Token = '"+ token +"'"            + "WHERE  UserID= "+ userID  +" ";       conn.Open();       command.ExecuteNonQuery();       conn.Close();       return token;  }  private static string Encrypt(string str)  {     //Add  your Encryption logic here       return str;  }  private static string Decrypt(string str)  {     //Add  your Decryption logic here       return str;  }  }  } 

Listing 11.10 shows the AddressEntry class that implements the operations related to the address entries in the Address Book.

Listing 11.10 The AddressEntry Class ( AddressEntry.cs )
 using System;  using System.Data.SqlClient;  namespace Service  { public class AddressEntry  {   public int EntryID = 0;    public string NickName;    public string FirstName;    public string LastName;    public string EmailID;    public string Phone;    public Location AddrLocation;  //Default public constrcutor essential for searlization  public     AddressEntry()  { }  public AddressEntry(int entryID)  { SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);  SqlCommand command  = conn.CreateCommand();  command.CommandText = "SELECT * FROM AddressBook WHERE AddressEntryID='"+entryID +"'";  conn.Open();  SqlDataReader reader = command.ExecuteReader();  if(reader.Read() )  {      this.EntryID     = entryID;       NickName = reader.GetString(2);       FirstName        =  reader.IsDBNull(3)? null:reader.GetString(3);       LastName =  reader.IsDBNull(4)? null:reader.GetString(4);       EmailID      =  reader.IsDBNull(5)? null:reader.GetString(5);       Phone            =  reader.IsDBNull(6)? null:reader.GetString(6);       AddrLocation = new Location();       AddrLocation.Street  =  reader.IsDBNull(7)? null:reader.GetString(7);       AddrLocation.City    =  reader.IsDBNull(8)? null:reader.GetString(8);       AddrLocation.State   =  reader.IsDBNull(9)? null:reader.GetString(9);       AddrLocation.Zip     =  reader.IsDBNull(10)? null:reader.GetString(10);       AddrLocation.Country =  reader.IsDBNull(11)? null:reader.GetString(11);  }  reader.Close();  conn.Close();  if( this.EntryID == 0 )       throw new Exception("Invalid EntryID.");  }  //Create a new Address Entry  public static bool Create( int userID, AddressEntry addrEntry  )  { Location loc = addrEntry.AddrLocation ;  String sql;  SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);  SqlCommand command  = conn.CreateCommand();  command.CommandText = "SELECT Count(*) FROM AddressBook WHERE UserID='"+userID +"'"       +" AND  NickName= '"+ addrEntry.NickName +"'   ";  conn.Open();  if     ( (int) command.ExecuteScalar() > 0 )  {      conn.Close();       throw new Exception("Duplicate Nickname");  }  if (loc != null)  {      sql = "INSERT INTO  AddressBook"            +  "(UserID,NickName,FirstName,LastName,EmailID,Phone,Street,City,State,Zip,Country )"            + "VALUES ("+userID+",'"+addrEntry.NickName+"','"+addrEntry.FirstName+"',"            + "'"+ addrEntry.LastName +"','"+addrEntry.EmailID +"','"+ addrEntry.Phone+ "', graphics/ccc.gif "            + "'"+ loc.Street +"','"+ loc.City  +"','"+ loc.State +"','"+loc.Zip +"','"  + loc.Country +"'  )";  }  else  {      sql = "INSERT INTO  AddressBook"            + "(UserID,NickName,FirstName,LastName,EmailID,Phone )"            + "VALUES ("+userID+",'"+addrEntry.NickName+"','"+addrEntry.FirstName+"',"            + "'"+ addrEntry.LastName +"','"+addrEntry.EmailID +"','"+addrEntry.Phone +"' graphics/ccc.gif )" ;  }  command.CommandText = sql;  command.ExecuteNonQuery();  conn.Close();  return true;  }  //Update existing Address Entry  public static bool Update( int userID, AddressEntry addrEntry  )  { Location loc = addrEntry.AddrLocation ;  String sql;  SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);  SqlCommand command  = conn.CreateCommand();  command.CommandText = "SELECT Count(*) FROM AddressBook WHERE UserID='"+ userID +"'"       +" AND  AddressEntryID != '"+ addrEntry.EntryID +"' AND  NickName= '"+ graphics/ccc.gif addrEntry.NickName +"'";  conn.Open();  if     ( (int) command.ExecuteScalar() > 0 )  {      conn.Close();       throw new Exception("Duplicate NickName");  }  if (loc != null)  {      sql = "UPDATE AddressBook "            + " SET NickName = '"+addrEntry.NickName+"', FirstName = graphics/ccc.gif '"+addrEntry.FirstName+"',"            + " LastName     = '"+ addrEntry.LastName +"' ,EmailID = '"+addrEntry.EmailID graphics/ccc.gif +"',"            + " Phone ='"+ addrEntry.Phone+ "', Street= '"+ loc.Street +"',"            + " City     = '"+ loc.City  +"' ,State = '"+ loc.State +"' ,Zip= '"+ loc.Zip graphics/ccc.gif +"',"            + " Country = '"+ loc.Country +"'"            + " WHERE UserID = '"+ userID +"' AND AddressEntryID = '"+addrEntry.EntryID graphics/ccc.gif +"'";  }  else  {      sql = "UPDATE AddressBook"            + " SET NickName = '"+addrEntry.NickName+"', FirstName = graphics/ccc.gif '"+addrEntry.FirstName+"',"            + " LastName     = '"+ addrEntry.LastName +"' ,EmailID = '"+addrEntry.EmailID graphics/ccc.gif +"',"            + " Phone ='"+ addrEntry.Phone+ "',"            + " WHERE UserID = '"+ userID +"' AND AddressEntryID = '"+addrEntry.EntryID graphics/ccc.gif +"'";  }  command.CommandText = sql;  command.ExecuteNonQuery();  conn.Close();  return true;  }  //Delete existing Address Entry  public static bool Delete( int userID, int entryID  )  {      SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);       SqlCommand command  = conn.CreateCommand();       command.CommandText = "DELETE FROM AddressBook WHERE UserID='"+ userID+"'"            +" AND  AddressEntryID = '"+ entryID +"'   ";       conn.Open();       command.ExecuteNonQuery();       conn.Close();       return true;  }  //Get all existing Address entires for a specific user  public static AddressEntry[] GetAddressList(int userID)  {      AddressEntry[] addressList = null ;       int addrCount = 0;       SqlConnection conn = new SqlConnection(DBConfig.CONNECT_STRING);       SqlCommand command  = conn.CreateCommand();       command.CommandText = "SELECT Count(*) FROM AddressBook WHERE UserID='"+userID +"'";       conn.Open();       addrCount =     (int) command.ExecuteScalar();       if( addrCount != 0 )       {           addressList = new AddressEntry[addrCount];            command.CommandText = "SELECT AddressEntryID,NickName,FirstName,LastName, graphics/ccc.gif EmailID,"            + "Phone FROM AddressBook WHERE UserID='"+ userID +"' ORDER BY NickName"     ;            SqlDataReader reader = command.ExecuteReader();            int i=0;            while( reader.Read() )            {                addressList[i] = new AddressEntry();                 addressList[i].EntryID   = reader.GetInt32(0);                 addressList[i].NickName  = reader.GetString(1);                 addressList[i].FirstName = reader.IsDBNull(2)?  null:reader.GetString(2);                 addressList[i].LastName  = reader.IsDBNull(3)?  null:reader.GetString(3);                 addressList[i].EmailID   = reader.IsDBNull(4)?  null:reader.GetString(4);                 addressList[i++].Phone   = reader.IsDBNull(5)?  null:reader.GetString(5);            }            reader.Close();       }       conn.Close();       return addressList;  }  }  public class Location  { public string Street;  public string City;  public string State;  public string Zip;  public string Country;  }  } 
only for RuBoard


XML and ASP. NET
XML and ASP.NET
ISBN: B000H2MXOM
EAN: N/A
Year: 2005
Pages: 184

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net