我必须完成10个不同的样本C#项目,这些项目已经过时,不再有效。
我所追求的只是一种基于ISBN或标题来获取图书信息的方法。
亚马逊网络服务网站是一个绝对悲惨的泥潭。
更新
我设法使用this作为起点,并成功完成了基本请求。我将继续寻找其他可能涉及其他详细方案的最新资源。
答案 0 :(得分:3)
适用于.NET的SprightlySoft AWS组件允许您与包括Product Advertising API在内的所有Amazon服务进行交互。以下是查找ISBN的示例代码。在http://sprightlysoft.com/免费获取该组件。
//Product Advertising API, ItemLookup: http://docs.amazonwebservices.com/AWSECommerceService/2010-10-01/DG/ItemLookup.html
SprightlySoftAWS.REST MyREST = new SprightlySoftAWS.REST();
String RequestURL;
RequestURL = "https://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&Operation=ItemLookup&Version=2010-10-01";
RequestURL += "&AWSAccessKeyId=" + System.Uri.EscapeDataString(AWSAccessKeyId) + "&SignatureVersion=2&SignatureMethod=HmacSHA256&Timestamp=" + Uri.EscapeDataString(DateTime.UtcNow.ToString("yyyy-MM-dd\\THH:mm:ss.fff\\Z"));
RequestURL += "&ItemId=9781904233657";
RequestURL += "&IdType=ISBN";
RequestURL += "&SearchIndex=Books";
String RequestMethod;
RequestMethod = "GET";
String SignatureValue;
SignatureValue = MyREST.GetSignatureVersion2Value(RequestURL, RequestMethod, "", AWSSecretAccessKey);
RequestURL += "&Signature=" + System.Uri.EscapeDataString(SignatureValue);
Boolean RetBool;
RetBool = MyREST.MakeRequest(RequestURL, RequestMethod, null);
System.Diagnostics.Debug.Print("");
System.Diagnostics.Debug.Print(MyREST.LogData);
System.Diagnostics.Debug.Print("");
String ResponseMessage = "";
if (RetBool == true)
{
System.Xml.XmlDocument MyXmlDocument;
System.Xml.XmlNamespaceManager MyXmlNamespaceManager;
System.Xml.XmlNode MyXmlNode;
System.Xml.XmlNodeList MyXmlNodeList;
MyXmlDocument = new System.Xml.XmlDocument();
MyXmlDocument.LoadXml(MyREST.ResponseString);
MyXmlNamespaceManager = new System.Xml.XmlNamespaceManager(MyXmlDocument.NameTable);
MyXmlNamespaceManager.AddNamespace("amz", "http://webservices.amazon.com/AWSECommerceService/2010-10-01");
MyXmlNodeList = MyXmlDocument.SelectNodes("amz:ItemLookupResponse/amz:Items/amz:Item", MyXmlNamespaceManager);
if (MyXmlNodeList.Count == 0)
{
ResponseMessage = "No items found.";
}
else
{
foreach (System.Xml.XmlNode ItemXmlNode in MyXmlNodeList)
{
MyXmlNode = ItemXmlNode.SelectSingleNode("amz:ItemAttributes/amz:Title", MyXmlNamespaceManager);
ResponseMessage += "Title = " + MyXmlNode.InnerText;
ResponseMessage += Environment.NewLine;
}
}
MessageBox.Show(ResponseMessage);
}
else
{
ResponseMessage = MyREST.ResponseStringFormatted;
MessageBox.Show(ResponseMessage);
}
答案 1 :(得分:2)
前段时间我写了一个客户端库,用于与亚马逊的ECS(A2S)服务进行通信。似乎亚马逊讨厌他们的开发人员,并不断改变他们的服务名称和框架。好吧,由于Recent API Changes,我的客户现在完全被打破了。
您最好的选择是查看他们的样本here。
祝你好运。他们的API非常庞大,而且已经过时了,但那是两年前的事了。我得到的印象是他们真的迎合了开发人员的企业服务,而不是免费的A2S。
答案 2 :(得分:1)
我也一直在努力(而且我也在学习阶段)。
我发现最好的方法是使用REST api,然后使用Linq to XML将结果解析为我可以使用的自定义结果对象。请原谅长代码粘贴(在此板上的协议上不确定),但想到你想要的一切。其中很大一部分来自亚马逊自己的样本,但网站没有组织,所以我很难再找到它。
// custom class for result item
public class AmazonBookSearchResult
{
public string ASIN;
public string Author;
public string Title;
public Uri DetailPageURL;
public Uri AllCustomerReviews;
}
// I call this with the search terms, returns an IEnumerable of results
public class ItemLookup
{
private const string MY_AWS_ACCESS_KEY_ID = "YOUR KEY";
private const string MY_AWS_SECRET_KEY = "YOUR KEY";
private const string DESTINATION = "ecs.amazonaws.com";
private const string NAMESPACE = "http://webservices.amazon.com/AWSECommerceService/2009-03-31";
public static IEnumerable<AmazonBookSearchResult> AmazonItemLookup(string category, string browseNode, string keyWords)
{
SignedRequestHelper helper = new SignedRequestHelper(MY_AWS_ACCESS_KEY_ID, MY_AWS_SECRET_KEY, DESTINATION);
String requestUrl;
IDictionary<string, string> r1 = new Dictionary<string, String>();
r1["Service"] = "AWSECommerceService";
r1["Version"] = "2009-03-31";
r1["Operation"] = "ItemSearch";
r1["ResponseGroup"] = "ItemAttributes";
r1["SearchIndex"] = category;
r1["Keywords"] = keyWords;
requestUrl = helper.Sign(r1);
XmlDocument xmlDoc = sendRequest(requestUrl);
XDocument doc = XDocument.Load(new XmlNodeReader(xmlDoc));
XNamespace ns = "http://webservices.amazon.com/AWSECommerceService/2009-03-31";
IEnumerable<AmazonBookSearchResult> result =
from items in doc.Element(ns + "ItemSearchResponse").Elements(ns + "Items").Elements(ns + "Item")
select new AmazonBookSearchResult
{
ASIN = (string)items.Element(ns + "ASIN")
};
int count = doc.Element(ns + "ItemSearchResponse").Elements(ns + "Items").Elements(ns + "Item").Count();
return result;
} // end Lookup()
// this is just taken from the amazon sample
private static XmlDocument sendRequest(string url)
{
try
{
WebRequest request = HttpWebRequest.Create(url);
WebResponse response = request.GetResponse();
XmlDocument doc = new XmlDocument();
doc.Load(response.GetResponseStream());
XmlNodeList errorMessageNodes = doc.GetElementsByTagName("Message", NAMESPACE);
if (errorMessageNodes != null && errorMessageNodes.Count > 0)
{
String message = errorMessageNodes.Item(0).InnerText;
throw new Exception("Error " + message);
}
return doc;
}
catch (Exception e)
{
System.Console.WriteLine("Caught Exception: " + e.Message);
System.Console.WriteLine("Stack Trace: " + e.StackTrace);
}
return null;
}// end FetchTitle()
}
class SignedRequestHelper
{
private string endPoint;
private string akid;
private byte[] secret;
private HMAC signer;
private const string REQUEST_URI = "/onca/xml";
private const string REQUEST_METHOD = "GET";
/*
* Use this constructor to create the object. The AWS credentials are available on
* http://aws.amazon.com
*
* The destination is the service end-point for your application:
* US: ecs.amazonaws.com
* JP: ecs.amazonaws.jp
* UK: ecs.amazonaws.co.uk
* DE: ecs.amazonaws.de
* FR: ecs.amazonaws.fr
* CA: ecs.amazonaws.ca
*/
public SignedRequestHelper(string awsAccessKeyId, string awsSecretKey, string destination)
{
this.endPoint = destination.ToLower();
this.akid = awsAccessKeyId;
this.secret = Encoding.UTF8.GetBytes(awsSecretKey);
this.signer = new HMACSHA256(this.secret);
}
/*
* Sign a request in the form of a Dictionary of name-value pairs.
*
* This method returns a complete URL to use. Modifying the returned URL
* in any way invalidates the signature and Amazon will reject the requests.
*/
public string Sign(IDictionary<string, string> request)
{
// Use a SortedDictionary to get the parameters in naturual byte order, as
// required by AWS.
ParamComparer pc = new ParamComparer();
SortedDictionary<string, string> sortedMap = new SortedDictionary<string, string>(request, pc);
// Add the AWSAccessKeyId and Timestamp to the requests.
sortedMap["AWSAccessKeyId"] = this.akid;
sortedMap["Timestamp"] = this.GetTimestamp();
// Get the canonical query string
string canonicalQS = this.ConstructCanonicalQueryString(sortedMap);
// Derive the bytes needs to be signed.
StringBuilder builder = new StringBuilder();
builder.Append(REQUEST_METHOD)
.Append("\n")
.Append(this.endPoint)
.Append("\n")
.Append(REQUEST_URI)
.Append("\n")
.Append(canonicalQS);
string stringToSign = builder.ToString();
byte[] toSign = Encoding.UTF8.GetBytes(stringToSign);
// Compute the signature and convert to Base64.
byte[] sigBytes = signer.ComputeHash(toSign);
string signature = Convert.ToBase64String(sigBytes);
// now construct the complete URL and return to caller.
StringBuilder qsBuilder = new StringBuilder();
qsBuilder.Append("http://")
.Append(this.endPoint)
.Append(REQUEST_URI)
.Append("?")
.Append(canonicalQS)
.Append("&Signature=")
.Append(this.PercentEncodeRfc3986(signature));
return qsBuilder.ToString();
}
/*
* Sign a request in the form of a query string.
*
* This method returns a complete URL to use. Modifying the returned URL
* in any way invalidates the signature and Amazon will reject the requests.
*/
public string Sign(string queryString)
{
IDictionary<string, string> request = this.CreateDictionary(queryString);
return this.Sign(request);
}
/*
* Current time in IS0 8601 format as required by Amazon
*/
private string GetTimestamp()
{
DateTime currentTime = DateTime.UtcNow;
string timestamp = currentTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
return timestamp;
}
/*
* Percent-encode (URL Encode) according to RFC 3986 as required by Amazon.
*
* This is necessary because .NET's HttpUtility.UrlEncode does not encode
* according to the above standard. Also, .NET returns lower-case encoding
* by default and Amazon requires upper-case encoding.
*/
private string PercentEncodeRfc3986(string str)
{
str = HttpUtility.UrlEncode(str, System.Text.Encoding.UTF8);
str = str.Replace("'", "%27").Replace("(", "%28").Replace(")", "%29").Replace("*", "%2A").Replace("!", "%21").Replace("%7e", "~").Replace("+", "%20");
StringBuilder sbuilder = new StringBuilder(str);
for (int i = 0; i < sbuilder.Length; i++)
{
if (sbuilder[i] == '%')
{
if (Char.IsLetter(sbuilder[i + 1]) || Char.IsLetter(sbuilder[i + 2]))
{
sbuilder[i + 1] = Char.ToUpper(sbuilder[i + 1]);
sbuilder[i + 2] = Char.ToUpper(sbuilder[i + 2]);
}
}
}
return sbuilder.ToString();
}
/*
* Convert a query string to corresponding dictionary of name-value pairs.
*/
private IDictionary<string, string> CreateDictionary(string queryString)
{
Dictionary<string, string> map = new Dictionary<string, string>();
string[] requestParams = queryString.Split('&');
for (int i = 0; i < requestParams.Length; i++)
{
if (requestParams[i].Length < 1)
{
continue;
}
char[] sep = { '=' };
string[] param = requestParams[i].Split(sep, 2);
for (int j = 0; j < param.Length; j++)
{
param[j] = HttpUtility.UrlDecode(param[j], System.Text.Encoding.UTF8);
}
switch (param.Length)
{
case 1:
{
if (requestParams[i].Length >= 1)
{
if (requestParams[i].ToCharArray()[0] == '=')
{
map[""] = param[0];
}
else
{
map[param[0]] = "";
}
}
break;
}
case 2:
{
if (!string.IsNullOrEmpty(param[0]))
{
map[param[0]] = param[1];
}
}
break;
}
}
return map;
}
/*
* Consttuct the canonical query string from the sorted parameter map.
*/
private string ConstructCanonicalQueryString(SortedDictionary<string, string> sortedParamMap)
{
StringBuilder builder = new StringBuilder();
if (sortedParamMap.Count == 0)
{
builder.Append("");
return builder.ToString();
}
foreach (KeyValuePair<string, string> kvp in sortedParamMap)
{
builder.Append(this.PercentEncodeRfc3986(kvp.Key));
builder.Append("=");
builder.Append(this.PercentEncodeRfc3986(kvp.Value));
builder.Append("&");
}
string canonicalString = builder.ToString();
canonicalString = canonicalString.Substring(0, canonicalString.Length - 1);
return canonicalString;
}
}
/*
* To help the SortedDictionary order the name-value pairs in the correct way.
*/
class ParamComparer : IComparer<string>
{
public int Compare(string p1, string p2)
{
return string.CompareOrdinal(p1, p2);
}
}
答案 3 :(得分:0)
您可以从亚马逊下载此示例 Product Advertising API Signed Requests Sample Code - C# SOAP WCF 4.0
如果使用SOAP(在本例中),获取所需信息比使用REST要简单得多。
我不认为在这种情况下使用REST比使用SOAP调用更简单,在C#中返回一个格式良好的对象,在该对象中,您可以获得有关产品的所有信息,而无需额外编码。我想现在每个人都在使用REST,因为它很时髦,我只在使用它时更容易集成。对于Amazon Product Advertising API,我宁愿使用SOAP api。