AWS Developer Blog

Using Non-.NET Languages for Windows Store Apps

by Norm Johanson | on | in .NET | Permalink | Comments |  Share

In Version 2 of our AWS SDK for .NET, we added support for Windows Store apps by creating a .NET Windows Store app class library. This approach works great if you are writing your Windows Store app in a .NET language like C# or VB. It means most code written for the AWS SDK for .NET 3.5 and 4.5 will also work for Window Store apps (with the biggest difference being that all service operations must instead be called asynchronously). But what if you’re using C++ or Javascript instead of .NET and want to access AWS in a Windows Store app? This is still possible by creating a Windows Runtime Component that wraps the AWS calls you want to make.

What is a Windows Runtime Component

A Windows Runtime component is like a class library except it can be called into by any languages supported by the Windows Runtime. An important distinction from class libraries is all parameters and return types must be compatible Windows Runtime types. Windows Runtime components can be written in any supported Windows Runtime language. In our case, it needs to be done in C# or Visual Basic because we want to access the AWS SDK, which is a .NET class library.

Creating the Wrapper

In my example, I want my C++ Windows Store app to be able to put and get objects from Amazon S3. To get started, I’m going to create a C# Windows Runtime Component project called AWSWrapper. Then I’ll add a class called S3Wrapper with the following code.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;

using Amazon;
using Amazon.S3;
using Amazon.S3.Model;

namespace AWSWrapper
{
    public sealed class S3Wrapper
    {
	// For demo purposes, I'll embed the credentials. To get 
	// credentials securely to your application,
	// developers should look into strategies like the 
	// token vending machine, 
        // http://aws.amazon.com/articles/4611615499399490, or 
	// IAM Web Identity, 
        // http://aws.typepad.com/aws/2013/05/aws-iam-now-supports-amazon-facebook-and-google-identity-federation.html/
        const string ACCESSKEY = "";
        const string SECRETKEY = "";

        IAmazonS3 s3Client;

        private IAmazonS3 S3Client
        {
            get
            {
                if (this.s3Client == null)
                {
                    this.s3Client = new AmazonS3Client(
                        ACCESSKEY, SECRETKEY, RegionEndpoint.USWest2);
                }

                return this.s3Client;
            }
        }

        public IAsyncAction PutObjectAsync(string bucketName, 
              string key, IStorageFile storageFile)
        {
            PutObjectRequest request = new PutObjectRequest()
            {
                BucketName = bucketName,
                Key = key,
                StorageFile = storageFile
            };

            return this.S3Client.PutObjectAsync(request).AsAsyncAction();
        }

        public IAsyncOperation GetObjectAsync(string bucketName, string key)
        {
            GetObjectRequest request = new GetObjectRequest()
            {
                BucketName = bucketName,
                Key = key
            };

            return Task.Run(() =>
            {
                var task = this.S3Client.GetObjectAsync(request);
                var response = task.Result;
                return response.ResponseStream.AsInputStream();
            }).AsAsyncOperation();
        }
    }
}

This class wraps both the put and get operations to Amazon S3. Since this is a Windows Runtime component, I need to make sure the return types are valid Windows Runtime types. This is why instead of tasks being returned they are converted to IAsyncAction for put and IAsyncOperation with an IInputStream because neither Task nor Stream are valid Windows Runtime types. Note that error handling is being ignored for the purposes of keeping the sample simple.

Consuming the Wrapper

Now, in my C++ Windows Store app, I can add my newly created Windows Runtime component as a reference. Here is a sample showing the wrapper being used from a file picked using the FileOpenPicker.

void CppS3Browser::MainPage::Button_Click(
     Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
	FileOpenPicker^ openPicker = ref new FileOpenPicker();
	openPicker->ViewMode = PickerViewMode::Thumbnail; 
	openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary; 
	openPicker->FileTypeFilter->Append("*"); 

	create_task(openPicker->PickSingleFileAsync())
            .then([this](StorageFile^ file) 
	{
		if (file) 
		{ 
			AWSWrapper::S3Wrapper^ s3wrapper = 
                            ref new AWSWrapper::S3Wrapper();
			s3wrapper->PutObjectAsync(
                            this->bucketName, file->Name, file);
		}
	});
}

You can extend this pattern for any operations in the AWS SDK for .NET. Just make sure to convert the parameters and return types to Windows Runtime types.