亚马逊产品API - C#中是否有任何有效的,最新的示例?

时间:2010-11-10 23:03:12

标签: c# amazon-web-services

我必须完成10个不同的样本C#项目,这些项目已经过时,不再有效。

我所追求的只是一种基于ISBN或标题来获取图书信息的方法。

亚马逊网络服务网站是一个绝对悲惨的泥潭。

更新

我设法使用this作为起点,并成功完成了基本请求。我将继续寻找其他可能涉及其他详细方案的最新资源。

4 个答案:

答案 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。