Generic.List(Of Thoughts)
Generic.List(Of Thoughts)
Adventures in .NET Development - by Albert Walker
Adventures in .NET Development - by Albert Walker
HomeArchiveContactSubscribeSign in

RecentPosts

  • Roll Your Own Amazon Context Links, Part 1CommentsNot rated yet
  • Amazon Advertising API – Signing Requests VB.NET 2008 SampleCommentsRating: 5 / 1
  • Amazon Advertising API: Signing Requests (Second Try)CommentsNot rated yet
  • Process.Start() on Windows Shortcuts (.lnk files)CommentsRating: 5 / 1
  • Amazon Advertising API: Signing RequestsCommentsRating: 3 / 2
  • C#: Displaying Windows Shortcut IconsCommentsRating: 5 / 1
  • CSS: “display: inline-block”, where were you 5 years ago?CommentsNot rated yet
  • Recursive CTEs (quick refresher)CommentsNot rated yet
  • LINQ to SitemapCommentsNot rated yet
  • WPF ScrollViewer: Scrolling on mouse hover eventsCommentsNot rated yet

Month List

  • 2009
    • July (8)
    • August (4)
    • September (1)

Category list

  • RSS feed for Amazon Advertising APIAmazon Advertising API (2)
  • RSS feed for C# 2008C# 2008 (7)
  • RSS feed for GeneralGeneral (1)
  • RSS feed for IIS 7IIS 7 (1)
  • RSS feed for Internet Explorer 8Internet Explorer 8 (1)
  • RSS feed for LINQLINQ (2)
  • RSS feed for Office 2007Office 2007 (1)
  • RSS feed for SOAPSOAP (1)
  • RSS feed for SQL 2005SQL 2005 (1)
  • RSS feed for SQL 2008SQL 2008 (1)
  • RSS feed for VB.NET 2008VB.NET 2008 (3)
  • RSS feed for WCFWCF (1)
  • RSS feed for Web ServicesWeb Services (3)
  • RSS feed for Win32 InteropWin32 Interop (1)
  • RSS feed for Windows VistaWindows Vista (1)
  • RSS feed for WPFWPF (2)
Protected by Commentor
6754 comments approved
223317 spam caught
Since December 1, 2008
Powered by Spam Counter

Roll Your Own Amazon Context Links, Part 1

Yeah, I know. Another blog post on the Amazon Advertising API? Actually, I've had the idea for this particular post for a while, and I figured it was a good time to share, seeing as how developers coding against Amazon Web Services are visiting the site in full force right now.

Back in October 2008, Amazon stopped offering Context Links to their affiliates (Amazon's announcement here). Everyone who browses the web has encountered some form of context links; essentially, it's when text in a blog post or a forum post is scanned for key phrases, and those phrases are automatically converted to sponsored links. Amazon's Context Links would scan text on the fly and automatically convert them to (affiliate-tagged) links to products on their site.

The context linking functionality was never really that good; products linked were generally pretty irrelevant to the subject being discussed. Also, it doesn't appear as though many affiliates used them. So, those are probably the two biggest reasons Amazon Context Links went away.

But since that time, I've started to wonder if I could use existing web services to acheive something similar. I'm not quite at the point where text is automatically scanned and converted to links on the fly, but I think I at least came up with a replacement for the core functionality.

Yahoo provides a free web service called the Term Extraction service. This takes a block of text, and using Yahoo's search engine algorithms, extracts the most meaningful phrases from that block of text. The example they provide on their site passes in the phrase "Italian sculptors and painters of the renaissance favored the Virgin Mary for inspiration." When passed to the Term Extraction service, it returns the keywords "italian sculptors", "virgin mary", "painters", "renaissance", and "inspiration".

I bet you see where I'm going with this. Because once you have the key phrases extracted from a block of text, it's pretty easy to use the Amazon Advertising API to search Amazon using those key phrases, and returning the products that most closely match those phrases.

So here's what I have so far. (The most important code is in a zip file at the end of this article.) I have a class called AmazonContextLinks that has a method called Generate:

public static List<KeywordResult> Generate(string p_sTextToAnalyze)

This takes in a block of text to analyze, and returns a generic list of a custom class. Here's the definition of the KeywordResult class:

 

public class KeywordResult

{

     public string Url { get; set; }

     public string Keyword { get; set; }

     public string Title { get; set; }

}

After calling the Generate function, the URL property will hold the full URL to the Amazon product, including my affiliate tag. The Keyword property will be the keyword that was detected by Yahoo Term Extraction and used to find the product located at the URL. And the Title property will have the product title (e.g., book title, movie title, etc.). The Title is probably not needed for this functionality, but I threw it in there anyway, for possible future use.

So let's take a closer look at the Generate method:

public static List<KeywordResult> Generate(string p_sTextToAnalyze)

{

List<string> KeywordList = YahooTermExtraction(p_sTextToAnalyze);

return AmazonSearch(KeywordList);

}

 

Pretty simple so far. More...

e0b504f1-a972-4a17-a390-4155284991a8|0|.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: Web Services | Amazon Advertising API | C# 2008 | LINQ
Posted by Albert Walker on Friday, September 04, 2009 5:05 PM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (41) | Post RSSRSS comment feed

Amazon Advertising API – Signing Requests VB.NET 2008 Sample

In my previous post, I discussed how I integrated the code I found on this blog post with my (primarily) VB.NET website to sign my requests to the Amazon Advertising API. For my purposes, I only had to convert the three helper classes over to VB.NET from the original C# code. Since it seems there might be a demand for it, I went ahead and converted all of Oren Trutner's sample solution from C# to VB.NET. I did this by hand, so that all the comments/line spacing would be preserved and also to avoid some of the quirks of automatic code convertors.

The solution contains three small projects, all console applications, that demonstrate how to sign simple, batch, and asynchronous requests to the Amazon Advertising API using VB.NET and WCF. You'll have to make sure to update the code to replace the XXXXXXXs with your real AWS Access Key and Private Key.

Download zip file: Signing Amazon Advertising API Requests in VB.NET.

3ae71879-35d6-4c64-a4f3-960e97b55b16|1|5.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: Amazon Advertising API | WCF | VB.NET 2008
Posted by Albert Walker on Saturday, August 29, 2009 6:06 AM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (15) | Post RSSRSS comment feed

Amazon Advertising API: Signing Requests (Second Try)

Thanks to a commenter on this blog for pointing out that my original try at signing Amazon requests was based on incorrect information. Turns out that adding a certificate to your requests to the Amazon Advertising API does not actually "sign" the requests. The API still expects the AWSAccessKey, Timestamp and computed Signature in the SOAP headers.

The only way to do this is by using WCF to connect to the web service. Unfortunately, this does require adding a reference to the latest version of the Amazon API. I was hoping to continue to use the older version indefinitely, but it doesn't appear there's a way to sign requests while still using an older version of the web service.

So I had to bite the bullet on this one and upgrade, but the good news is that the latest version appears to be fully backward compatible with the old version. Except for a few lines of code to sign the requests, I didn't have to change any of my code to use the new version, but your mileage may vary.

NOTE: The bulk of this blog post was taken from a very helpful post on this site: http://flyingpies.wordpress.com/?p=17, written by Oren Trutner. My contribution is really just to port his code over to VB.NET because that's the primary language of my site.

So here's what you need to do if you're running an older version of the Amazon ECS service, and you need to sign your requests.

First, make sure you have your access identifier key and your secret key for Amazon Web Services, which you can find on http://aws.amazon.com/. These two keys are located on your Access Identifiers page, as shown below.

Second, you need to add a reference to the latest version of the Amazon Advertising API. You do this by right-clicking on the project and selecting "Add Service Reference…" (Do not select the "Add Web Reference" item.) Then enter the address http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl and click Go.

Enter a name for the service reference and hit OK (I called it "AmazonECS2009" to differentiate it from the old, WSE reference, which was "AmazonECS").

The code I got from Owen Trutner's blog features three classes that inherit/implement WCF classes to allow for signing of the request. There's AmazonHeader, which inherits from System.ServiceModel.Channels.MessageHeader. There's AmazonSigningEndpointBehavior, which implements System.ServiceModel.Description.IEndpointBehavior. Finally, there's AmazonSigningMessageInspector, which implements the System.ServiceModel.Dispatcher.IClientMessageInspector interface. All three of these code files can be found in the zip file at the end of this article.

Take these files and include them in your App_Code directory. Now you'll have to change your requests that import the old web reference to import the new, like so:

'Imports AmazonECS

Imports AmazonECS2009

 

Now, modify your calls to the AWSE service to use the WCF client. Here's what my code looked like before making the change:

Dim oCommerceServ As New AWSECommerceService()

Dim oItemLookup As New ItemLookup()

 

oItemLookup.SubscriptionId = "XXXXXXXXXXXXXXXXXXXX"

oItemLookup.AssociateTag = "MyAssociateId-20"

 

Dim oLookupRequest As New ItemLookupRequest()

Dim oLookupResponse As ItemLookupResponse

 

'Set the search parameters

oLookupRequest.ItemId = New String() {sAsin}

oLookupRequest.ResponseGroup = New String() {"Small", "Images", "ItemAttributes", _

"OfferFull", "EditorialReview", "Reviews"}

 

oLookupRequest.ReviewSort = "-HelpfulVotes" 'Most helpful review first

 

'Assign the request to the item search object

oItemLookup.Request = New ItemLookupRequest() {oLookupRequest}

 

Try

 

'Send the query

oLookupResponse = oCommerceServ.ItemLookup(oItemLookup)

 

Catch oException As Exception

 

<Error Handling Code>

 

End Try

 

More...

349e7a30-07ee-49b7-b452-5df481b3bf05|0|.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: Web Services | VB.NET 2008
Posted by Albert Walker on Friday, August 28, 2009 3:09 AM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (70) | Post RSSRSS comment feed

Process.Start() on Windows Shortcuts (.lnk files)

.NET provides any easy way of spawning new processes through the System.Diagnostics.Process class. It's relatively straightforward, and you can even call Process.Start on files that are not executables, and the associated program will be launched to open the file. You can even pass in a shortcut file, and the shortcut will be launched.

There's a problem, however: If the file you launch is not an executable, Process.Start will not return a handle to the process. Which means handy functions like WaitForInputIdle or WaitForExit will throw a NullReferenceException. And that's kind of a problem if you're actually trying to, say, keep the user updated on the status of the launched application.

Here's an example of the problem. I created a shortcut to the Sound applet in Control Panel and put it on the Desktop. I use the following code to launch the shortcut:

string sShortcutFilePath =

@"C:\Users\Albert\Desktop\Sound - Shortcut.lnk";

 

ProcessStartInfo awProcessStartInfo = new ProcessStartInfo(sShortcutFilePath);

 

// Start the process

Process awProcess = Process.Start(awProcessStartInfo);

 

// Wait for the process to finish loading

awProcess.WaitForInputIdle();

 

// Wait for the process to exit

awProcess.WaitForExit();

After calling Process.Start, awProcess is equal to null, and the remaining statements error out. After investigating the Process and ProcessStartInfo classes to see if there was a property I needed to set (helpful hint: the ProcessStartInfo.UseShellExecute property will not help here), it became clear to me that the Win32 API would be the only way to do this, specifically by using ShellExecuteEx and passing in the SEE_MASK_WAITFORINPUTIDLE flag. More...

b81402fd-d28c-4a08-aead-784d0463bbbb|1|5.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: C# 2008 | Win32 Interop
Posted by Albert Walker on Wednesday, August 12, 2009 6:09 PM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (83) | Post RSSRSS comment feed

Amazon Advertising API: Signing Requests

One of the websites I run relies on commissions from the Amazon Associates program. I've been using the Amazon Advertising API (formerly known as Amazon ECS Web Services) for years to generate custom ad banners for Amazon products. I load ASINs (Amazon's product identifiers) into a database table, and then I make requests through the web service to get product images, prices, and short descriptions.

It appears security has become something of a concern to Amazon for making calls through these web services, which is why associates using the services got the following email notice from Amazon:

Dear Developer,

We want to remind you that all calls to the Product Advertising API must be authenticated using request signatures by August 15, 2009. Please remember that calls to the Product Advertising API that are not signed will not be processed after August 15, 2009. For help on request signatures, please see the Resources section below.

The Product Advertising API Team.

This concept of signing requests seemed overwhelming. Complicating the issue is that my ASP.NET project relies on an older version of the Amazon ECS Web Service. The newer version has the properties required to easily sign the requests, such as the Destination property on the AWSECommerceService itself, or new classes like AmazonHmacAssertion and AmazonX509Assertion. Unfortunately, the version I've been using all these years does not.

The prospect of figuring out how to sign these requests in the older version of the web service looked somewhat daunting, especially when reading not-so-helpful hints in the developer guide like "Calculate an RFC 2104-compliant HMAC-SHA256 signature, using the string you just created and your Secret Access Key as the key." (And people wonder why software developers have a reputation for being poor communicators.)

Missing in the whole developer's guide is a straightforward example of how to sign SOAP requests in a .NET application with the Amazon Advertising API added as a Web Reference, which you'd think would be the most common way of calling these services.

Luckily, I was able to scour the web and figure out the really simple way to sign requests. If you're using an older version of the ECS service, this should work for you too.

Step 1. Log into your Amazon Web Services account at http://aws.amazon.com/, and go to your Access Identifiers page.

Step 2. Create a new X.509 certificate for your account by clicking "Create New" under the X.509 Certificate section.

Step 3. If you've never created an X.509 certificate for your account before, click "Yes" on the warning that follows. Next, download the X.509 Certificate that you just created. I blotted out the full name of the certificate file in the screenshot for security reasons.

Step 4. Take the cert-*.pem file you just downloaded, and copy it to your ASP.NET website. It doesn't really matter where you put it, just make sure to remember the location for later.

Step 5. Modify your calls to the Amazon Advertising API, like so. Do this before making any requests to the service (e.g., ItemLookup, ItemSearch, etc.)

Dim AmazonService As New AWSECommerceService()

Dim X509Cert As New X509Certificate( _

Server.MapPath("<relative path to your cert-*.pem file>"))

AmazonService.ClientCertificates.Add(X509Cert)

That's about it. If you did it wrong, it should throw an invalid signature exception. If not, your requests are being signed and you should be all set for the August 15 deadline.

In the near future, I plan to revisit when and how I'm making my Amazon web service calls. It's been several years since I looked at this code, and I'm sure there's an opportunity to streamline things a great deal. I may look at converting these SOAP calls over to REST calls, which are much simpler and straightforward, and don't carry the heavy burden that I experienced here, with the web reference ending up being years out of date.

6d8d375a-e402-41ad-895b-d0c6faba99a2|2|3.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: SOAP | Web Services | VB.NET 2008
Posted by Albert Walker on Tuesday, August 04, 2009 5:39 AM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (160) | Post RSSRSS comment feed

C#: Displaying Windows Shortcut Icons

This is one of those things you think will be quick and simple, but which quickly turns into a multi-day project.

What I wanted to do was display all the shortcuts in my Quick Launch bar as icons in my app. If you've read other posts on this blog, you may have an idea of the larger project I'm working on, but for now let's just focus on taking a Windows Shortcut file (a .lnk file) and displaying the associated icon.

Below is the end result of doing this in a WPF Browser Application, but the same technique can easily be applied to Windows Forms Applications. It's just really easily to load a dynamic list of images into an ItemsControl; certainly, it has to be easier than whatever the Forms equivalent of an ItemsControl is.

Yes, those are all the shortcuts in my Quick Launch bar. A special prize to anyone who can name all those programs!

When I first set about doing this, I tried adding a reference to the Windows Script Host Object Model (Interop.IWshRuntimeLibrary.dll), and for each .lnk file, I did this:

IWshShortcut link = (IWshShortcut)shell.CreateShortcut(LnkFile.FullName);

The problem is that the IconLocation property of IWshShortcut is completely unreliable. For most shortcuts, it would give the correct path to the file containing the icon. But for certain "special" shortcuts, such as the shortcuts in the Quick Launch bar for "Show desktop" or "Switch between windows", or even shortcuts I created myself pointing to Control Panel applets, it would return a useless IconLocation of ",0".

I briefly started researching the binary format of Windows Shortcut files, and I even tried extracting the properties I wanted using the BinaryReader class. I didn't get far before I realized there's a much easier way to do this. More...

dc1a6cb4-055a-47d9-902c-9a40ef77cf12|1|5.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: Windows Vista | C# 2008 | WPF
Posted by Albert Walker on Wednesday, July 29, 2009 12:58 PM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (134) | Post RSSRSS comment feed

CSS: “display: inline-block”, where were you 5 years ago?

It appears that all the major browsers now support the CSS declaration display: inline-block;. I'm not entirely sure when this happened. By default, Visual Studio 2008's CSS editor doesn't even recognize it as a valid value for the "display" property, so this must have happened fairly recently, perhaps with the release of IE8.

Why the excitement over inline-block? Because it allows you to specify block-type properties like padding, height, width, border, etc., while still keeping the element inline (i.e., adjacent to the previous element in the document). So now it's really easy to produce rollover navigation effects like the one below, purely through CSS.

I remember attempting something similar to this about 5 years ago. Back then, in the dark IE 5.5/6 days, the process went something like this:

  1. Wrap your hyperlink in a containing DIV.
  2. Use JavaScript to detect when the mouse was over the containing DIV, and set the rollover CSS properties in code.
  3. Of course, it's nowhere near as simple as doing <div onmouseover="whatever" onmouseout="whatever2"> because the onmouseout event would fire when the mouse hovered over child elements within the DIV. So you'd have to write extra logic to walk up the document tree every time the mouse moved, and see if the mouse was inside your containing DIV, and then fire your mouseover/mouseout changes in code.
  4. Oh yeah, and make sure that clicking on the containing DIV takes you to the URL, just like clicking on the hyperlink would do, which of course requires more JavaScript.
  5. Once you've done all that, promptly check yourself into the nearest mental health facility in time for your nervous breakdown.

     

That was the 2004 way. Here's the 2009 way: More...

aa4dfee3-8e42-4394-a848-977777f01cfc|0|.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: Internet Explorer 8
Posted by Albert Walker on Sunday, July 26, 2009 9:28 AM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (123) | Post RSSRSS comment feed

Recursive CTEs (quick refresher)

If you've already worked with CTEs (common table expressions) in SQL Server 2005, what I'm about to post won't exactly be groundbreaking. I played around with CTEs a little when SQL 2005 first came out, but in the past week I finally had a good reason to use them, meaning I had to spend a bit of time getting back up to speed on how they worked.

Because of their recursive nature, CTEs are good for generating hierarchal data. In this case, I wanted to generate URL paths based on an adjacency list. Let me paste my ContentPage table from my previous article:

It's a pretty simple data structure, where ParentId points to another record in the ContentPages table. So, given a particular ContentPage Id, I wanted to concatenate all the UrlSegments leading to that page, separated by the path separator (/). Common table expressions generally take the form

    with <CTE Name> (<CTE Fields>)

    as

    (

        <Anchor member definition>

 

        union all

 

        <Recursive member definition>

 

    )

    -- Statement that executes the CTE

    select <CTE Fields>

    from <CTE Name>

 

Back when I was taking computer science, it was called the "base case", but Microsoft refers to it as the "anchor member definition", but it's the same general concept behind all recursive algorithms: You're defining one set of rules for the root (base) and another set of rules for items that are not the root, and UNIONing them together. Here's what I came up with:More...

e5bf87f5-60e1-492e-b177-199953a5c0d7|0|.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: SQL 2008 | SQL 2005
Posted by Albert Walker on Friday, July 24, 2009 5:30 AM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (74) | Post RSSRSS comment feed

LINQ to Sitemap

Here's a very simple way to generate a sitemap from your LINQ to SQL classes, which in turn allows you to bind your LINQ to SQL classes to all the built-in ASP.NET navigation controls.

There are other, more complex ways to do this, such as converting LINQ data to XML, or creating custom hierarchical classes, but this is the straightforward way. Here are the highlights of this approach; the full code will be included at the end of this article.

This article assumes you have a table in SQL that implements an adjacency list (i.e., each row has a "parent id" column that points to a parent node in the same table), and that you've already generated the LINQ to SQL classes for this table (the .dbml file). Here's what I have (fields not important to this code have been blurred out):

Every ContentPage has a ParentId that points to the Id of another ContentPage, except for the root ContentPage, which has a ParentId of NULL. The UrlSegment field contains that portion of the URL path to that ContentPage. So, if the "Contact" page has a UrlSegment of "contact", with a parent page with a UrlSegment of "about", the full URL to the Contact page would be /about/contact

So here's what you do:

 

  1. Create a new class and implement StaticSiteMapProvider:

public class LinqSiteMapProvider : StaticSiteMapProvider

More...

8f3bea5a-1653-4b80-b4f3-43da22e53219|0|.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: LINQ | C# 2008
Posted by Albert Walker on Thursday, July 23, 2009 8:20 AM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (20) | Post RSSRSS comment feed

WPF ScrollViewer: Scrolling on mouse hover events

I've just recently started getting my feet wet with WPF. The project I'm working on is a Vista Sidebar Gadget written in C#. A WPF Browser Application seemed like the way to go, because this gadget needs to interact a lot with the local system, and doing that in Gadget-based JavaScript would require learning a whole new object hierarchy. By using an XBAP file hosted in an IFrame, I'm able to make use of the standard .NET classes for interacting with the local computer, which makes Gadget development a lot easier.

One thing I wanted to do in this gadget is reduce the number of clicks required to perform an action. The ScrollViewer is a great control, especially compared to the hellish techniques that were used for making scrolling viewports in Windows Forms in previous versions of.NET. However, the ScrollViewer still requires a lot of mouse clicks to locate the precise object you want to see.

What I wanted was a ScrollViewer that would scroll when you simply hovered over the up and down buttons. I've been able to achieve that, as you can see below.

Flash animation removed…

No clicks required! That's a StackPanel being bound to static XML data in the Page.Resources, by the way. More...

35f23d7b-74de-46c8-96b3-9adfc4e308a0|0|.0|27604f05-86ad-47ef-9e05-950bb762570c

Categories: WPF | C# 2008
Posted by Albert Walker on Sunday, July 19, 2009 1:15 PM
E-mail | Kick it! | DZone it! | del.icio.us
Permalink | Comments (109) | Post RSSRSS comment feed
<< Previous posts
  • Next posts
  • 1
  • 2
  • Previous posts
Powered by BlogEngine.NET 2.6.0.5 | Theme by Mark Wagner, Adapted by Ahmad Masykur, Modified by Albert Walker