Injecting theme name into front end Best approach - c#

At the min I am replacing _content in the source elements of my cshtml razor to inject the theme name my users are selecting in the admin this works.
But It requires me to place a tag helper on every element this happens.
At Present I am doing
[HtmlTargetElement(Attributes = AppendVersionAttributeName)]
public class AppendVersionTagHelper : TagHelper
{
private const string AppendVersionAttributeName = "cella-append-version";
private readonly IConfiguration _config;
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.RemoveAll(AppendVersionAttributeName);
if (!AppendVersion)
{
if (output.Attributes.ContainsName("href"))
{
var href = output.Attributes["href"].Value.ToString();
output.Attributes.SetAttribute("href", AppendVersionToUrl(href));
}
}
if (!AppendVersion)
{
if (output.Attributes.ContainsName("src"))
{
var src = output.Attributes["src"].Value.ToString();
output.Attributes.SetAttribute("src", AppendVersionToUrl(src));
}
}
if (output.Attributes.ContainsName("href"))
{
var href = output.Attributes["href"].Value.ToString();
output.Attributes.SetAttribute("href", AppendThemeNameToUrl(href));
}
if (output.Attributes.ContainsName("src"))
{
var src = output.Attributes["src"].Value.ToString();
var replace = AppendThemeNameToUrl(src);
output.Attributes.SetAttribute("src", replace);
}
if (output.Attributes.ContainsName("xlink:href"))
{
var src = output.Attributes["xlink:href"].Value.ToString();
var replace = AppDomainNameToImage(src);
output.Attributes.SetAttribute("xlink:href", replace);
}
private string AppDomainNameToImage(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return string.Empty;
}
var theme = Constants.DomainName + #"/" + _config[Constants.ThemFolderNameConfigKey] + #"/" + _config["Theme"];
url = url.Replace("_DomainName", theme);
return url;
}
private string AppendThemeNameToUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return string.Empty;
}
var theme = _config[Constants.ThemFolderNameConfigKey] + #"/"+ _config["Theme"];
url = url.Replace("_content", theme);
return url;
}
private string AppendVersionToUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return string.Empty;
}
var version = _config["Global.AssetVersion"];
return url.Contains("?") ? $"{url}&v={version}" : $"{url}?v={version}";
}
}
The function above called
private string AppendThemeNameToUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return string.Empty;
}
var theme = _config[Constants.ThemFolderNameConfigKey] + #"/"+ _config["Theme"];
url = url.Replace("_content", theme);
return url;
}
}
Then I call the tag helper like so
<link rel="stylesheet" cella-append-version="false" href="~/_content/vendor/bootstrap/css/bootstrap.min.css">
My only concern is this is making an impact on how fast the razor engine returns from the tag helper to present to the user is there a neater way to inject the theme name dynamically to the front end

Related

Content Observer doesn't monitor the DownloadManager's download progress on Android

I implemented the download functionality in my android app using the download manager.
The download manager dows its job well, and once download is completed, the broadcast receiver I set is called successfully.
But, I want to monitor the download progress and display it inside my app, and not rely only on the download manager's notification.
So, I implemented a "ContentProvider and a ContentObserver" to query frequently the download manager for download progress.
Here is my content provider:
[ContentProvider(new string[] { DownloadsContentProvider.Authority })]
public class DownloadsContentProvider : ContentProvider
{
public const string Authority = "com.myapp.Myapp.DownloadProvider";
public DownloadsContentProvider()
{
}
public static Android.Net.Uri ProviderUri(long downloadId)
{
Android.Net.Uri uri = Android.Net.Uri.Parse($"http://content//downloads/my_downloads/{downloadId}");
var builder = new Android.Net.Uri.Builder()
.Authority(Authority)
.Scheme(ContentResolver.SchemeFile)
.Path(uri.Path)
.Query(uri.Query)
.Fragment(uri.Fragment);
return builder.Build();
}
public override int Delete(Android.Net.Uri uri, string selection, string[] selectionArgs)
{
return 0;
}
public override string GetType(Android.Net.Uri uri)
{
return null;
}
public override Android.Net.Uri Insert(Android.Net.Uri uri, ContentValues values)
{
return null;
}
public override bool OnCreate()
{
return true;
}
public override ICursor Query(Android.Net.Uri uri, string[] projection, string selection, string[] selectionArgs, string sortOrder)
{
throw new NotImplementedException();
}
public override int Update(Android.Net.Uri uri, ContentValues values, string selection, string[] selectionArgs)
{
return 0;
}
}
Then, I created a content observer to observe what happens and trigger the query of downloads progress.
public DownloadProgressContentObserver(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference,
transfer)
{
}
public DownloadProgressContentObserver(Handler? handler) : base(handler)
{
}
public DownloadProgressContentObserver() : base(null)
{
}
public override void OnChange(bool selfChange, Uri? uri)
{
base.OnChange(selfChange, uri);
var downloadId = uri.ToString().Substring(uri.ToString().LastIndexOf(Path.PathSeparator) + 1);
if (!string.IsNullOrEmpty(downloadId))
{
ComputeDownloadStatus(Convert.ToInt64(downloadId));
//TODO: dispatch this download percentage to the whole app, and the database
}
}
public void ComputeDownloadStatus(long downloadId)
{
long downloadedBytes = 0;
long totalSize = 0;
int status = 0;
DownloadManager.Query query = new DownloadManager.Query().SetFilterById(downloadId);
var downloadManager = DownloadManager.FromContext(Android.App.Application.Context);
var cursor = downloadManager.InvokeQuery(query);
String downloadFilePath = (cursor.GetString(cursor.GetColumnIndex(DownloadManager.ColumnLocalUri))).Replace("file://", "");
try
{
if (cursor != null && cursor.MoveToFirst())
{
downloadedBytes =
cursor.GetLong(cursor.GetColumnIndexOrThrow(DownloadManager.ColumnBytesDownloadedSoFar));
totalSize =
cursor.GetInt(cursor.GetColumnIndexOrThrow(DownloadManager.ColumnTotalSizeBytes));
}
}
finally
{
if (cursor != null)
{
cursor.Close();
}
}
var percentage = (downloadedBytes / totalSize) * 100;
}
}
This is how I use both, and register them in the download manager to monitor the download progress.
var manager = DownloadManager.FromContext(Android.App.Application.Context);
var request = new DownloadManager.Request(Android.Net.Uri.Parse(downloadUrl));
request.SetNotificationVisibility(DownloadVisibility.VisibleNotifyCompleted);
request.SetDestinationInExternalPublicDir(downloadsPath, fileName);
request.SetTitle(productTitle);
request.SetDescription(downloadDescription);
long downloadId = manager.Enqueue(request);
//I provide a valid URI with my content provicer
var uri = DownloadsContentProvider.ProviderUri(downloadId);
var contentResolver = Android.App.Application.Context.ContentResolver;
var observer = new DownloadProgressContentObserver();
contentResolver.RegisterContentObserver(uri, true, observer);
ProductContentObservers.Add(downloadId, observer);
I have read a lot of doc, and my implementation seems to be ok. But the content observer's "OnCHange" method is never called.
Can someone please point out what I might be doing wrong ?

How to wait for methods to finish then do new action?

I'm setting up my architechture to use Cef.Offscreen. In order to make it easy to work with I have divided some parts. But I run into a problem that controller loading finshes and serves a view before everything has been able to load.
Here's my structure --> Controller
public ActionResult InitBrowser()
{
ICefSharpRenderer renderer = RendererSingelton.GetInstance();
//Try to render something in default appdomain
renderer.LoginToTradingView(null, null);
ViewBag.SiteTitle = BrowserActions.RunScriptInNamedBrowser("loginbrowser", #"(function() {return document.title;} )();");
ViewBag.ImagesixtyfourUrl = BrowserActions.TakeScreenshot("loginbrowser");
//this is returned to fast, we have to wait for all
return View();
}
I have this class to get do some basic actions and initialize if needed.
public class CefSharpRenderer : MarshalByRefObject, ICefSharpRenderer
{
private ChromiumWebBrowser _browser;
private TaskCompletionSource<JavascriptResponse> _taskCompletionSource;
private string _name;
public void LoginToTradingView(string url, string browserName)
{
CheckIfCefIsInitialized();
BrowserFactory.GetBrowserInstance(#"https://se.tradingview.com/", "loginbrowser");
}
public void CreateBrowserAndGoToUrl(string url, string browserName)
{
CheckIfCefIsInitialized();
BrowserFactory.GetBrowserInstance(url, "browserName");
}
public void CheckIfCefIsInitialized()
{
if (!Cef.IsInitialized)
{
var settings = new CefSettings();
var assemblyPath = Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath);
settings.BrowserSubprocessPath = Path.Combine(assemblyPath, "CefSharp.BrowserSubprocess.exe");
settings.ResourcesDirPath = assemblyPath;
settings.LocalesDirPath = Path.Combine(assemblyPath, "locales");
var osVersion = Environment.OSVersion;
//Disable GPU for Windows 7
if (osVersion.Version.Major == 6 && osVersion.Version.Minor == 1)
{
// Disable GPU in WPF and Offscreen examples until #1634 has been resolved
settings.CefCommandLineArgs.Add("disable-gpu", "1");
}
//Perform dependency check to make sure all relevant resources are in our output directory.
Cef.Initialize(settings, performDependencyCheck: false, cefApp: null);
}
}
}
I get my browserinstance here and connected the events to be fired.
public static class BrowserFactory
{
public static ChromiumWebBrowser GetBrowserInstance(string _url, string browsername)
{
if (!BrowserContainer.CheckIfBrowserExists(browsername))
{
ChromiumWebBrowser _browser = new ChromiumWebBrowser(_url);
_browser.LoadingStateChanged += BrowserEvents.OnLoadingStateChanged;
BrowserContainer.AddDataHolder(browsername, new DataBrowserHolder { BrowserName = browsername, ChromiumWebBrow = _browser });
return _browser;
}
return null;
}
}
Browserevent loads correct page.
public static class BrowserEvents
{
public static void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
{
if (args.IsLoading == false)
{
ChromiumWebBrowser cwb = (ChromiumWebBrowser)sender;
if (cwb.Address == "https://se.tradingview.com/")
{
BrowserActions.LogInToTradingView("xxxxx", "yyyyyyy", "loginbrowser");
}
}
}
}
Last my browseractions, spare med for the thread sleeps it's just under construction and it works atm.
public static class BrowserActions
{
public static void LogInToTradingView(string twusername, string twpassword, string browserName)
{
ChromiumWebBrowser _dataholder = BrowserContainer.GetDataHolderByName(browserName).ChromiumWebBrow;
IFrame ifww = _dataholder.GetMainFrame();
// var lull = #"(function() { var serielength = TradingView.bottomWidgetBar._widgets.backtesting._reportWidgetsSet.reportWidget._data.filledOrders.length; return serielength; })();";
// JavascriptResponse _js = Task.Run(async () => { return await _browser.GetMainFrame().EvaluateScriptAsync(lull); }).Result;
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-header__link tv-header__link--signin js-header__signin')[0].click();})();");
// var loginusernamescript =
var loginpasswordscript = #"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[1].value= " + twpassword + "; })();";
var clkloginbtn = #"(function() { document.getElementsByClassName('tv-button tv-button--no-border-radius tv-button--size_large tv-button--primary_ghost tv-button--loader')[0].click();})();";
Thread.Sleep(300);
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[0].click();})();");
Thread.Sleep(50);
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[0].value = '" + twusername + "';})();");
Thread.Sleep(50);
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[1].click();})();");
Thread.Sleep(50);
ifww.ExecuteJavaScriptAsync(#"(function() { window.document.getElementsByClassName('tv-control-material-input tv-signin-dialog__input tv-control-material-input__control')[1].value = '" + twpassword + "';})();");
Thread.Sleep(50);
ifww.ExecuteJavaScriptAsync(#"(function() { document.getElementsByClassName('tv-button tv-button--no-border-radius tv-button--size_large tv-button--primary_ghost tv-button--loader')[0].click();})();");
}
public static string TakeScreenshot(string browserName)
{
try
{
Bitmap img = Task.Run(async () => { return await BrowserContainer.GetDataHolderByName(browserName).ChromiumWebBrow.ScreenshotAsync(); }).Result;
// object mgss = img.Clone();
string baseen = ExtraFunctions.ToBase64String(img, ImageFormat.Png);
return baseen;
}
catch (Exception e)
{
var x = e.InnerException;
return null;
}
}
public static string RunScriptInNamedBrowser(string browserName, string script)
{
try
{
string str = Task.Run(async () => { return await BrowserContainer.GetDataHolderByName(browserName).ChromiumWebBrow.GetMainFrame().EvaluateScriptAsync(script); }).Result.ToString();
// object mgss = img.Clone();
return str;
}
catch (Exception e)
{
var x = e.InnerException;
return null;
}
}
}
How can I get my browser actions to report back to my controller so that I can wait for them to finish?
For a Task asynchronous operation to report back, it's possible to use Progress<T>. How that's done is detailed in Enabling Progress and Cancellation in Async APIs. The key is:
var progressIndicator = new Progress<int>(ReportProgress);
This creates a Progress<T> object that can indicate how far a task is complete, and also call a custom method (ReportProgress) at set intervals. You can create a custom class if necessary instead of using int.
So your browser actions can report back to the controller with the progress reporting method until everything is complete.

String property behaves really weird

I have a settings class like this:
public class Settings
{
string resourcePath;
public string ResourcePath {
get {
return resourcePath + "/";
}
set {
resourcePath = value;
}
}
string texturePath;
public string TexturePath {
get {
string a = resourcePath + "/"; // This is just some debug stuff I did trying to find out wtf is going on
string b = texturePath + "/";
return a + b; // Breakpointing here shows that it is "Content/Textures/"
}
set {
texturePath = value;
}
}
public Settings ()
{
resourcePath = "Content";
texturePath = "Textures";
}
public static Settings CurrentSettings = new Settings();
}
Then I try to get the TexturePath from it, like this:
string path = Settings.CurrentSettings.TexturePath + file;
The string returned by the property is "Content//Content/Textures//"
What am I missing here? Why does it do that? With my knowledge it should return Content/Textures/
Use Path.Combine to work with path.
string path = Path.Combine(Settings.CurrentSettings.TexturePath,file);
and no need to add "/" to your properties.
public string ResourcePath {
get {
return resourcePath;
}
set {
resourcePath = value;
}
}
You might not be balancing the / between the getter and the setter. And you probably are getting some property and then setting another with it - resulting in too many /'s.
You haven't shown the code that produces the results you reported but the following code is highly suspect:
string resourcePath;
public string ResourcePath {
get {
return resourcePath + "/";
}
set {
resourcePath = value;
}
}
It always appends a forward slash on the getter but never removes it in the setter. So the following code:
x.ResourcePath = "abc";
x.ResourcePath = x.ResourcePath + "/def";
x.ResourcePath = x.ResourcePath + "/ghi";
Would set ResourcePath to "abc//def//ghi".
I suspect you are running into something like that.

itunes listening to

within windows live messenger, it is possible to share the song you are currently listening to. what would i need to do to get this working within c# like libarys etc cannot find the correct documentation on google.
You'll need to use the iTunes SDK to interact with iTunes from .NET. So there's your Google search term. :)
Here's a start:
http://blogs.msdn.com/b/noahc/archive/2006/07/06/automating-itunes-with-c-in-net.aspx
http://blogs.msdn.com/b/dancre/archive/2004/05/08/128645.aspx
Here is a script for LinqPad in C# which does as requested. (see LinqPad.com)
Bonus! Artwork view.
It looks like this:
<Query Kind="Program">
<Namespace>iTunesLib</Namespace>
<Namespace>System.Security.Cryptography</Namespace>
</Query>
void Main()
{
var track = new iTunesApp().CurrentTrack;
if (track == null)
"nothing playing".Dump();
else
new Viewer(track,true).Dump();
}
public class Viewer
{
const string PREFIX = "itlps-";
private IITFileOrCDTrack store;
private bool materialize;
public string album { get { return store.Album; } }
public string band { get { return store.Artist; } }
public string song { get { return store.Name; } }
public string desc { get { return store.Description; } }
public int? artCnt { get {
if (store.Artwork == null) return null;
else return store.Artwork.Count; }
}
public IEnumerable<ImageViewer> art { get {
if (materialize)
{
foreach(var artT in store.Artwork)
{
var art = artT as IITArtwork;
string ext = ".tmp";
switch(art.Format)
{
case ITArtworkFormat.ITArtworkFormatBMP:
ext = ".BMP";
break;
case ITArtworkFormat.ITArtworkFormatJPEG:
ext = ".JPG";
break;
case ITArtworkFormat.ITArtworkFormatPNG:
ext = ".PNG";
break;
}
string path = Path.Combine(Path.GetTempPath(),PREFIX+Path.GetRandomFileName()+ext);
art.SaveArtworkToFile(path);
yield return new ImageViewer(path);
}
}
yield break; }
}
public Viewer(IITFileOrCDTrack t,bool materializeArt = false)
{
store = t;
materialize = materializeArt;
}
public Viewer(IITTrack t,bool materializeArt = false)
{
store = t as IITFileOrCDTrack;
materialize = materializeArt;
}
}
public class ImageViewer
{
public string hash { get { return _hash.Value; } }
static private string _path { get; set; }
public object image { get { return _image.Value; } }
static private SHA1Managed sha = new SHA1Managed();
private Lazy<object> _image = new Lazy<object>(() => {return Util.Image(_path);});
private Lazy<string> _hash = new Lazy<string>(() =>
{
string hash = string.Empty;
using (FileStream stream = File.OpenRead(_path))
{
byte [] checksum = sha.ComputeHash(stream);
hash = BitConverter.ToString(checksum).Replace("-", string.Empty);
}
return hash;
});
public ImageViewer(string path)
{
_path = path;
}
}
last i checked this functionality is included out of the box all you need is to have itunes and windows live messenger installed and activate "what im listening to" and it shows this in your messenger status. if you are looking to create a bot that messages this out to a contact that is a different story tho that you will need to write a script for

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