<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog de Jérémie Bertrand &#187; Amazon</title>
	<atom:link href="https://blog.developpez.com/laedit/pcategory/amazon/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/laedit</link>
	<description></description>
	<lastBuildDate>Tue, 22 Mar 2011 14:30:08 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Amazon Product Advertising API en C#</title>
		<link>https://blog.developpez.com/laedit/p9187/c/amazon_product_advertising_api_en_c</link>
		<comments>https://blog.developpez.com/laedit/p9187/c/amazon_product_advertising_api_en_c#comments</comments>
		<pubDate>Sat, 07 Aug 2010 18:37:34 +0000</pubDate>
		<dc:creator><![CDATA[laedit]]></dc:creator>
				<category><![CDATA[Amazon]]></category>
		<category><![CDATA[Articles]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[WebService]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Avez-vous déjà voulu requêter les web services d&#8217;amazon afin de récupérer le titre d&#8217;un film ou d&#8217;un livre ? Si oui, vous vous êtes sûrement déjà confrontés au brouillard de tous les web services amazon afin de trouver le bon, et après il faut encore trouver son nom ( car ils ont tendance à changer ) et à trouver quelques bons exemples de codes encore valable, voire la bonne adresse du WSDL. Après une petite [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Avez-vous déjà voulu requêter les web services d&rsquo;amazon afin de récupérer le titre d&rsquo;un film ou d&rsquo;un livre ?</p>
<p>Si oui, vous vous êtes sûrement déjà confrontés au brouillard de tous les web services amazon afin de trouver le bon, et après il faut encore trouver son nom ( car ils ont tendance à changer ) et à trouver quelques bons exemples de codes encore valable, voire la bonne adresse du WSDL.</p>
<p>Après une petite après-midi de recherche, j&rsquo;ai pu trouver ce que je voulais et arriver au résultat voulu : récupérer toutes les informations d&rsquo;un produit à partir de son code EAN (code-barre).</p>
<p><span id="more-19"></span></p>
<p>Après avoir passé quelques heures sur le site d&rsquo;amazon et m&rsquo;être aperçu que tous les exemples ne sont plus valable, je me suis tourné vers google. Et après quelques recherches infructueuses, j&rsquo;ai trouvé la perle : le code-source et le guide pour réaliser le même code.</p>
<p>Merci Oren Trutner : <a href="https://flyingpies.wordpress.com/2009/08/01/17/">https://flyingpies.wordpress.com/2009/08/01/17/</a></p>
<p>Au passage, il faut se créer un compte pour utiliser les web services d&rsquo;Amazon. Vous pouvez vous en créer un gratuitement à cette adresse : <a href="http://aws.amazon.com/">http://aws.amazon.com/</a> en cliquant sur le lient &laquo;&nbsp;Create an AWS Account&nbsp;&raquo; en haut à droite. Une fois la création effectuée, allez dans Account->Security Credentials et gardez sous la main l&rsquo;Access Key ID et la Secret Access Key dans la partie Access Credentials, vous en aurez besoin par la suite.</p>
<p>Au niveau du code, au début rien de bien compliqué : le WSDL est dispo à l&rsquo;adresse <a href="http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl">http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl</a>.<br />
Il suffit de créer une nouveau projet dans Visual Studio et d&rsquo;ajouter une référence de service avec cette uri, en asynchrone ou non selon vos goûts.<br />
On obtient donc de jolies classes de proxy, que l&rsquo;on peut donc utiliser afin de requêter Amazon.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; class Program <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; // your Amazon ID's <br />
&nbsp; &nbsp; &nbsp; &nbsp; private const string accessKeyId = &quot;AccessKeyId&quot;; <br />
&nbsp; &nbsp; &nbsp; &nbsp; private const string secretKey = &quot;SecretAccessKey&quot;; <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; // the program starts here <br />
&nbsp; &nbsp; &nbsp; &nbsp; static void Main(string[] args) <br />
&nbsp; &nbsp; &nbsp; &nbsp; { <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // create a WCF Amazon ECS client <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AWSECommerceServicePortTypeClient client = new AWSECommerceServicePortTypeClient( <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new BasicHttpBinding(), <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new EndpointAddress(&quot;http://webservices.amazon.com/onca/soap?Service=AWSECommerceService&quot;)); <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // prepare an ItemSearch request <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ItemSearchRequest request = new ItemSearchRequest(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request.SearchIndex = &quot;All&quot;; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request.Keywords = &quot;3700259800655&quot;; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request.ResponseGroup = new String[] { &quot;Large&quot; }; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ItemSearch itemSearch = new ItemSearch(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; itemSearch.Request = new ItemSearchRequest[] { request }; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; itemSearch.AWSAccessKeyId = accessKeyId; <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // issue the ItemSearch request <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ItemSearchResponse response = client.ItemSearch(itemSearch); <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // write out the results <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foreach (var item in response.Items[0].Item) <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine(item.ItemAttributes.Title); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.ReadLine();</div></div>
<p>Pour information, la liste de tous les SearchIndex est ici : <a href="http://docs.amazonwebservices.com/AWSEcommerceService/4-0/ApiReference/SearchIndexValues.html">http://docs.amazonwebservices.com/AWSEcommerceService/4-0/ApiReference/SearchIndexValues.html</a>. Il faut tout de même lui ajouter All, qui correspond à une recherche sur toutes les catégories.</p>
<p>Mais le code précédent ne fonctionne pas. Pas avant d&rsquo;avoir bidouillé un peu. Car ce qu&rsquo;Amazon ne dit pas sur son site (ou alors il fallait chercher pendant encore quelques heures), c&rsquo;est toute la partie authentification des messages SOAP qu&rsquo;il faut mettre en place.<br />
Trois classes vont rendre cela possible :</p>
<ul>
<li>AmazonSigningMessageInspector : implémente IClientMessageInspector et permet de modifier la requête avant son envoi. Elle va donc rajouter les headers.</li>
<li>AmazonSigningEndpointBehavior : implémente IEndpointBehavior et permet d&rsquo;ajouter le bon MessageInspector au bon moment.</li>
<li>AmazonHeader : hérite de MessageHeader et est utilisée par le MessageInspector pour ajouter les headers.</li>
</ul>
<p>Voilà la partie du code de AmazonSigningMessageInspector ajoutant les headers :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; public object BeforeSendRequest(ref Message request, IClientChannel channel) <br />
&nbsp; &nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // prepare the data to sign <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; string operation = Regex.Match(request.Headers.Action, &quot;[^/]+$&quot;).ToString(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DateTime now = DateTime.UtcNow; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; string timestamp = now.ToString(&quot;yyyy-MM-ddTHH:mm:ssZ&quot;); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; string signMe = operation + timestamp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] bytesToSign = Encoding.UTF8.GetBytes(signMe); <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // sign the data <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] secretKeyBytes = Encoding.UTF8.GetBytes(secretKey); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HMAC hmacSha256 = new HMACSHA256(secretKeyBytes); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] hashBytes = hmacSha256.ComputeHash(bytesToSign); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; string signature = Convert.ToBase64String(hashBytes); <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // add the signature information to the request headers <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request.Headers.Add(new AmazonHeader(&quot;AWSAccessKeyId&quot;, accessKeyId)); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request.Headers.Add(new AmazonHeader(&quot;Timestamp&quot;, timestamp)); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request.Headers.Add(new AmazonHeader(&quot;Signature&quot;, signature)); <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return null; <br />
&nbsp; &nbsp; &nbsp; &nbsp; }</div></div>
<p>Cela permettra de mettre en place un header de ce type :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;soap:Header <br />
&nbsp; &nbsp;xmlns:aws=&quot;http://security.amazonaws.com/doc/2007-01-01/&quot;&gt; <br />
&nbsp; &nbsp;&lt;aws:AWSAccessKeyId&gt;YOURACCESSKEYIDHEREX&lt;/aws:AWSAccessKeyId&gt; <br />
&nbsp; &nbsp;&lt;aws:Timestamp&gt;2009-08-15T23:59:59Z&lt;/aws:Timestamp&gt; <br />
&nbsp; &nbsp;&lt;aws:Signature&gt;SZf1CHmQnrZbsrC13hCZS061ywsEXAMPLE&lt;/aws:Signature&gt; <br />
&lt;/soap:Header&gt;</div></div>
<p>Il suffit ensuite de modifier la façon d&rsquo;appeler le web service pour que tout roule :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // create a WCF Amazon ECS client <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; binding.MaxReceivedMessageSize = int.MaxValue; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AWSECommerceServicePortTypeClient client = new AWSECommerceServicePortTypeClient( <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; binding, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new EndpointAddress(&quot;http://webservices.amazon.com/onca/soap?Service=AWSECommerceService&quot;)); <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // add authentication to the ECS client <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; client.ChannelFactory.Endpoint.Behaviors.Add(new AmazonSigningEndpointBehavior(accessKeyId, secretKey));</div></div>
<p>Et afin de pouvoir &laquo;&nbsp;localiser&nbsp;&raquo; les web services, j&rsquo;ai créée une petite classe AmazonEndpointAdress recensant toutes les adresses des endpoint des web services Amazon, accessibles ici : <a href="http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?AnatomyOfaRESTRequest.html">http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?AnatomyOfaRESTRequest.html</a>.<br />
Bien entendu, votre fichier App.config doit comporter tous les endpoint correspondant.<br />
Et au final, le code d&rsquo;appel ressemble à celle-ci :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">AWSECommerceServicePortTypeClient client = new AWSECommerceServicePortTypeClient( <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; binding, <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new EndpointAddress(AmazonEndpointAdresses.FR));</div></div>
<p>Et voilà !</p>
<p>Vous pouvez maintenant rechercher n&rsquo;importe quel produit sur n&rsquo;importe quel site d&rsquo;Amazon !</p>
<p>Les sources sont disponibles ici : <a href="http://laedit.ftp-developpez.com/CSharp/Amazon/AmazonProductAdvtApiWcfSample.zip">http://laedit.ftp-developpez.com/CSharp/Amazon/AmazonProductAdvtApiWcfSample.zip</a>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
