how to remove duplication from this c# code block - c#

I wrote this code but during code review process it was suggested that this is duplicate code and I need to remove code duplication from this code. Can anyone suggest how I can make this code better to avoid duplication.
private void ShowHideEmailContents(string email, string email2, string format, string tooltip, bool isReadOnly)
{
if (isReadOnly)
{
hlEmail.NavigateUrl = string.Format(format, email);
hlEmail2.NavigateUrl = string.Format(format, email2);
hlEmail.Text = email;
hlEmail2.Text = email2;
hlEmail.ToolTip = tooltip;
hlEmail2.ToolTip = tooltip;
hlEmail.Visible = isReadOnly;
hlEmail2.Visible = isReadOnly;
txtEmail.Visible = !isReadOnly;
txtEmail2.Visible = !isReadOnly;
}
else
{
txtEmail.Text = email;
txtEmail2.Text = email2;
}
}

Note that the duplication exists because you do the same things twice, just on different objects.
To fix that, create a new method which does those things only once:
private static void ShowHideEmailContents(?? hl, ?? txt, string email, string format, string tooltip, bool isReadOnly)
{
if (isReadOnly)
{
hl.NavigateUrl = string.Format(format, email);
hl.Text = email;
...
}
else
{
txt.Text = email;
}
}
and call it twice:
private void ShowHideEmailContents(string email, string email2, string format, string tooltip, bool isReadOnly)
{
ShowHideEmailContents(hlEmail, txtEmail, email, format, tooltip, isReadOnly);
ShowHideEmailContents(hlEmail2, txtEmail2, email2, format, tooltip, isReadOnly);
}

You can minimise the number of parameters that you pass by encapsulating the logic to set the email object's properties in a class:
public sealed class EmailOptionsSetter
{
readonly string _tooltip;
readonly string _format;
readonly bool _isReadOnly;
public EmailOptionsSetter(string tooltip, string format, bool isReadOnly)
{
_tooltip = tooltip;
_format = format;
_isReadOnly = isReadOnly;
}
public void SetOptions(YourEmailType emailObj, string email)
{
emailObj.NavigateUrl = string.Format(_format, email);
emailObj.Text = email;
emailObj.ToolTip = _tooltip;
emailObj.Visible = _isReadOnly;
}
}
Then you can call it like this:
private void ShowHideEmailContents(string email, string email2, string format, string tooltip, bool isReadOnly)
{
if (isReadOnly)
{
var optionsSetter = new EmailOptionsSetter(tooltip, format, isReadOnly);
optionsSetter.SetOptions(hlEmail, email);
optionsSetter.SetOptions(hlEmail2, email2);
txtEmail.Visible = !isReadOnly;
txtEmail2.Visible = !isReadOnly;
}
else
{
txtEmail.Text = email;
txtEmail2.Text = email2;
}
}

Related

Sending email notification upon error in C#

I set up this try/catch and I want to send an error to my email when something goes wrong like an invalid password being entered. I know I have most of it right but I'm not getting an email when I force a change in my config file. I'm not getting any errors when I run this so I'm assuming it must be something small. Does anyone see any obvious errors I've made? Let me know if additional info is required.
Thanks in advance...learning tons of C# but no master just yet.
try
{
_arrivals = new ArrivalsService();
_configuration = new Configuration(xmlMessage);
//process summary or detail
if (_configuration.IncludeHODetails == true)
{
throw new Exception("Include HOH Details is a future feature.");
//ProcessArrivalDetails(_configuration);
}
else
ProcessArrivalSummary(_configuration);
UpdateLastRunDate(_configuration.ClientId, _configuration.LastRunDateId, DateTime.Now);
}
catch (Exception ex)
{
if (_configuration == null)
{
string[] messageTo = new[] { "aaaaaaaaaaaa#gmail.com" };
//string acctManagerEmail = Util.usp_GetEmailAcct(_clientId);
//string[] messageTo = new[] { "77777777777.com", acctManagerEmail };
EmailUtility.SendEmail(Util.EMAIL_FROM, messageTo,
"Error Running Report Utility for Client: " + _configuration.DbName, "Error Message: " + ex.Message,
Util.SMTP_SERVER, false);
}
throw new Exception("Error Occurred");
}
Here's my EmailUtility file:
namespace Common
{
public class EmailUtility
{
public static string SMTP_SERVER;
public static string[] GetEmailRecipientAdmin();
public static void SendEmail(string messageFrom, string[] messageTo, string messageSubject, string messageBody, string ipAddress, bool isHtml);
public static void SendEmail(string messageFrom, string[] messageTo, string[] messageCC, string messageSubject, string messageBody, string messageAttachmentPath, string ipAddress, bool isHtml);
public static void SendEmail(string messageFrom, string[] messageTo, string[] messageCC, string messageSubject, string messageBody, string[] messageAttachmentPath, string ipAddress, bool isHtml);
public static void SendEmail(string messageFrom, string messageTo, string messageSubject, string messageBody, string ipAddress, bool isHtml);
public static void SendEmail(string messageFrom, string messageTo, string messageSubject, string messageBody, string messageAttachmentPath, string ipAddress, bool isHtml);
}
}

C# Error: “Fill: SelectCommand.Connection property has not been initialized.”

I have problem with this error:
C# Error: “Fill: SelectCommand.Connection property has not been
initialized.”
I lloked ower others threads, but people have it built their clients little different and it didnt help.
I dont know, why this error showed. And I suppose its wrong somewhere at SelectOsoba.
I need to show data in DataGridView.
my code is :
class Vrstva
{
public static SqlConnection myConnection;
public static string connstr;
static DataTable t;
public static void createConnect1()
{
connstr = ConfigurationSettings.AppSettings["local1"];
Vrstva.myConnection = new SqlConnection(connstr);
}
public static void createConnect2()
{
connstr = ConfigurationSettings.AppSettings["local2"];
Vrstva.myConnection = new SqlConnection(connstr);
}
public static void createConnect3()
{
connstr = ConfigurationSettings.AppSettings["local3"];
Vrstva.myConnection = new SqlConnection(connstr);
}
public static void openConn()
{
Vrstva.myConnection.Open();
}
public static void closeConn()
{
Vrstva.myConnection.Close();
}
public static SqlDataAdapter Query(string command)
{
return new SqlDataAdapter(command, Vrstva.myConnection);
}
public static void NonQuery(string command)
{
SqlCommand Command = new SqlCommand(command, Vrstva.myConnection);
Command.ExecuteNonQuery();
}
public static bool login1(string login, string password)
{
string login1 = ConfigurationSettings.AppSettings["login1"];
string password1 = ConfigurationSettings.AppSettings["password1"];
if (login == login1 && password == password1)
{
return true;
}
return false;
}
public static bool login2(string login, string password)
{
string login1 = ConfigurationSettings.AppSettings["login2"];
string password1 = ConfigurationSettings.AppSettings["password2"];
if (login == login1 && password == password1)
{
return true;
}
return false;
}
public static bool login3(string login, string password)
{
string login1 = ConfigurationSettings.AppSettings["login3"];
string password1 = ConfigurationSettings.AppSettings["password3"];
if (login == login1 && password == password1)
{
return true;
}
return false;
}
////vypis tabulku prislusniku
public static DataTable SelectOsoba()
{
t = new DataTable();
Query("Select * from Osoba;").Fill(t);
return t;
}
//Insert
public static void PridejOsoba(string Jmeno, string Prijmeni, string Povolani, int Poc_Det)
{
NonQuery("Insert into Osoba(Jmeno,Prijmeni,Povolani,Poc_Det) values('" + Jmeno + "','" + Prijmeni + "','" + Povolani + "','" + Poc_Det + "');");
}
}
This error is most likely being thrown because your connection in this line:
return new SqlDataAdapter(command, Vrstva.myConnection);
has not been initialized.
You have to call one of your createConnectX() methods before trying to query.

Mvc .Net.Mail: How to send email with image (logo)

I am using three classes to send email but i cant to combine text email with image, or just to send image. When i get email i see empty image.
Help me to change my code so i can to send email with:
text
image
and style
public class SendService : IDistributionProvider
{
public int Send(System.Xml.Linq.XDocument recipientsData, string subject, string fromName, string fromAccount)
{
foreach (XElement element in recipientsData.Root.Elements())
{
string email = element.Element("email").Value;
string name = element.Element("name").Value;
string message = element.Element("message").Value;
bool result = EmailUtils.SendEmail(fromAccount, fromName, email, name, subject, message.Replace("\n", "<br/>"));
}
return 1;
}
public interface IDistributionProvider
{
int Send(XDocument recipientsData, string subject, string fromName,
string fromAccount);
}
public static class EmailUtils
{
private static string sendHostName;
private static int sendPort;
private static string userName;
private static string password;
private static string defaultFromEmail;
private static string defaultFromName;
static EmailUtils()
{
sendHostName = ConfigurationManager.AppSettings["sendHostName"];
sendPort = int.Parse(ConfigurationManager.AppSettings["sendPort"]);
defaultFromEmail = ConfigurationManager.AppSettings["fromEmail"];
defaultFromName = ConfigurationManager.AppSettings["fromName"];
string credential = Utils.DecryptString(ConfigurationManager.AppSettings["credential"]);
if (!string.IsNullOrEmpty(credential) && credential.Split(";".ToCharArray()).Length > 1)
{
userName = credential.Split(";".ToCharArray())[0];
password = credential.Split(";".ToCharArray())[1];
}
}
public static bool SendEmail(string toEmail, string toName, string subject, string body)
{
return SendEmail(defaultFromEmail, defaultFromName, toEmail, toName, subject, body);
}
public static bool SendEmail(string fromEmail, string fromName, string toEmail, string toName, string subject, string body)
{
try
{
if (string.IsNullOrEmpty(toEmail))
{
return false;
}
if (string.IsNullOrEmpty(toName))
{
toName = toEmail.Substring(0, toEmail.IndexOf("#"));
}
if (string.IsNullOrEmpty(fromEmail))
{
fromEmail = defaultFromEmail;
}
if (string.IsNullOrEmpty(fromName))
{
fromName = defaultFromName;
}
Message message = new Message();
message.Charset = "UTF-8";
message.Subject = Codec.RFC2047Encode(subject, "UTF-8");
message.From = new Address(fromEmail, fromName);
message.To.Add(toEmail, toName);
message.BodyHtml.Format = BodyFormat.Html;
message.BodyHtml.Charset = "UTF-8";
message.BodyHtml.Text = body;
return ActiveUp.Net.Mail.SmtpClient.SendSsl(message, sendHostName, sendPort, userName, password, SaslMechanism.Login);
}
catch
{
return false;
}
}
}
In this way I send email- just text:
string bodyEmail = "<h2>Welcome to website</h2></br><div><p>Thank for using website</p></div>";
EmailUtils.SendEmail("xxx#gmail.com","xxxx","Contact",bodyEmail);
Easiest way to do it is to inline your images using Data URIs.
You essentially inline the image into the HTML of your message. Just follow the format
data:[<MIME-type>][;charset=<encoding>][;base64]
where mime-type may be image/jpeg, charset should be ASCII, and the bytes of the image converted to base64. You can get that by reading the bytes of the image file from disk
byte[] imaeg = File.ReadAllBytes("nekkedladies.jpg");
then convert the byte array to a base 64 string
var base64Imaeg = System.Convert.ToBase64String(imaeg);
slap it together and stick it in your html (stolen from wiki)
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Nekkid Ladies" />
btw, the example image data isn't nekkid ladies. It's this:
sorry
I've actually ran into this same problem and what really helped me was this. In my case I had the html and I had to parse it out using HtmlUtilityPack. I would not recommend using the encoded string as It is not fully supported, and it makes your message bloated. The cid way is also how outlook adds images to an email. I'd add code but I think the example was good enough in my case.

Accessing Yelp's OAuth 1.0a API with DotNetOpenAuth

Has anyone had success using DotNetOpenAuth to access Yelp's v2 api using DotNetOpenAuth?
After digging through the examples and the source, this is what I came up with:
public class YelpConnector
{
private static readonly string YelpConsumerKey = ConfigurationManager.AppSettings["YelpConsumerKey"];
private static readonly string YelpConsumerSecret = ConfigurationManager.AppSettings["YelpConsumerSecret"];
private static readonly string YelpToken = ConfigurationManager.AppSettings["YelpToken"];
private static readonly string YelpTokenSecret = ConfigurationManager.AppSettings["YelpTokenSecret"];
private static readonly InMemoryTokenManager tokenManager = new InMemoryTokenManager(YelpConsumerKey, YelpConsumerSecret, YelpToken, YelpTokenSecret);
private static readonly Uri YelpURLBase = new Uri("http://api.yelp.com/v2/");
private static readonly ServiceProviderDescription YelpServiceDescription = new ServiceProviderDescription {
RequestTokenEndpoint = null,
UserAuthorizationEndpoint = null,
AccessTokenEndpoint = null,
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
};
private static dynamic SearchBase(string queryString)
{
if (string.IsNullOrEmpty(queryString))
throw new ArgumentNullException();
var searchEndpoint = new MessageReceivingEndpoint(new Uri(YelpURLBase, "search?" + queryString), HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);
var consumer = new WebConsumer(YelpServiceDescription, tokenManager);
try
{
using (IncomingWebResponse response = consumer.PrepareAuthorizedRequestAndSend(searchEndpoint, YelpToken))
{
string rs = response.GetResponseReader().ReadToEnd();
dynamic js = SimpleJson.SimpleJson.DeserializeObject(rs);
return js;
}
}
catch (Exception e)
{
ErrorSignal.FromCurrentContext().Raise(e);
return null;
}
}
internal class InMemoryTokenManager : IConsumerTokenManager
{
private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
public InMemoryTokenManager(string consumerKey, string consumerSecret, string token, string secret)
{
if (String.IsNullOrEmpty(consumerKey))
{
throw new ArgumentNullException("consumerKey");
}
this.tokensAndSecrets[token] = secret;
this.ConsumerKey = consumerKey;
this.ConsumerSecret = consumerSecret;
}
public string ConsumerKey { get; private set; }
public string ConsumerSecret { get; private set; }
public string GetTokenSecret(string token)
{
return this.tokensAndSecrets[token];
}
public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response)
{
this.tokensAndSecrets[response.Token] = response.TokenSecret;
}
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret)
{
this.tokensAndSecrets.Remove(requestToken);
this.tokensAndSecrets[accessToken] = accessTokenSecret;
}
public TokenType GetTokenType(string token)
{
throw new NotImplementedException();
}
}
}
If I pass in the following QueryString limit=5&category_filter=movietheaters,bars,cafe,museums,danceclubs,parks&ll=37.78364455,-122.464104, I get an exception saying "Precondition failed.: value != null" and a stacktrace of:
at System.Diagnostics.Contracts.__ContractsRuntime.Requires[TException](Boolean condition, String message, String conditionText)
at DotNetOpenAuth.Messaging.MessagingUtilities.EscapeUriDataStringRfc3986(String value)
at DotNetOpenAuth.OAuth.ChannelElements.SigningBindingElementBase.ConstructSignatureBaseString(ITamperResistantOAuthMessage message, MessageDictionary messageDictionary)
at DotNetOpenAuth.OAuth.ChannelElements.HmacSha1SigningBindingElement.GetSignature(ITamperResistantOAuthMessage message)
at DotNetOpenAuth.OAuth.ChannelElements.SigningBindingElementBase.ProcessOutgoingMessage(IProtocolMessage message)
at DotNetOpenAuth.OAuth.ChannelElements.SigningBindingElementChain.ProcessOutgoingMessage(IProtocolMessage message)
at DotNetOpenAuth.Messaging.Channel.ProcessOutgoingMessage(IProtocolMessage message)
at DotNetOpenAuth.OAuth.ChannelElements.OAuthChannel.InitializeRequest(IDirectedProtocolMessage request)
at DotNetOpenAuth.OAuth.ConsumerBase.PrepareAuthorizedRequestAndSend(MessageReceivingEndpoint endpoint, String accessToken)
at MeetPpl.Helpers.SocialConnectors.YelpConnector.SearchBase(String queryString)
Any suggestions? Am I on the right trail?
I struggled with this issue for 1 whole day before giving up on dotnetopenauth. I found a very simple way to search yelp using the oauth library of http://www.twitterizer.net/ . Simply download the lite version of twitterizer and use my sample code below.
Download link is http://www.twitterizer.net/files/Twitterizer2lite-2.3.2.zip
public static string search()
{
string yelpSearchURL = "http://api.yelp.com/v2/search?term=food&location=San+Francisco";
string yelpConsumerKey = "your key";
string yelpConsumerSecret = "your secret";
string yelpRequestToken = "your token";
string yelpRequestTokenSecret = "your token secret";
Twitterizer.OAuthTokens ot = new Twitterizer.OAuthTokens();
ot.AccessToken = yelpRequestToken;
ot.AccessTokenSecret = yelpRequestTokenSecret;
ot.ConsumerKey = yelpConsumerKey;
ot.ConsumerSecret = yelpConsumerSecret;
string formattedUri = String.Format(CultureInfo.InvariantCulture,
yelpSearchURL, "");
Uri url = new Uri(formattedUri);
Twitterizer.WebRequestBuilder wb = new Twitterizer.WebRequestBuilder(url, Twitterizer.HTTPVerb.GET, ot);
System.Net.HttpWebResponse wr = wb.ExecuteRequest();
StreamReader sr = new StreamReader(wr.GetResponseStream());
return sr.ReadToEnd();
}
You can use RestSharp api: https://github.com/JustinBeckwith/YelpSharp in combination with OAuthBase: http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs.
In YelpSharp implementation change Yelp.cs class method makeRequest with this:
protected string makeRequest(string area, string id, Dictionary<string, string> parameters)
{
// build the url with parameters
var url = area;
if (!String.IsNullOrEmpty(id)) url += "/" + HttpUtility.UrlEncode(id);
if (parameters != null)
{
bool firstp = true;
string[] keys = parameters.Keys.ToArray();
foreach (string _key in keys)
{
if (firstp) url += "?";
else url += "&";
firstp = false;
//Double URL encode "&" to prevent restsharp from treating the second half of the string as a new parameter
parameters[_key] = parameters[_key].Replace("&", "%26");
parameters[_key] = parameters[_key].Replace("+", "%2B");
parameters[_key] = parameters[_key].Replace(" ", "%2B");
url += _key + "=" + parameters[_key]; //HttpUtility.UrlEncode(parameters[_key]);
}
}
var client = new RestClient(rootUri);
var request = new RestRequest(Method.GET);
OAuthBase oAuth = new OAuthBase();
string nonce = oAuth.GenerateNonce();
string timeStamp = oAuth.GenerateTimeStamp();
string normalizedUrl;
string normalizedRequestParameters;
string sig = oAuth.GenerateSignature(new Uri(string.Format("{0}/{1}", client.BaseUrl, url)),
options.ConsumerKey, options.ConsumerSecret,
options.AccessToken, options.AccessTokenSecret,
"GET", timeStamp, nonce, out normalizedUrl, out normalizedRequestParameters);
sig = HttpUtility.UrlEncode(sig);
request.Resource = string.Format(area);
if (parameters != null)
{
foreach (var p in parameters)
{
request.AddParameter(p.Key, p.Value);
}
}
request.AddParameter("oauth_consumer_key", options.ConsumerKey);
request.AddParameter("oauth_token", options.AccessToken);
request.AddParameter("oauth_nonce", nonce);
request.AddParameter("oauth_timestamp", timeStamp);
request.AddParameter("oauth_signature_method", "HMAC-SHA1");
request.AddParameter("oauth_version", "1.0");
request.AddParameter("oauth_signature", sig);
var response = client.Execute(request);
return response.Content;
}
Test like this:
public void testYelp()
{
string _term = "food";
string _location = "San Francisco";
var o = Credentials.GetOptions();
var y = new Yelp(o);
var searchOptions = new SearchOptions();
searchOptions.GeneralOptions = new GeneralOptions()
{
term = _term
};
searchOptions.LocationOptions = new LocationOptions()
{
location = _location
};
var results = y.Search(searchOptions);
}

amazon product advertising api - item lookup request working example

would anyone have a working example of an amazon ITEMLOOKUP ?>
i have the following code but it does not seem to work:
string ISBN = "0393326381";
string ASIN = "";
if (!(string.IsNullOrEmpty(ISBN) && string.IsNullOrEmpty(ASIN)))
{
AWSECommerceServicePortTypeChannel service = new AWSECommerceServicePortTypeChannel();
ItemLookup lookup = new ItemLookup();
ItemLookupRequest request = new ItemLookupRequest();
lookup.AssociateTag = secretKey;
lookup.AWSAccessKeyId = accessKeyId;
if (string.IsNullOrEmpty(ASIN))
{
request.IdType = ItemLookupRequestIdType.ISBN;
request.ItemId = new string[] { ISBN.Replace("-", "") };
}
else
{
request.IdType = ItemLookupRequestIdType.ASIN;
request.ItemId = new string[] { ASIN };
}
request.ResponseGroup = new string[] { "OfferSummary" };
lookup.Request = new ItemLookupRequest[] { request };
response = service.ItemLookup(lookup);
if (response.Items.Length > 0 && response.Items[0].Item.Length > 0)
{
Item item = response.Items[0].Item[0];
if (item.MediumImage == null)
{
//bookImageHyperlink.Visible = false;
}
else
{
//bookImageHyperlink.ImageUrl = item.MediumImage.URL;
}
//bookImageHyperlink.NavigateUrl = item.DetailPageURL;
//bookTitleHyperlink.Text = item.ItemAttributes.Title;
//bookTitleHyperlink.NavigateUrl = item.DetailPageURL;
if (item.OfferSummary.LowestNewPrice == null)
{
if (item.OfferSummary.LowestUsedPrice == null)
{
//priceHyperlink.Visible = false;
}
else
{
//priceHyperlink.Text = string.Format("Buy used {0}", item.OfferSummary.LowestUsedPrice.FormattedPrice);
//priceHyperlink.NavigateUrl = item.DetailPageURL;
}
}
else
{
//priceHyperlink.Text = string.Format("Buy new {0}", item.OfferSummary.LowestNewPrice.FormattedPrice);
//priceHyperlink.NavigateUrl = item.DetailPageURL;
}
if (item.ItemAttributes.Author != null)
{
//authorLabel.Text = string.Format("By {0}", string.Join(", ", item.ItemAttributes.Author));
}
else
{
//authorLabel.Text = string.Format("By {0}", string.Join(", ", item.ItemAttributes.Creator.Select(c => c.Value).ToArray()));
}
/*
ItemLink link = item.ItemLinks.Where(i => i.Description.Contains("Wishlist")).FirstOrDefault();
if (link == null)
{
//wishListHyperlink.Visible = false;
}
else
{
//wishListHyperlink.NavigateUrl = link.URL;
}
* */
}
}
}
the problem is with this:
thisshould be defined differently but i do not know how AWSECommerceServicePortTypeChannel service = new AWSECommerceServicePortTypeChannel();
Say, that code looks awful familiar. You're missing the Endpoint signing piece from when they switched over to requiring that you add message signing. You need to add a behavior on your client. Here's the change to your code above:
if (!(string.IsNullOrEmpty(ISBN) && string.IsNullOrEmpty(ASIN)))
{
AWSECommerceServicePortTypeClient client = new AWSECommerceServicePortTypeClient();
client.ChannelFactory.Endpoint.Behaviors.Add(
new Amazon.AmazonSigningEndpointBehavior(
accessKeyId,
secretKey);
ItemLookup lookup = new ItemLookup();
ItemLookupRequest request = new ItemLookupRequest();
lookup.AssociateTag = accessKeyId;
lookup.AWSAccessKeyId = secretKey;
//... etc.
And here's the Endpoint (I can't take credit for this, I wish I could remember who should):
namespace Amazon
{
public class AmazonSigningEndpointBehavior : IEndpointBehavior {
private string accessKeyId = "";
private string secretKey = "";
public AmazonSigningEndpointBehavior(string accessKeyId, string secretKey) {
this.accessKeyId = accessKeyId;
this.secretKey = secretKey;
}
public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime) {
clientRuntime.MessageInspectors.Add(new AmazonSigningMessageInspector(accessKeyId, secretKey));
}
public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher) { return; }
public void Validate(ServiceEndpoint serviceEndpoint) { return; }
public void AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection bindingParameters) { return; }
}
}
Oh. And you'll need the MessageInspector for that to work.
namespace Amazon
{
public class AmazonSigningMessageInspector : IClientMessageInspector {
private string accessKeyId = "";
private string secretKey = "";
public AmazonSigningMessageInspector(string accessKeyId, string secretKey) {
this.accessKeyId = accessKeyId;
this.secretKey = secretKey;
}
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
// prepare the data to sign
string operation = Regex.Match(request.Headers.Action, "[^/]+$").ToString();
DateTime now = DateTime.UtcNow;
string timestamp = now.ToString("yyyy-MM-ddTHH:mm:ssZ");
string signMe = operation + timestamp;
byte[] bytesToSign = Encoding.UTF8.GetBytes(signMe);
// sign the data
byte[] secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
HMAC hmacSha256 = new HMACSHA256(secretKeyBytes);
byte[] hashBytes = hmacSha256.ComputeHash(bytesToSign);
string signature = Convert.ToBase64String(hashBytes);
// add the signature information to the request headers
request.Headers.Add(new AmazonHeader("AWSAccessKeyId", accessKeyId));
request.Headers.Add(new AmazonHeader("Timestamp", timestamp));
request.Headers.Add(new AmazonHeader("Signature", signature));
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState) { }
}
}
And finally, the Header:
namespace Amazon
{
public class AmazonHeader : MessageHeader
{
private string name;
private string value;
public AmazonHeader(string name, string value)
{
this.name = name;
this.value = value;
}
public override string Name { get { return name; } }
public override string Namespace { get { return "http://security.amazonaws.com/doc/2007-01-01/"; } }
protected override void OnWriteHeaderContents(XmlDictionaryWriter xmlDictionaryWriter, MessageVersion messageVersion)
{
xmlDictionaryWriter.WriteString(value);
}
}
}
Yes, they made it complicated when they started requiring message signing...
A simple and easy library is available on nuget.
PM> Install-Package Nager.AmazonProductAdvertising
Example
var authentication = new AmazonAuthentication("accesskey", "secretkey");
var client = new AmazonProductAdvertisingClient(authentication, AmazonEndpoint.US);
var result = await client.GetItemsAsync("B00BYPW00I");
To perform a lookup for anything other then an ASIN, you need to specify the "SearchIndex" property. You can simply set it to "All".
var request = new ItemLookupRequest();
request.ItemId = new[] {upcCode};
request.IdType = ItemLookupRequestIdType.UPC;
request.IdTypeSpecified = true;
request.SearchIndex = "All";
Here is a link to the documentation: http://docs.amazonwebservices.com/AWSECommerceService/2011-08-01/DG/index.html?ItemLookup.html. Note the description of the SearchIndex parameter:
Constraint:If ItemIdis an ASIN, a search index cannot be specified in
the request. Required for non-ASIN ItemIds.
I actually built a little wrapper around it so it hands you back a handy object graph. I have the source up on BitBucket and a little more about it on the C# Amazon ItemLookup page.
C# Amazon ItemLookup
You can make calls like:
var item = client.LookupByAsin("B0037X9N5U");
double? price = item.GetLowestPrice();

Categories