| Comments

One of the announcements that happened during the MIX10 conference was the availability of the V2 of the Microsoft Translator API.  This is the engine that powers the translation behind http://www.bing.com/translate and some other Bing-related properties as well.  A lot of research has gone into the engine from Microsoft Research and others.  Language translation isn’t an easy task especially taking into consideration cultural significance of words, etc.  I have heard that the most challenging in machine translation is to Asian languages.  I will admit to not speaking any of them, so I don’t know how well we are performing here – you’ll have to let that team know if they are doing well.

After reading the announcement and working on my translate plugin for the new Seesmic Desktop Platform, I noticed that there was a Speak API.  After reading I saw this literally translates text to a WAV file for platback.  Pretty cool I thought.  I wanted to play around with this in Silverlight so created a simple application to do so:

Microsoft Translator in Silverlight

The Speak translation isn’t available for all the Translator languages (currently 30 languages for text language translation) but does support seven (7) languages: English, German, Spanish, French, Italian, Portuguese, and Russian.  So how is Silverlight talking back to you?

The Translator API comes in 3 flavors: SOAP, HTTP and Ajax.  Now I could have used the SOAP version and used Add Service Reference but I felt for what I was doing this was overkill.  The SOAP API doesn’t return me back super-strongly typed objects, so I saw little value in doing that over the REST-based HTTP methods which I decided to use.  The code is relatively simple.  I first want to translate the text input into the selected language, then pass the translated text to the Speak API and play the results in a MediaElement.

First, we use the Translate method and a WebClient call to accomplish this:

   1: private void TranslateTextToAudio(object sender, RoutedEventArgs e)
   2: {
   3:     if (Languages.SelectedIndex < 0)
   4:     {
   5:         MessageBox.Show("Please select a language first...");
   6:         return;
   7:     }
   8:     WebClient client = new WebClient();
   9:     client.OpenReadCompleted += ((s, args) =>
  10:         {
  11:             if (args.Error == null)
  12:             {
  13:                 DataContractSerializer des = new DataContractSerializer(typeof(string));
  14:                 string responseText = des.ReadObject(args.Result) as string;
  15:                 SpeakIt(responseText);
  16:             }
  17:         });
  18:     client.OpenReadAsync(new Uri(string.Format(TRANSLATE_URI, _appId, HttpUtility.UrlEncode(TextToTranslate.Text), Languages.SelectedValue.ToString(), _currentLang)));
  19: }

Notice the DataContractSerializer use here.  The HTTP API returns serialized objects, so you’ll want to use this method here to deserialize to make it easier.

After we have the translated text, we pass that to the Speak API (notice the call to SpeakIt above) which returns a Stream that is an audio/wav format.   We know that Silverlight’s MediaElement cannot directly play lossless WAV format.  But luckily there is a MediaStreamSource API that enables us to essentially write our own decoders for audio/video.  One of the Silverlight team members, Gilles, created a WAV MediaStreamSource for us to use.  After having that and not worrying about decoding, I could create a new WaveMediaStreamSource with my result Stream and set that as the Source for the MediaElement – here is the resulting SpeakIt() method (TranslatedPlayback is the name of my MediaElement in the application):

   1: private void SpeakIt(string responseText)
   2: {
   3:     WebClient client = new WebClient();
   4:     client.OpenReadCompleted += ((s, args) =>
   5:     {
   6:         if (args.Error == null)
   7:         {
   8:             WaveMediaStreamSource mss = new WaveMediaStreamSource(args.Result);
   9:             TranslatedPlayback.SetSource(mss);
  10:         }
  11:     });
  12:     client.OpenReadAsync(new Uri(string.Format(SPEAK_URI, _appId, responseText, Languages.SelectedValue)));
  13: }

That’s it!  It’s pretty cool (bonus points to you in identifying the obvious pre-filled text being used in my sample).

I’ve almost completed my Seesmic plugin and using the Translator API has made it easier.  I’ve found that a simple wrapper to the HTTP-based methods is going to make things easier for people to use, so I’ve created a Translator Client for Silverlight that I’ll be releasing once I can complete the plugin (waiting on a few things).  This will make it easier for Silverlight developers to quickly consume the API for text and Speech translation.

The code (C#) for the above sample is here: MSTranslatorSilverlightSample.zip.  You will need a Translator Application ID key to run it yourself (put it in the App.xaml resources).  If you just want to see it running really quick, you can view it here: Speak Translator for Silverlight.  You will need Silverlight 4 RC to run the sample.

NOTE: The Translator API actually doesn’t need Silverlight 4, but I just created the app using that base.

Hope this helps!

| Comments

If your a developer that spends any time with web services, you’ll basically probably end up working in one of two camps: REST- or SOAP-based services.  Now with SOAP services you’re likely used to having a WSDL document describing the service, providing type definitions, etc. – something you can use developer tools like Visual Studio to Add Service Reference and get a strongly-typed object model to work with.

If you’ve been doing Silverlight or ASP.NET (or any other technology really) development with mashup services, you probably have been working with REST-based services.  These are services that don’t self-describe themselves in a manner like SOAP with WSDL does.  Often I’ve found that really only the larger REST service providers provide good documentation for their services.  As a consumer of a REST service, you’re at the mercy of the documentation to understand the structure of the requests/responses that you’ll be working with…at times that can be frustrating.  If you are like me, you’ve probably either found someone else’s wrapper to the API or tried to work some other method to avoid spelunking the XML nodes.

If you don’t need to take on the full wrapper that you may have found someone already doing and maybe just need to consume something quick or whatever, enter Paste XML as Types.  Located in the WCF REST Starter Kit Preview 2, this is a Visual Studio new option under the Edit menu.  Let’s take a look at an example.

Twitter sounds like it would be a good example, but honestly they provide so many different formats (JSON, XML, RSS) that I’m not sure you would really want the XML version when RSS is more of a known type and easy to work with.  So let’s look at the Flickr API which is a similarly popular one and has a well-documented REST interface.  Let’s say you wanted to work with the results of their ‘interestingness’ public query which will provide you with a list of photos.  We can see in their documentation that they provide us with a sample response:

   1: <photos page="2" pages="89" perpage="10" total="881">
   2:     <photo id="2636" owner="[email protected]" 
   3:         secret="a123456" server="2" title="test_04"
   4:         ispublic="1" isfriend="0" isfamily="0" />
   5:     <photo id="2635" owner="[email protected]"
   6:         secret="b123456" server="2" title="test_03"
   7:         ispublic="0" isfriend="1" isfamily="1" />
   8: </photos>

Sweet.  Copy that sample response.  Go into Visual Studio in your project class file (or create a new one), go to the edit menu:

Paste XML as Types

Booyah!  Watch as the magic happens and the XML structure is transformed into strong types for you.

Well, sorta.  Turns out while I think this is a cool feature, it might have some work still to go.  My first assumption was that the documentation on Flickr matched exactly the response (heck, it says sample response).  But it really is only the response body.  There was some missing response header nodes.  You should call the API directly to see a real response.  Second, even with that it looks like I’m getting some weird namespace stuff.

But regardless of that, even taking an XML file and being able to reflect on that to create an object model on paste is pretty cool. 

Try this out – if you see issues leave comments on the WCF REST Starter Kit site so they can see them – you’re welcome to leave them here as well, but I’m not on that team and it’s better to give direct feedback on their project.

| Comments

When working with data and Silverlight there has often been the questions of wondering why when a service call fails that Silverlight returns the HTTP 404 status code.  In fact I’ve written about troubleshooting those types of issues in the past and tools you can use to help investigate some problems.

Still people mostly ask "if there is an exception, why is Silverlight telling me ‘not found’ instead of sending me the exception?'”  Eugene Osovetsky from the connected systems team aims to answer those questions in a recent post with a little more detail than has been provided in the past as well as offering some suggestions.  From his post, this is one of the main reasons which I’ve echoed in discussions, webcasts, forums in the past as well:

“Unfortunately, web browsers have a limitation with regards to status codes: When a browser plugin (such as Silverlight) makes an HTTP request, and the response status code is not 200, the browser hides the actual status code and the message body from the plugin. All Silverlight knows is that "something went wrong", but it has no way of discovering any details.”

Take a look at Eugene’s post for some other helpful suggestions.

| Comments

I ran into an interesting situation last week…the desire to access some of my Amazon S3 services from within a Silverlight application.

Amazon Simple Storage Solution (S3) is a pay service provided Amazon for object storage ‘in the cloud.’  Although there is no UI tool provided by Amazon to navigate your account in S3, a SOAP and REST API are available for developers to integrate S3 information into their applications or other uses.  You can view more information about Amazon S3 on their site.

What is S3?

Since S3 is a pretty flexible service, it can be used for many different things including storing “objects” like serialized representations of a type or something.  A lot of applications these days are using cloud storage to store their application objects like this.  For me, I use it as a file server in the cloud.  Mostly it is there to host my images on this site as well as downloads and such.  Because there is no user interface I collaborated with Aaron to make the S3 Browser for Live Writer so that I could access my files for when I need them in posting content.

Accessing content from S3 also has different meanings, even with regard to Silverlight.  For example, if you wanted to simply set an Image source to a hosted image on S3, you could easily do that using the URL provided by S3 to the object.  Since Silverlight allows media assets to be sourced from anywhere, this is not a problem.

The Problem

The problem comes when you want to download content in otherways, such as maybe a file stored there, a serialized object, or access their services in a Silverlight application.  Why is this a problem?  Well because S3 does not expose any cross-domain policy files in their implementation.  RIA platforms like Silverlight require a policy file from the providing service to exist in order to make cross-domain calls from the platform. 

You can read more about Silverlight’s cross-domain policy information here:


So how can we accomplish this?

The S3 Service APIs

Amazon exposes two service APIs: SOAP and REST.  Because of the requirements around using their REST service and providing an Authorization header, we are unable to use that in Silverlight at this time since Authorization is a restricted header we cannot modify at this time.  So we can use their SOAP service.  This is fine for Silverlight because Amazon provides a WSDL for us to generate a proxy with.  The defined endpoint in the WSDL for the service is https://s3.amazonaws.com/soap.  This is important so remember this.  Let’s move on.

Buckets to the rescue!

S3 uses a concept they call buckets to store information in containers.  I’m not going to into a lot of detail explaining this concept so if you want to learn more, read their documentation.  Basically a bucket is global unique to the service (not to your account)…so there can only exist one “timheuer” bucket across the service, name them accordingly :-).  All data you push to S3 must be in a bucket.  When you create a bucket, you can also access content in that bucket using a domain shortcut system.  For example when you create a bucket called “timheuer” and put a file in there called foo.txt, it has the URI of http://timheuer.s3.amazonaws.com/foo.txt.  Notice the alias that is happening here.  We can now use this method to solve some of our issues.  How?  Well the “/soap” key will be available at any bucket endpoint!

Because of this aliasing, we can use this mechanism to ‘trick’ the endpoint of our service to respond to the policy file request…so let’s review how we’ll do this.

Step 1: Create the bucket

There are different ways you could do this.  You could simply put a bucket called “foo” and use that, or you can completely alias a domain name.  I’m choosing to completely alias a domain name.  Here’s how I did it.  First I created a bucket called timheueraws.timheuer.com – yes that full name.  That’s a valid bucket name and you’ll see why I did the full one in a moment.

Step 2: Alias the domain

If you have control over your DNS, this is easy, if you don’t, you may want to use the simple bucket aliasing.  But I went into my DNS (I use dnsmadeeasy.com btw, and it rocks, you should use it too).  I added a CNAME record to my domain (timheuer.com):

   1: CNAME    timheueraws    timheueraws.timheuer.com.s3.amazonaws.com.    86400    

What does this mean?  Well any request to timheueraws.timheuer.com will essentially be made at timheueraws.timheuer.com.s3.amazonaws.com.  The last parameter is the TTL (time-to-live).

UPDATE: For security reasons you should actually stick with using only a bucket name and not a CNAME'd bucket.  This will enable you to use the SSL certificate from Amazon and make secure calls.  For example a bucket names "foo" could use https://foo.s3.amazonaws.com/soap as the endpoint.  This is highly adviseable.

Step 3: Create the clientaccesspolicy.xml file

Create the policy file and upload it to your bucket you created in step 1.  Be sure to set the access control list to allow ‘Everyone’ read permissions on it or you’ll have a problem even getting to it.

Creating the Silverlight application

Create a new Silverlight application using Visual Studio 2008.  You can get all the tools you need by visiting the Getting Started section of the Silverlight community site.  Once created let’s point out the key aspects of the application.

Create the Amazon service reference

In your Silverlight application, add a service reference.  The easiest way to do this by right-clicking on the Silverlight project in VS2008 and choosing Add Service Reference.  Then in the address area, specify the Amazon S3 WSDL location:

This will create the necessary proxy class code for us as well as a ServiceReferences.clientconfig file.

Write your Amazon code

Now for this simple purposes, let’s just list out all the buckets for our account.  There is an API method called “ListAllMyBuckets” that we’ll use.  Now Amazon requires a Signature element with every API call – it is essentially the authentication scheme.  The Signature is a hash of the request plus your Amazon secret key (something you should never share).  This can be confusing to some, so with the perusing of various code libraries on the Amazon doc areas, I came up with a simplified S3Helper to be able to do this Signature generation for us.

   1: public class S3Helper
   2: {
   3:     private const string AWS_ISO_FORMAT = "yyyy-MM-ddTHH:mm:ss.fffZ";
   4:     private const string AWS_ACTION = "AmazonS3";
   6:     public static DateTime GetDatestamp()
   7:     {
   8:         DateTime dteCurrentDateTime;
   9:         DateTime dteFriendlyDateTime;
  10:         dteCurrentDateTime = DateTime.Now;
  11:         dteFriendlyDateTime = new DateTime(dteCurrentDateTime.Year,
  12:             dteCurrentDateTime.Month, dteCurrentDateTime.Day,
  13:             dteCurrentDateTime.Hour, dteCurrentDateTime.Minute,
  14:             dteCurrentDateTime.Second,
  15:             dteCurrentDateTime.Millisecond, DateTimeKind.Local);
  16:         return dteFriendlyDateTime;
  17:     }
  19:     public static string GetIsoTimestamp(DateTime timeStamp)
  20:     {
  21:         string sISOtimeStamp;
  22:         sISOtimeStamp = timeStamp.ToUniversalTime().ToString(AWS_ISO_FORMAT, System.Globalization.CultureInfo.InvariantCulture);
  23:         return sISOtimeStamp;
  24:     }
  26:     public static string GenerateSignature(string secret, string S3Operation, DateTime timeStamp)
  27:     {
  28:         Encoding ae = new UTF8Encoding();
  29:         HMACSHA1 signature = new HMACSHA1(ae.GetBytes(secret));
  30:         string rawSignature = AWS_ACTION + S3Operation + GetIsoTimestamp(timeStamp);
  31:         string encodedSignature = Convert.ToBase64String(signature.ComputeHash(ae.GetBytes(rawSignature.ToCharArray())));
  33:         return encodedSignature;
  34:     }
  35: }

This will abstract that goop for us.

Let’s assume we have a ListBox in our Page.xaml file that we’re going to populate with our bucket names.  Mine looks like this:

   1: <ListBox x:Name="BucketList">
   2:     <ListBox.ItemTemplate>
   3:         <DataTemplate>
   4:             <TextBlock Text="{Binding Name}" />
   5:         </DataTemplate>
   6:     </ListBox.ItemTemplate>
   7: </ListBox>

So let’s just add a simple method to our Loaded event handler calling our ListAllMyBuckets method.  Remember, everything in Silverlight with regard to services is asynchronous, so we’re actually going to call ListAllMyBucketsAsync from our generated code.  We’ll need a completed event handler where we will put our binding code.  Here’s my complete code for both of these:

   1: void Page_Loaded(object sender, RoutedEventArgs e)
   2: {
   3:     DateTime timeStamp = S3Helper.GetDatestamp();
   5:     s3 = new AWS.AmazonS3Client();
   7:     s3.ListAllMyBucketsCompleted += new EventHandler<AWS.ListAllMyBucketsCompletedEventArgs>(s3_ListAllMyBucketsCompleted);
   8:     s3.ListAllMyBucketsAsync(AWS_AWS_ID, timeStamp, S3Helper.GenerateSignature(AWS_SECRET_KEY, "ListAllMyBuckets", timeStamp));
   9: }
  11: void s3_ListAllMyBucketsCompleted(object sender, AWS.ListAllMyBucketsCompletedEventArgs e)
  12: {
  13:     if (e.Error == null)
  14:     {
  15:         AWS.ListAllMyBucketsResult res = e.Result;
  16:         AWS.ListAllMyBucketsEntry[] buckets = res.Buckets;
  17:         BucketList.ItemsSource = buckets;
  18:     }
  19: }

The AWS_AWS_ID and AWS_SECRET_KEY are constants in my application that represent my access key and secret for my S3 account.  You’ll notice that in this snippet above the “s3” object isn’t typed – that is because I have a global that defines it (you can see it all in the code download).

So now if we run this application, we should expect to see our bucket list populated in our ListBox, right?  Wrong.  We get a few exceptions.  First, we get an error because we can’t find the cross-domain policy file.  Ah yes, remember we’re still using the Amazon SOAP endpoint.  We need to change that.

Changing the Amazon endpoint

You may notice that the SOAP endpoint for S3 is an https:// scheme.  We won’t be able to use that using this method because of our aliasing and the fact that the SSL certificate wouldn’t match our alias.  So we need to change our endpoint.  There are two ways we can do this.

We can change this in code and alter our code by creating a new BasicHttpBinding and EndpointAddress and passing them into the constructor of new AWS.AmazonS3Client().  But that would be putting our configuration in code.  Remember that when we added the service reference we were provided with a ServiceReferences.clientconfig file.  Open that up and check it out.  It provides all the configuration information for the endpoint.  Now we could just change a few things.  I decided to create a new <binding> node for my use rather than alter the others.  I called it “CustomAWS” and copied from the existing one that was there.  Now because the default endpoint for S3 is a secure transport and we cannot use that, we have to change the <security> node to mode=”None” so that we can use our custom endpoint URI.

The second thing we do is in the <client> node change the address attribute and the bindingConfiguration attribute (to match new new config we just created).  Mine now looks like this in entirety:

   1: <configuration>
   2:     <system.serviceModel>
   3:         <bindings>
   4:             <basicHttpBinding>
   5:                 <binding name="AmazonS3SoapBinding" maxBufferSize="65536" maxReceivedMessageSize="65536">
   6:                     <security mode="Transport" />
   7:                 </binding>
   8:                 <binding name="AmazonS3SoapBinding1" maxBufferSize="65536" maxReceivedMessageSize="65536">
   9:                     <security mode="None" />
  10:                 </binding>
  11:               <binding name="CustomAWS" maxBufferSize="65536" maxReceivedMessageSize="65536">
  12:                 <security mode="None" />
  13:               </binding>
  14:             </basicHttpBinding>
  15:         </bindings>
  16:         <client>
  17:             <endpoint address="http://timheueraws.timheuer.com/soap" binding="basicHttpBinding"
  18:                 bindingConfiguration="CustomAWS" contract="Amz.AWS.AmazonS3"
  19:                 name="AmazonS3" />
  20:         </client>
  21:     </system.serviceModel>
  22: </configuration>

Now when we run the application it will work and if we sniff the traffic we’ll see that the first request is to our clientaccesspolicy.xml file that enables us to continue with the /soap requests:

Now we can see a list of our buckets and after wiring up some other code so that when we click on the bucket, we’ll see a list of all the objects, bound to a DataGrid (details blurred for privacy) :


Sweet, we’re done!  We’ve now been able to provide our own clientaccesspolicy.xml file in a place where it didn’t exist before and be able to call the service.  We can now use other methods perhaps to create a new bucket, put objects in buckets, etc.

So in order to do this, we’ve:

    • Created an alias to an bucket in our S3 account
    • Uploaded a clientaccesspolicy.xml file to that bucket
    • Changed the endpoint configuration in our service reference
    • Called the services!

I’ve included all the files for the above solution in the download file.  You’ll have to provide your own access key/secret of course as well as specify the endpoint address in the ServiceReferences.clientconfig file.

Hope this helps!  Please read Part 2 of this post.

| Comments

Stephen WaltherAre you poking around with the latest ASP.NET MVC (Model-View-Controller) bits?  If so, hopefully you are already aware of the resources available to you and the fact that Phil Haack is one of the program manager’s leading those efforts, and Scott Hanselman has been providing the community with some resources to jump start your learning.

Well, another member has just joined the ranks on the team I work for.  Stephen Walther, pictured here in his best book-cover pose ;-), has joined the team.  He actually joined earlier this month, but I’m just now getting around to welcoming him to our team and checking out the stuff he’s been doing.  He’s been on a great clip lately and I’ve been reading his latest 11 tips on ASP.NET MVC on his blog.  I’m really glad to have him on our team as I think we’ve got some great resources for ASP.NET, AJAX, MVC, Silverlight and Windows Client.

If you are messing around with the ASP.NET MVC framework, check out his site and subscribe.  We’ll be seeing a lot more of Stephen soon and I’m sure your ideas will be welcome to him as well!