Modifying the GET Request for the SharedAccesSignature Controller

Modifying the GET Request for the SharedAccesSignature Controller

In the previous post I noted that the code was pretty messy, particularly for the client code with a bunch of hardcoded literals. To fix this I’m going to encapsulate the full URL for blob storage into the server code, meaning that the client shouldn’t have to know the url of blob storage – this will make it easy to administer this in the future as things change.

It turns out that in order to make this change all I needed to do is to return the full blob container url (including the SAS) instead of just the SAS.

var ub = new UriBuilder(container.Uri.OriginalString)
{
    Query = container.GetSharedAccessSignature(sasPolicy).TrimStart(‘?’)
};
sas =  ub.Uri.OriginalString;

The client code of course needs to be updated to handle the full Uri being passed back – Note that we didn’t include the name of the blob as part of creating the Uri. This is something the client should do. Since the SAS is for access to the whole container, the client doesn’t have to request a new SAS for each blob, only for each container it wants to write to.

Saving Image to Blob Storage Using Shared Access Signature

Saving Image to Blob Storage Using Shared Access Signature

In this post I’m  going to bring together a couple of my previous posts that discuss retrieving and saving images, and retrieving a Shared Access Signature from a controller which will allow me to write to a particular container within Blob Storage. To complete the implementation I’ll use the Windows Azure Storage library from NuGet – it only installs for Windows platforms as there’s no PCKL or Xamarin support for this library currently.

image

As the Windows Azure Storage library is current platform specific, I’ll need to wrap it in a simple interface that makes it easy for me to write data to Blob Storage – I’ll come back to that. For the time being I’m just going to retrieve the SAS and use it along with the storage library to upload an image. So I’ll start by invoking the sharedaccesssignature controller using the GET verb as I want to ensure the container is created if it doesn’t already exist. This will return a SAS which I can use in the upload process.

public async Task<string> RetrieveSharedAccessSignature()
{
    var sas = await MobileService.InvokeApiAsync<string>(“sharedaccesssignature”, HttpMethod.Get,
        new Dictionary<string, string> { { “id”, “test” } });
    return sas;
}

Next I want to capture an image, in this case picking a photo, and uploading it to a specified blobg.

private async void CaptureClick(object sender, RoutedEventArgs e)
{
    var picker = new MediaPicker();
    var sas = string.Empty;
    using (var media = await picker.PickPhotoAsync())
    using (var strm = media.GetStream())
    {
        sas = await CurrentViewModel.RetrieveSharedAccessSignature();

        Debug.WriteLine(sas);

        // Get the URI generated that contains the SAS
        // and extract the storage credentials.
        var cred = new StorageCredentials(sas);
        var imageUri = new Uri(“
https://realestateinspector.blob.core.windows.net/test/testimage.png”);

        // Instantiate a Blob store container based on the info in the returned item.
        var container = new CloudBlobContainer(
            new Uri(string.Format(“
https://{0}/{1}”,
                imageUri.Host, “test”)), cred);

        // Upload the new image as a BLOB from the stream.
        var blobFromSASCredential = container.GetBlockBlobReference(“testimage.png”);
        await blobFromSASCredential.UploadFromStreamAsync(strm.AsInputStream());
    }

}

Clearly this code isn’t well factored but it’s here as a quick example of how you can use a SAS to upload content to blob storage.

Simplifying Shared Access Signature Generation with the Mobile Services ResourceBroker

Simplifying Shared Access Signature Generation with the Mobile Services ResourceBroker

In my post Storing the Big Stuff in Blob Storage I showed you how to manually create a shared access signature. The Azure Mobile Services team have done a really nice job of making this even easier with the ResourceBroker NuGet package. Getting started documentation is available via GitHub (https://github.com/Azure/azure-mobile-services-resourcebroker) and of course the package, which I’ve added to my Mobile Service project, is available via NuGet.

image

The changes I needed to make to my SharedAccessSignature controller are:

– Change my Web.config to include the ResourceBrokerStorageConnectionString appSetting – the documentation talks about adding this via the Configure panel of the mobile service portal but you’ll need to add it to web.config for debugging. Also the format of this string should be similar to the following:

<add key=”ResourceBrokerStorageConnectionString”
     value=”DefaultEndpointsProtocol=https;AccountName=realestateinspector;AccountKey=LxWu0q2UvQ7ddxXvIP3UfV4ozDkLpgaSkUxkK8————————–BYHTpTrAGaHjLoynH+61ng==” />

– Change the base class of the controller to ResourcesControllerBase (I needed to add an import statement to the top of the file too)

– Add routing information to the WebApiConfig.cs file (as per the documentation on GitHub)

// Create a custom route mapping the resource type into the URI.    
var resourcesRoute = config.Routes.CreateRoute(
     routeTemplate: “api/resources/{type}”,
     defaults: new { controller = “resources” },
     constraints: null);

// Insert the ResourcesController route at the top of the collection to avoid conflicting with predefined routes.
config.Routes.Insert(0, “Resources”, resourcesRoute);

– Initially I removed the contents of my controller but then I realised that there are limitations on the ResourceControllerBase (eg the Blob container must exist and that I needed to specify an actual blob, not just a container for access), so I kept my code and modified it to work with the new connection string.

public class SharedAccessSignatureController :  ResourcesControllerBase
{
    public async Task<string> Get(string id)
    {
        var sas = string.Empty;

        if (!string.IsNullOrEmpty(id))
        {
            // Try to get the Azure storage account token from app settings. 
            string storageAccountConnectionString;

            if (Services.Settings.TryGetValue(“ResourceBrokerStorageConnectionString”, out storageAccountConnectionString) )
            {
                // Set the URI for the Blob Storage service.
                var account = CloudStorageAccount.Parse(storageAccountConnectionString);
                // Create the BLOB service client.
                var blobClient = new CloudBlobClient(account.BlobStorageUri,account.Credentials);

                // Create a container, if it doesn’t already exist.
                var container = blobClient.GetContainerReference(id);
                await container.CreateIfNotExistsAsync();

                // Create a shared access permission policy.
                var containerPermissions = new BlobContainerPermissions();

                // Enable anonymous read access to BLOBs.
                containerPermissions.PublicAccess = BlobContainerPublicAccessType.Blob;
                container.SetPermissions(containerPermissions);

                // Define a policy that gives write access to the container for 1h
                var sasPolicy = new SharedAccessBlobPolicy()
                {
                    SharedAccessStartTime = DateTime.UtcNow,
                    SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(59).AddSeconds(59),
                    Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read
                };

                sas = container.GetSharedAccessSignature(sasPolicy);
            }
        }

        return sas;
    }
}

– To get my code to work I also had to amend the route to the following, adding the id as an optional parameter

var resourcesRoute = config.Routes.CreateRoute(
        routeTemplate: “api/sharedaccesssignature/{type}/{id}”,
        defaults: new { controller = “sharedaccesssignature”, id = RouteParameter.Optional },
        constraints: null);

Calling the controller from Fiddler can be done in two ways:

GET: http://localhost:51539/api/sharedaccesssignature/blob/test

POST: http://localhost:51539/api/sharedaccesssignature/blob
Content-Type: application/json
{
    “name”: “myblob”,
    “container”: “test”,
    “permissions”: “w”,
    “expiry”: “2015-12-01T07:34:42Z”
}

Don’t forget that if during debugging you set authenticationlevel to anonymous, to make sure you change it back to User or Application before publishing.

Adding Xamarin Components via Visual Studio

Adding Xamarin Components via Visual Studio

Sometimes you’ll want to use some of the components from the Xamarin component store. This can be done directly in Visual Studio. Right-click Components node within iOS or Android project and select Get More Components

image

Once added you’ll see the component listed in Solution Explorer under the Components node. However, the Components, like NuGet packages, are located at a solution level. This makes them easy to reference from other projects.

image

In this case the Xamarin.Mobile component can be referenced by our Universal, Windows Phone 8.0, iOS and Android projects. This will make performing operations such as selecting or capturing photos much easier. However, be aware that there are some APIs that aren’t supported across all platforms. For example whilst you can reference the component from the WP8.1 application, MediaPicker fails as it’s not supported.

Cross Platform File Storage with PCLStorage NuGet Package

Cross Platform File Storage with PCLStorage NuGet Package

Before I can get onto using the SharedAccessSignature to upload content to Blob storage I first need to generate and save content. As this relies on platform specific implementations of capturing images from the camera and then accessing the file system. I’ll start with the latter and I’ll use a NuGet package called PCLStorage which has implementations for all the platforms I’m interested in. From NuGet I locate the PCLStorage package and install it into the client applications.

image

In my MainViewModel I’ve added the following WriteFile and ReadFile methods that for the time being will write and read an simple text file:

private string fileText;

public string FileText
{
    get { return fileText; }
    set
    {
        if (FileText == value) return;
        fileText = value;
        OnPropertyChanged();
    }
}

public async Task WriteFile()

{
    var file =
        await
            FileSystem.Current.LocalStorage.CreateFileAsync(“test.txt”, CreationCollisionOption.ReplaceExisting);
    using(var stream = await file.OpenAsync(FileAccess.ReadAndWrite))
        using(var writer = new StreamWriter(stream))
        {
            await writer.WriteAsync(FileText);
        }
}
public async Task ReadFile()
{
    var file =
        await
            FileSystem.Current.LocalStorage.GetFileAsync(“test.txt”);
    using (var stream = await file.OpenAsync(FileAccess.Read))
    using (var reader= new StreamReader(stream))
    {
        FileText = await reader.ReadToEndAsync();
    }
}

The FileText property can be databound to a TextBox in the XAML based projects allowing for user input which will be persisted between application instances. The actual location of the file is platform specific, for example on WPF this file is located at C:UsersNickAppDataLocalRealEstateInspectorRealEstateInspector.Desktop1.0.0.0test.txt which is local data specific to both user and application. PCLStorage also defines a roaming storage option which again will be dependent on the platform implementation.

Storing the Big Stuff in Blob Storage

Storing the Big Stuff in Blob Storage

Often mobile applications need to store and retrieve large object data, typically photos and video. This is where Azure blog storage comes into play. In order to write into blob storage you need an access key. However, you’d never distribute an actual access key out to a mobile application, even temporarily, as it’s a really bad idea – if someone gets hold of the access key they have access to everything stored in your blob storage. Luckily blob storage has the notion of shared access signatures which you can think of as short term access passes to blob storage. These are typically created using a full access key and as such this operation is done service side.

I’m going to create a dedicated API just for granting shared access signatures to specific containers (which you can think of as single level folders). In this case the containers will be created with public read access on the contents – since the list of blobs per container will be protected and clients will still need a shared access signature in order to write to containers, this should be ample security for a large proportion of application scenarios.

I’ll start off by creating a new Storage area within the Azure management portal.

image

Once created you’ll need to record the storage account name (realestateinspector) and the storage account access key. Add these values into the appSettings section of the web.config file for the Azure Mobile Service

<appSettings>

  <add key=”STORAGE_ACCOUNT_NAME”
       value=”realestateinspector” />
  <add key=”STORAGE_ACCOUNT_ACCESS_KEY”
       value=”LxWu0q2UvQ7ddxXvIP3UfV4ozDkLpgaSkUx————————————33WBYHTpTrAGaHjLoynH+61ng==” />

I’ll create a new controller in my Azure Mobile Service based on the Custom Controller item template

image

The bulk of this api controller sits within a single GET operation:

[AuthorizeLevel(AuthorizationLevel.User)]
public class SharedAccessSignatureController : ApiController
{
    public ApiServices Services { get; set; }

    public async Task<string> Get(string containerToAccess)
    {
        var sas = string.Empty;

        if (!string.IsNullOrEmpty(containerToAccess))
        {
            // Try to get the Azure storage account token from app settings. 
            string storageAccountName;
            string storageAccountKey;

            if (Services.Settings.TryGetValue(“STORAGE_ACCOUNT_NAME”, out storageAccountName) &&
                Services.Settings.TryGetValue(“STORAGE_ACCOUNT_ACCESS_KEY”, out storageAccountKey))
            {
                // Set the URI for the Blob Storage service.
                var blobEndpoint = new Uri(string.Format(“
https://{0}.blob.core.windows.net”, storageAccountName));

                // Create the BLOB service client.
                var blobClient = new CloudBlobClient(blobEndpoint, new StorageCredentials(storageAccountName, storageAccountKey));

                // Create a container, if it doesn’t already exist.
                var container = blobClient.GetContainerReference(containerToAccess);
                await container.CreateIfNotExistsAsync();

                // Create a shared access permission policy.
                var containerPermissions = new BlobContainerPermissions();

                // Enable anonymous read access to BLOBs.
                containerPermissions.PublicAccess = BlobContainerPublicAccessType.Blob;
                container.SetPermissions(containerPermissions);

                // Define a policy that gives write access to the container for 1h
                var sasPolicy = new SharedAccessBlobPolicy()
                {
                    SharedAccessStartTime = DateTime.UtcNow,
                    SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(59).AddSeconds(59),
                    Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read
                };

                sas = container.GetSharedAccessSignature(sasPolicy);
            }
        }

        return sas;
    }
}

If you change the AuthorizationLevel to Anonymous you can run up this controller and use Fiddler to generate the shared access signature by invoking a GET on (eg http://localhost:51539/api/SharedAccessSignature/test, where test is the name of the container we’re requesting access to. If you want to check that the container has been created and the appropriate security set, you can use the CloudBerry Explorer for Azure Blob Storage.

image

After entering credentials you can immediately see the folders in your blob storage which will in this case have the container “test” which was created when I made the request to the SharedAccessSignature service.

image

You can also use Fiddler to prepare and launch a query – don’t forget to switch the AuthorizationLevel back to User before deploying your services otherwise anyone will be able to access content from your blob storage.

Sample App

Sample App

The following posts make up a series of posts written during the development of a Real Estate Inspector template application. They cover a range of mobile and Azure related topics that will hopefully assist others as they run into technical challenges during development.

ViewModel Refactoring, INotifyPropertyChanged and Running on UI Context with Dispatcher

ViewModel Refactoring, INotifyPropertyChanged and Running on UI Context with Dispatcher

In a previous post I showed how to use SignalR as one option for providing feedback to the client application during a long running service operation. However, I didn’t display this on the UI because that would have made the blog post long and complicated as I tried to explain propagating a change from a non-UI thread, back onto the UI thread so it could be displayed within the app. In this post I’m going to do just that – what’s interesting is that each platform handles this scenario slightly different with some caring about thread affinity, whilst others do not.

Firstly, I’ll update the layout to include a TextBlock that’s going to display the progress:

<TextBlock Text=”{Binding Progress}” />

In this case databinding to the Progress property on the MainViewModel:

private string progress;
public string Progress
{
    get { return progress; }
    set
    {
        if (Progress == value) return;
        progress = value;
        OnPropertyChanged();
    }
}

Note that as this property changes it calls the OnPropertyChanged method which will be used to raise the PropertyChanged event specified in the INotifyPropertyChanged interface – this is what the XAML data binding framework uses to detect when bound properties are changed. In this case I’m going to implement this interface in BaseViewModel, and have MainViewModel inherit from BaseViewModel, rather than implement it in every view model.

public class MainViewModel:BaseViewModel  { … }

public class BaseViewModel:INotifyPropertyChanged
{
   
public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));

    }
}

Now, let’s modify the delegate that gets invoked when we receive an update from the service. Previously we just had Debug.WriteLine(msg), let’s change that to  Progress=msg. When you run this in your Universal Windows application – BANG – Exception due to an attempt to update the UI (ie the Text attribute on the TextBlock) from a non-UI thread. Interestingly doing the same thing in the WPF application doesn’t throw the same exception. In order to update the Progress property, we first need to jump back onto the UI thread, which is fine, if we were working directly with the Page/View. However, we don’t have any notion of a Dispatcher, UI threads etc from within the MainViewModel. This sounds like another scenario for a dependency injected implementation, so here goes:

My BaseViewModel is extended to include a UIContext object:

private readonly UIContext context=new UIContext();

public UIContext UIContext

{
    get { return context; }
}

The UIContext object wraps and abstracts away the loading of an implementation of IUIContext:

public interface IUIContext
{
    Task RunOnUIThreadAsync(Func<Task> action);
}

public class UIContext
{
    private IUIContext runContext;
    private IUIContext RunContext
    {
        get
        {
            if (runContext == null)
            {
                runContext = ServiceLocator.Current.GetInstance<IUIContext>();

            }
            return runContext;
        }
    }

    public async Task RunAsync(Action action)
    {
        await RunAsync(async () => action());
    }

    public async Task RunAsync(Func<Task> action)
    {
        var context = RunContext;
        await context.RunOnUIThreadAsync(action);
    }
}

Of course, we now need an implementation of IUIContext for our Universal Windows application:

public class UniversalUIContext : IUIContext
{
    public async Task RunOnUIThreadAsync(Func<Task> action)
    {
        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,async  () => await action());
    }
}

And this needs to be registered with Autofac in the ClientApplicationCore – note the use of the NETFX_CORE compilation attribute.

CoreApplication.Startup(builder =>
{
    builder.RegisterType<SignalRFactory>().As<ISignalR>();
#if NETFX_CORE
    builder.RegisterType<UniversalUIContext>().As<IUIContext>();
#endif
});

And finally I need to go back to my initial progress statement and update it from msg => Progress = msg, to the following:

async msg =>
    await UIContext.RunAsync(() =>
    {
        Progress = msg;
    })

This issue isn’t specific to Universal applications, and you should always make sure you have access to the UI thread when making UI changes (such as updating data bound properties).

A Simple ViewModelLocator for Spawning ViewModels for XAML Based Applications

A Simple ViewModelLocator for Spawning ViewModels for XAML Based Applications

There are numerous frameworks out there that provide mechanisms for instantiating view models. Long again, when I first started building XAML based applications and became familiar with MVVM, I stepped through a number of different ways of creating and wiring up view models. In this post I’m going to show a very basic implementation of a locator to instantiate view models. Into the Core library I will add a ViewModelLocator class which exposes a property, Main, that will return a new instance of the MainViewModel.

public class ViewModelLocator
{
    public MainViewModel Main
    {
        get { return CreateViewModel<MainViewModel>(); }
    }

    private T CreateViewModel<T>() where T:new()
    {
        return new T();
    }
}

I’m going to want a single instance of this class to be created and kept around for the duration of my application’s lifecycle. One option would be to instantiate it within my ApplicationCore class I introduced previously. However, I actually want the instance of the ViewModelLocator to be accessible via XAML, so for this reason it makes more sense to instantiate it as a XAML resource. In the WPF and Universal (Win/WP8.1) applications I can simply add this to the app.xaml file to the Application.Resource element.

<Application.Resources>
        <core:ViewModelLocator x_Key=”Locator” />
</Application.Resources>

In the MainWindow (WPF) and MainPage (Universal) I can now specify the DataContext in the opening element, removing the need to create the MainViewModel in code in the codebehind file. Eg

<Window x_Class=”RealEstateInspector.Desktop.MainWindow”
        http://schemas.microsoft.com/winfx/2006/xaml/presentation"”>http://schemas.microsoft.com/winfx/2006/xaml/presentation”
        http://schemas.microsoft.com/winfx/2006/xaml"”>http://schemas.microsoft.com/winfx/2006/xaml”
        DataContext=”{Binding Main, Source={StaticResource Locator}}” >

The current implementation of Xamarin.Forms doesn’t seem to support creating Application resources in XAML. However, by tweaking the App constructor, I can add an instance of the ViewModelLocator:

public App()
{
    Resources = new ResourceDictionary();
    Resources.Add(“Locator”, new ViewModelLocator());

    MainPage =new MainPage();
}

The syntax in the MainPage of the XForms application is similar except BindingContext replaces DataContext:

BindingContext=”{Binding Main, Source={StaticResource Locator}}”

There seems to be a quirk in XForms at the moment in that the Binding expression calls to the Main property repeatedly – since it gets a different instance of the MainViewModel back each time, it ends up in an endless loop trying to get a consistent value. To prevent this, we can add a view model dictionary to the ViewModelLocator and change the behaviour to always return the same instance of the view model.

private readonly Dictionary<Type, object> viewModels = new Dictionary<Type, object>();

private T CreateViewModel<T>() where T:new()
{
    var type = typeof (T);
    object existing;
    if (!viewModels.TryGetValue(type, out existing))
    {
        existing = new T();
        viewModels[type] = existing;
    }
    return (T)existing;
}

And there you have it – view model location across all applications.