Abstraction
Dto.BaseDto: This class abstracts the common properties and
methods for serialization and de-serialization.
Request Classes
Dto.Request: The data being requested is stored in the
Request class. It also encapsulates the logic to build the ItemLookupRequest.
The ResponseGroup property specifies a list of properties that need to be
present in the response like editorial review, price, etc. The advantage of
this is that only specific parameters can be queried, thus avoiding information
overload. Note that the ItemLookupRequestIdType.ASIN is used here. Amazon.com
used an ASIN to identify any item that is listed on their site.
Listing 1 – Building the ItemLookupRequest
[XmlInclude(typeof(Request)), XmlInclude(typeof(ISBNRequest))]
public class Request: Base
{
[XmlElement("Keywords", typeof(string))]
public string m_keywords = string.Empty;
[XmlElement("SearchKey", typeof(string))]
public string m_searchKey = string.Empty;
protected webservices.amazon.com.ItemLookupRequest m_itemLookupRequest = new
webservices.amazon.com.ItemLookupRequest();
public Request()
{
}
public Request(string keywords)
{
this.m_keywords = keywords;
}
public Request(string keywords, string key)
{
this.m_keywords = keywords;
this.m_searchKey = key;
}
[XmlIgnore]
public virtual webservices.amazon.com.ItemLookupRequest AWSItemLookupRequest
{
get
{
m_itemLookupRequest.Condition = webservices.amazon.com.Condition.All;
m_itemLookupRequest.MerchantId = "All";
string[]responseGroup =
{
"ItemAttributes", "Offers", "EditorialReview"
};
m_itemLookupRequest.ResponseGroup = responseGroup;
this.m_itemLookupRequest.IdType =
webservices.amazon.com.ItemLookupRequestIdType.ASIN;
this.m_itemLookupRequest.IdTypeSpecified = true;
string[]keywords =
{
this.m_keywords
};
this.m_itemLookupRequest.ItemId = keywords;
return this.m_itemLookupRequest;
}
}
}
Dto.ISBNRequest: If the data being requested is an ISBN for
a book, it is stored in the ISBNRequest class. It is quite similar to the
Request except for the validation of ISBN and the ItemLookupRequestIdType.ISBN.
This indicates that the item being requested is a book whose ISBN has been
supplied as a keyword.
Listing 2 – Building the ItemLookupRequest
[XmlInclude(typeof(ISBNRequest))]
public class ISBNRequest: Request
{
public ISBNRequest()
{
this.m_searchKey = System.Configuration.ConfigurationManager.AppSettings[
"AmazonWS.BookSearch.Key"];
}
public ISBNRequest(string isbn)
{
this.m_keywords = isbn;
this.m_searchKey = System.Configuration.ConfigurationManager.AppSettings[
"AmazonWS.BookSearch.Key"];
this.m_isvalid = ValidateISBN();
}
[XmlIgnore]
public override webservices.amazon.com.ItemLookupRequest AWSItemLookupRequest
{
get
{
this.m_itemLookupRequest = base.AWSItemLookupRequest;
this.m_itemLookupRequest.SearchIndex = this.m_searchKey;
this.m_itemLookupRequest.IdType =
webservices.amazon.com.ItemLookupRequestIdType.ISBN;
this.m_itemLookupRequest.IdTypeSpecified = true;
return this.m_itemLookupRequest;
}
}
…
}
Dto. RequestList: Multiple requests are sent in
List<Request> class. Its constructor takes in a serialized xml version of
the RequestList and encapsulates the logic to build the ItemLookupRequest[]. If
the request is of type ISBNRequest, the ISBN validation is done after
deserialization. This needs to be done as the ISBN validation in the
ISBNRequest constructor does not get called during deserialization.
Listing 3
[XmlRoot("RequestList", Namespace = "")][XmlInclude(typeof(List < Request > ))]
public class RequestList: List < Request >
{
…
public RequestList(string xml)
{
List < Request > listReq = (List < Request > )Base.Deserialize(xml,
this.GetType());
foreach (Request request in listReq)
{
if (request is ISBNRequest)
if (((ISBNRequest)request).ValidateISBN())
request.m_isvalid = true;
else
throw new ApplicationException("Invalid ISBN '" + request.m_keywords
+ "' supplied");
this.Add(request);
}
}
}
Response Classes
Dto.AWSResponse: This class builds the List<Response>
and the List<ReturnMg>. The SetAWSREsponse method checks for errors in
the ItemLookupResponse and adds them to the List<ReturnMg>. If no errors
are found, the List<Response> is constructed and a success message is
added to the List<ReturnMg>.
Listing 4 – Building the AWSResponse
public class AWSResponse
{
[XmlElement("Response")]
public ResponseList m_responseList = new ResponseList();
[XmlElement("RetMsg")]
public ReturnMsgList m_returnMsg = new ReturnMsgList();
… public void SetAWSResponse(webservices.amazon.com.ItemLookupResponse
itemLookupResponse)
{
if (itemLookupResponse.OperationRequest.Errors == null ||
itemLookupResponse.OperationRequest.Errors.Length == 0)
{
bool errorsFound = false;
for (int i = 0; i < itemLookupResponse.Items.Length; i++)
{
if (itemLookupResponse.Items[i].Item != null)
{
this.m_responseList = new ResponseList
(itemLookupResponse.Items[i].Item);
}
else
{
// Request Level Errors
foreach (webservices.amazon.com.ErrorsError error in
itemLookupResponse.Items[i].Request.Errors)
{
errorsFound = true;
System.Diagnostics.Trace.WriteLine("Errors found in response. ");
this.m_returnMsg.Add(new ReturnMsg("Error", error.Code + " - " +
error.Message));
}
}
}
if (!errorsFound)
{
System.Diagnostics.Trace.WriteLine("Search was successful. ");
this.m_returnMsg.Add(new ReturnMsg("Success", "Search was successful"));
}
}
else
{
// Operation Level Errors
foreach (webservices.amazon.com.ErrorsError error in
itemLookupResponse.OperationRequest.Errors)
{
System.Diagnostics.Trace.WriteLine("Errors found in response. ");
this.m_returnMsg.Add(new ReturnMsg("Error", error.Code + " - " +
error.Message));
}
}
}
}
…
}
Dto.ResponseList: Responses for multiple requests are
returned in the List<Response> class. It encapsulates the logic to parse
the Item in the ItemLookupResponse and populate the required values such as
ItemAttributes, Offers and EditorialReview into the Response.
Listing 5 – Retrieve the Items from the
ItemLookupResponse
public class ResponseList: List < Response >
{
…
public ResponseList(webservices.amazon.com.Item[]items)
{
for (int j = 0; j < items.Length; j++)
{
Response response = new Response();
response.m_awsItemAttributes = items[j].ItemAttributes;
response.m_awsOffers = items[j].Offers;
response.m_awsEditorialReviews = items[j].EditorialReviews;
response.SetAWSResponse();
this.Add(response);
}
}
}
Dto.Response: The Response class extracts the values from
the ItemLookupResponse and populates itself. As the code below shows, the
author, publisher and title are contained in the ItemAttributes. The price is
contained in the Offers. The editorial reviews are contained in the
EditorialReview.
Listing 6 – Parsing the ItemAttributes: Attributes,
Price, Reviews
public class Response: Base
{
…[XmlIgnore]
public webservices.amazon.com.ItemAttributes m_awsItemAttributes = null;
[XmlIgnore]
public webservices.amazon.com.Offers m_awsOffers = null;
[XmlIgnore]
public webservices.amazon.com.EditorialReview[]m_awsEditorialReviews = null;
…
public void SetAWSResponse()
{
if (this.m_awsItemAttributes != null)
{
this.m_title = (this.m_awsItemAttributes.Title != null) ?
this.m_awsItemAttributes.Title : string.Empty;
if (this.m_awsItemAttributes.Author != null)
{
for (int aCount = 0; aCount < this.m_awsItemAttributes.Author.Length;
aCount++)
this.m_author += this.m_awsItemAttributes.Author[aCount] + ", ";
this.m_author = this.m_author.Substring(0, this.m_author.Length - 2);
}
this.m_publisher = (this.m_awsItemAttributes.Manufacturer != null) ?
this.m_awsItemAttributes.Manufacturer : string.Empty;
if (this.m_awsOffers != null && this.m_awsOffers.Offer != null &&
this.m_awsOffers.Offer[0].OfferListing != null &&
this.m_awsOffers.Offer[0].OfferListing[0].Price != null)
{
this.m_price = (this.m_awsOffers.Offer[0].OfferListing[0].Price != null)
? this.m_awsOffers.Offer[0].OfferListing[0].Price.FormattedPrice:
string.Empty;
}
if (this.m_awsEditorialReviews != null)
{
this.m_editorialReview = this.m_awsEditorialReviews[0].Content;
}
}
…
}
Dto.ReturnMg: This class encapsulates the return messages
from AWS. In case of errors it will contain the error message. In case of a
successful call to AWS it contains a success message.
Dto.List<ReturnMsg>: This is a list of return
messages.
Utility Class
Util.AWSSearch: This class has a Search method that does the
following tasks.
1.
Makes a call to the AWSECommerceService which is the AWS web service
instance
2.
Instantiates the ItemLookup
3.
Populates the ItemLookupRequest[] from the List<Request> and
assigns it to the ItemLookup.Request property
4.
Invokes the AWSECommerceService.ItemLookup webmethod and gets back the
ItemLookupResponse
5.
It parses the ItemLookupResponse using the core ASWS classes, populates the
AWSResponse and returns it.
Listing 7
public class AWSSearch
{
…
public AWSResponse Search()
{
AWSResponse awsResponse = new AWSResponse();
try
{
if (m_requestList != null && m_requestList.Count > 0)
{
webservices.amazon.com.AWSECommerceService acs = new
webservices.amazon.com.AWSECommerceService();
webservices.amazon.com.ItemLookup itemLookup = new
webservices.amazon.com.ItemLookup();
itemLookup.AWSAccessKeyId = m_accessKeyID;
webservices.amazon.com.ItemLookupRequest[]itemLookupRequests = new
webservices.amazon.com.ItemLookupRequest[m_requestList.Count];
for (int i = 0; i < this.m_requestList.Count; i++)
{
if (m_requestList[i]is ISBNRequest)
{
ISBNRequest isbnRequest = (ISBNRequest)m_requestList[i];
itemLookupRequests[i] = isbnRequest.AWSItemLookupRequest;
}
else
{
itemLookupRequests[i] = m_requestList[i].AWSItemLookupRequest;
}
}
itemLookup.Request = itemLookupRequests;
webservices.amazon.com.ItemLookupResponse itemLookupResponse =
acs.ItemLookup(itemLookup);
awsResponse.SetAWSResponse(itemLookupResponse);
}
else
{
// Request Empty Error
awsResponse.m_returnMsg.Add(new ReturnMsg("Error",
"No requests where processed."));
}
}
catch (Exception e)
{
System.Diagnostics.Trace.WriteLine(
"An error occured when trying to Search. " + e.Message + " " +
e.StackTrace);
awsResponse.m_returnMsg.Add(new ReturnMsg("Error", e.Message));
}
return awsResponse;
}
}
AmazonWebSearch Web Service: The web service has two main
web methods.
Search(List<Request>): This web method accepts a
List< Request> class and returns a AWSResponse. Any ASP.NET based thin
client can call this web method, pass the List<Request> as input and get
the AWSResponse as output.
SearchXml(string): This web method accepts an xml string
input which is the serialized version of the List< Request> class. The
xml is deserialized and passed to Search(List<Request> web method. The
AWSResponse that is returned is serialized and returned. Any thin client
irrespective of the platform can use this web method. This web method was
tested with a PDA that had a J2ME (Java 2 Micro Edition) based application
running.