C# //将AWSAccessKeyId和时间戳添加到请求中。 sortedMap[“AWSAccessKeyId”]=this.akid; sortedMap[“Timestamp”]=this.GetTimestamp(); //获取规范查询字符串 字符串canonicalQS=this.constructionCanonicalQueryString(sortedMap); //派生需要签名的字节。 StringBuilder=新的StringBuilder(); builder.Append(请求\方法) .Append(“\n”) .Append(this.endPoint) .Append(“\n”) .Append(请求\ URI) .Append(“\n”) .附加(规范); 字符串stringToSign=builder.ToString(); 字节[]toSign=Encoding.UTF8.GetBytes(stringToSign); //计算签名并转换为Base64。 字节[]sigBytes=signer.ComputeHash(toSign); 字符串签名=Convert.ToBase64String(sigBytes); //现在构造完整的URL并返回给调用者。 StringBuilder qsBuilder=新的StringBuilder(); qsBuilder.Append(“http://”) .Append(this.endPoint) .Append(请求\ URI) .附加(“?”) .Append(canonicalQS) .Append(“&Signature=”) .附加(此.RFC3986(签名)); 返回qsBuilder.ToString(); } /* *以查询字符串的形式对请求进行签名。 * *此方法返回要使用的完整URL。修改返回的URL *无论如何,签名无效,亚马逊将拒绝这些请求。 */ 公共字符串符号(字符串查询字符串) { IDictionary请求=this.CreateDictionary(queryString); 返回此。签名(请求); } /* *亚马逊要求的IS0 8601格式的当前时间 */ 私有字符串GetTimestamp() { DateTime currentTime=DateTime.UtcNow; 字符串时间戳=currentTime.ToString(“yyyy-MM-ddTHH:MM:ssZ”); 返回时间戳; } /* *亚马逊要求按照RFC 3986进行百分比编码(URL编码)。 * *这是必要的,因为.NET的HttpUtility.UrlEncode不进行编码 *根据上述标准。此外,.NET还返回小写编码 *默认情况下,Amazon需要大写编码。 */ 私有字符串PercentEncoderRFC3986(字符串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=新StringBuilder(str); for(int i=0;i
您可以从Amazon下载此示例 如果您使用SOAP(在本例中),那么获得所需信息将比使用REST简单得多 我不认为在这种情况下使用REST比使用SOAP调用更简单,SOAP调用在C#中返回一个格式良好的对象,您可以在其中获取所有信息C# //将AWSAccessKeyId和时间戳添加到请求中。 sortedMap[“AWSAccessKeyId”]=this.akid; sortedMap[“Timestamp”]=this.GetTimestamp(); //获取规范查询字符串 字符串canonicalQS=this.constructionCanonicalQueryString(sortedMap); //派生需要签名的字节。 StringBuilder=新的StringBuilder(); builder.Append(请求\方法) .Append(“\n”) .Append(this.endPoint) .Append(“\n”) .Append(请求\ URI) .Append(“\n”) .附加(规范); 字符串stringToSign=builder.ToString(); 字节[]toSign=Encoding.UTF8.GetBytes(stringToSign); //计算签名并转换为Base64。 字节[]sigBytes=signer.ComputeHash(toSign); 字符串签名=Convert.ToBase64String(sigBytes); //现在构造完整的URL并返回给调用者。 StringBuilder qsBuilder=新的StringBuilder(); qsBuilder.Append(“http://”) .Append(this.endPoint) .Append(请求\ URI) .附加(“?”) .Append(canonicalQS) .Append(“&Signature=”) .附加(此.RFC3986(签名)); 返回qsBuilder.ToString(); } /* *以查询字符串的形式对请求进行签名。 * *此方法返回要使用的完整URL。修改返回的URL *无论如何,签名无效,亚马逊将拒绝这些请求。 */ 公共字符串符号(字符串查询字符串) { IDictionary请求=this.CreateDictionary(queryString); 返回此。签名(请求); } /* *亚马逊要求的IS0 8601格式的当前时间 */ 私有字符串GetTimestamp() { DateTime currentTime=DateTime.UtcNow; 字符串时间戳=currentTime.ToString(“yyyy-MM-ddTHH:MM:ssZ”); 返回时间戳; } /* *亚马逊要求按照RFC 3986进行百分比编码(URL编码)。 * *这是必要的,因为.NET的HttpUtility.UrlEncode不进行编码 *根据上述标准。此外,.NET还返回小写编码 *默认情况下,Amazon需要大写编码。 */ 私有字符串PercentEncoderRFC3986(字符串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=新StringBuilder(str); for(int i=0;i,c#,amazon-web-services,C#,Amazon Web Services,您可以从Amazon下载此示例 如果您使用SOAP(在本例中),那么获得所需信息将比使用REST简单得多 我不认为在这种情况下使用REST比使用SOAP调用更简单,SOAP调用在C#中返回一个格式良好的对象,您可以在其中获取所有信息 //Product Advertising API, ItemLookup: http://docs.amazonwebservices.com/AWSECommerceService/2010-10-01/DG/ItemLookup.html Sprightl
//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);
}
// 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);
}
}