Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

NuGet does my head in….. No thanks to Xamarin.Forms

This is a bit of a rant with hopefully a fix that will help others. Firstly, the rant:

In my post on Building Cross Platform Apps I used the new project templates in Visual Studio 2017 to create a new Xamarin.Forms application that targets iOS, Android and UWP. What I didn’t mention is the time I wasted trying to upgrade NuGet packages in order to get the thing to build and run. Namely I get the following exception when attempting to build the newly created application.

Severity    Code    Description    Project    File    Line    Suppression State
Error        Exception while loading assemblies: System.IO.FileNotFoundException: Could not load assembly 'Xamarin.Android.Support.v7.RecyclerView, Version=1.0.0.0, Culture=neutral, PublicKeyToken='. Perhaps it doesn't exist in the Mono for Android profile?
File name: 'Xamarin.Android.Support.v7.RecyclerView.dll'
   at Java.Interop.Tools.Cecil.DirectoryAssemblyResolver.Resolve(AssemblyNameReference reference, ReaderParameters parameters)
   at Xamarin.Android.Tasks.ResolveAssemblies.AddAssemblyReferences(DirectoryAssemblyResolver resolver, ICollection`1 assemblies, AssemblyDefinition assembly, Boolean topLevel)
   at Xamarin.Android.Tasks.ResolveAssemblies.Execute(DirectoryAssemblyResolver resolver)    App5.Droid           

I figured that there was something wrong with the Xamarin.Forms and/or Xamarin Android NuGet packages, so I thought I’d just go an upgrade the Xamarin.Forms NuGet package. Note: Don’t every try to upgrade the Xamarin Android packages independently – let the Xamarin.Forms NuGet package determine which versions of those libraries you need. Anyhow, unfortunately that just generates another exception:

Severity    Code    Description    Project    File    Line    Suppression State
Error        Unable to resolve dependencies. 'Xamarin.Android.Support.Compat 24.2.1' is not compatible with 'Xamarin.Android.Support.Design 24.2.1 constraint: Xamarin.Android.Support.Compat (= 24.2.1)'.            0   

At this point I was starting to get annoyed – it looks like there was already an inconsistency between the Xamarin.Forms package and the Xamarin Android packages included in the template. Luckily it was easier to fix than I thought it was. I opened up the packages.config file for the Android head project and delete the Xamarin.Android libraries.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Xamarin.Android.Support.Design" version="23.4.0.1" targetFramework="monoandroid60" />
  <package id="Xamarin.Android.Support.v4" version="23.4.0.1" targetFramework="monoandroid60" />
  <package id="Xamarin.Android.Support.v7.AppCompat" version="23.4.0.1" targetFramework="monoandroid60" />
  <package id="Xamarin.Android.Support.v7.CardView" version="23.4.0.1" targetFramework="monoandroid60" />
  <package id="Xamarin.Android.Support.v7.MediaRouter" version="23.4.0.1" targetFramework="monoandroid60" />

  <package id="Xamarin.Forms" version="2.3.2.127" targetFramework="monoandroid60" />
</packages>

Then, I just upgraded Xamarin.Forms to the latest NuGet package and all was good again. Lastly, I upgraded all the other NuGet packages (excluding the Xamarin.Android packages) to the latest stable versions.

When I grow up I want to be a .NETStandard Library!

A month or so ago we made the decision to upgrade some of the portable libraries we use for projects from being based on PCL Profiles (eg profile 111 or profile 259) across to .NET Standard. To do this, we followed the upgrade prompt in the project properties page in Visual Studio.

image

After clicking the “Target .NET Platform Standard” you can then pick which .NET Standard you want. Where possible we try for .NETStandard 1.0, which aligns with PCL Profile 259, or .NETStandard 1.1, which aligns with PCL Profile 111 (see https://docs.nuget.org/ndocs/schema/target-frameworks). The theory being that a .NETStandard 1.0 library can be consumed by any .NETStandard library 1.0 and above, as well as any PCL profile library that is profile 259 – in other words, we’re aiming for maximum reach.

Take for example, BuildIt.General, which is a general purpose utility library. This is now a .NETStandard 1.0 library….. or so we thought. I was doing some testing on the current stable version of the library to make sure it could be added into a Xamarin Forms application. In my previous post I showed how easily you can create a new Xamarin Forms project that has a PCL that contains all the UI for the application, and then head projects for each target platform (iOS, Android, UWP). Before adding in BuildIt.General I upgraded all the existing NuGet references – always good practice when creating new project (disclaimer: this sounds easier than it is due to an issue with the current Xamarin.Forms template which makes it hard to upgrade – more on this in a future post).

Next I added a reference to the BuildIt.General NuGet package – I made sure it was added to all projects as it includes a UWP library that has some useful extensions such as converters that are specific to UWP. At this point everything was able to build and I was able to run the UWP application (I didn’t get round to running the other platforms but I assumed that they would also work since I hadn’t really modified anything from what comes out of the box). I then wanted to test that I could invoke functions from the BuildIt.General library, so I added the following into the MainPage.xaml.cs file within the Xamarin.Forms PCL library:

LogHelper.Log("test");

Now, when I attempted to build the library I got the following error:

The primary reference "BuildIt.General, Version=1.0.0.20, Culture=neutral, processorArchitecture=MSIL" could not be resolved because it was built against the ".NETPortable,Version=v5.0" framework. This is a higher version than the currently targeted framework ".NETPortable,Version=v4.5,Profile=Profile259".

This completely confused me….. what’s this reference to .NETPortable and what’s the difference between v5.0 and v4.5. Immediately I thought that it was an issue with Visual Studio 2017 but after a bit of investigating it turns out that it’s a more fundamental issue with the way that we, actually MSBuild/Visual Studio, is creating the BuildIt.General library. I came across this thread which includes this comment:

image

(Oren has one of the best explanations on the whole .NET Standard v’s PCL Profile discussion at https://oren.codes/2016/06/23/portable-is-dead-long-live-netstandard/)

Anyhow, I wondered whether our library was suffering from the same ill fate. Using ILSpy I took a look at what was included as the TargetFramework and sure enough it’s listed as .NETPortable, v5.0.

image

The workaround for this was listed in this changeset. In summary it requires a change to the project file to override the default generation of the Target Framework Moniker (See bold pieces in the following extract). There are two parts to the change: the first specifies the filename where the TargetFrameworkMoniker assembly attribute will be written to, and then included in the build of the application; the second overwrites the generated TargetFrameworkMoniker.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="
http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
    ...
    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <TargetFrameworkProfile>
    </TargetFrameworkProfile>
    <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
   <TargetFrameworkMonikerAssemblyAttributesPath>$(IntermediateOutputPath)AssemblyTFMAttribute.cs.exclude</TargetFrameworkMonikerAssemblyAttributesPath>
    ...
  </PropertyGroup>
  ...
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
  <Target Name="_SetTargetFrameworkMonikerAttribute" BeforeTargets="GenerateTargetFrameworkMonikerAttribute">
    <PropertyGroup>
      <RealTargetFrameworkMoniker>.NETStandard,Version=v1.0</RealTargetFrameworkMoniker>
      <RealTargetFrameworkMonikerDisplayName>$(RealTargetFrameworkMoniker)</RealTargetFrameworkMonikerDisplayName>
      <TargetFrameworkMonikerAssemblyAttributeText Condition="'$(RealTargetFrameworkMoniker)' != '' and '$(TargetingClr2Framework)' != 'true'">
        // &lt;autogenerated /&gt;
        using System%3b
        using System.Reflection%3b
        [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(&quot;$(RealTargetFrameworkMoniker)&quot;, FrameworkDisplayName = &quot;$(RealTargetFrameworkMonikerDisplayName)&quot;)]
      </TargetFrameworkMonikerAssemblyAttributeText>
    </PropertyGroup>
  </Target>
</Project>

After making this change, and building a new version of the BuildIt.General library I can now see the correct Target Framework:

image

Out of interest, it appears that if you’re using the xproj project format targeting .NETStandard, it creates a library with the correct target framework. Hopefully this fix, will help you if you’re not.

Building Cross Platform Applications with Visual Studio 2017

Ok, before I jump into this, I want to point out a couple of things:

- Visual Studio 2017 is still in RC

- When you install the RC of Visual Studio 2017 and enable the options to install Xamarin, you will break any existing Xamarin support for earlier versions of Visual Studio (see https://www.visualstudio.com/en-us/news/releasenotes/vs2017-relnotes#KIXamarin).

I noticed the other day when I was creating a throwaway project is that there’s a new dialog when creating cross platform applications within Visual Studio 2017. In the New Project dialog, select the Cross Platform node and there is a single Cross Platform App option.

image

Selecting this option presents you with some project templates – there are only a couple at the moment but I’m hoping that they provide more examples.

image

Unfortunately, and it’s a little hard to see in this screenshot, for the Master Detail template, you can only select Shared Projects. Without exploring the template, I can only assume it was setup this way to share UI code that has platform specific code that compiles based on conditional flags. I really like the way that you can switch between a Forms application and a Native (and no they don’t literally mean “native” (eg Objective-C/Swift or Java/C++), they mean traditional Xamarin where you have platform specific UI.

I opted for the “Blank App (XAML)” which requires Forms, I selected PCL, but unfortunately the “Host in the cloud” option was then disabled. After hitting Accept, the new solution was created and I was immediately able to build and run the application across iOS, Android and Windows (UWP). Very nice.

Building a Mulit-Tenant Rich Client (UWP) that Connects via an Azure AD Protected WebAPI Through to an External Service

Wow, that title is a mouthful. Just reading that makes you think that this is some weird edge case that you’d never have to deal with but this is actually quite a common scenario. Let me give you the scenario we were trying to get to work:

- The user of the rich client application (I’ll use a UWP application but could be an iOS, Android, WPF, or in fact an external web site) needs to retrieve some information from their Office365 account. The required information isn’t currently available via the Graph API, so it requires the use of the Exchange Web Service (EWS) library, which is really only usable in applications written using the full .NET Framework (ie no PCL support). This means any calls to Exchange have to be proxied via a service (ie Web API) interface. Routing external calls via a service proxy is often a good practice as it makes the client application less fragile, making it possible to change the interactions with the external service without having to push out new versions of the application.

- Access to the WebAPI is protected using Azure AD. The credentials presented to the Web API will need to include appropriate permissions to connect through to Exchange using the EWS library.

- The user will need to sign into the rich client application. Their credentials will be used to access the Web API, and subsequently Exchange.

- Any user, from any tenant, should be able to sign into the rich client application and for information to be retrieved from their Exchange (ie Office 365) instance. In other words both the rich client and Web API need to be multi-tenanted.

Single Tenanted

I’ll start by walking through creating a single tenanted version of what we’re after. For this, I’m going to borrow the basic getting started instructions from Danny Strockis’ post (https://azure.microsoft.com/en-us/documentation/samples/active-directory-dotnet-webapi-onbehalfof/).

Creating the Applications

Let’s start by creating a new solution, Exchange Contacts, with a Universal Windows Platform (UWP) application, call it ExchangeContactsClient.

image

Next we’ll create a new ASP.NET Web Application project, call it ExchangeContactsWeb

image

For the moment I’m not going to setup either Authentication or hosting in Azure

image

Next I need to add the Active Directory Authentication Library (ADAL) NuGet package to both the WebAPI and UWP projects

image

To make it easy to debug and step through the interaction between the UWP application and the WebAPI I recommend setting Visual Studio up to start both projects when you press F5 to run. To do this, right-click the solution and select Set Startup Projects

image

I’d also suggest at this point running the solution to firstly make sure both applications are able to be run (ie that they were created correctly by Visual Studio) – I had to upgrade the Microsoft.NETCore.UniversalWindowsPlatform NuGet package in order for the UWP project to run. You also need to retrieve the localhost URL of the WebAPI that will be used later.

Local WebAPI URL: http://localhost:8859/

Configuring Azure AD

Before we continue developing the applications we’ll step over to Azure and configure the necessary applications in Azure Active Directory (Azure AD) – https://portal.azure.com. When you land on the Azure portal, make sure you’re working with the correct subscription – this is shown in the top right corner, under your profile information. In this case I’m going to be working with our Office 365 developer subscription (available for MSDN subscribers) called BTR Office Dev. This is associated with the btro365dev.onmicrosoft.com Azure AD tenant.

image

From the left side of the portal, select the Azure Active Directory node

image

Followed by selecting App registrations – this will list any existing Azure AD applications your organisation has.

image

You can think of an Azure AD application as a connector that allows your application to connect to Azure AD, so in order for both the UWP and WebAPI projects to connect to Azure AD I’ll need two new Azure AD applications

Register the WebAPI application

Click the Add button at the top of the list of the Azure AD applications

Give the application a friendly name (ExchangeContactsWeb), make sure the Application Type is set to Web app/API and specify the Sign-on URL. The Sign-on URL should be the Local WebAPI URL recorded earlier, ie https://localhost:8859/

image

After creating the Azure AD application for the Web API application, immediately select it from the list of Azure AD applications and take note of the Application Id.

image

Web API Client Id: 88e4051b-9f88-4ccb-9d0b-e7fca46c4430

Click on Keys and create a new key – the value of the key won’t appear until you save the new key. The name of the key isn’t that important, so just give it a name that will make sense to you. This key will be used by the web service as part of creating the authentication context when connecting to Azure AD in order to perform actions on behalf of the signed in user.

image

After clicking Save, the value of the new key will appear – make sure you take a copy of the key now as you won’t ever be able to see it again via the Azure portal.

image

App Key: T35aTVE9vrA5TEGCg9Jyw8wOzO47/IZpcN3NPeMDF/A=

 

Register the UWP application

Click the Add button at the top of the list of Azure AD applications

Give the application a friendly name (ExchangeContactsClient), make sure the Application Type is set to Native, and specify the Redirect URI (eg https://ContactsClient). The URL you specify for the Redirect URL doesn’t matter, so long as it’s a valid URL and that you specify the same Redirect URI within the UWP application when attempting to authenticate.

image

After creating the Azure AD application for the UWP application, immediately select it from the list of Azure AD applications and take note of the Application Id.

image

UWP Client Id: 1b64d2a6-32f4-4dba-9e3f-73def5520baa

 

Connecting the Azure AD applications

At this point you have two Azure AD application: one that the UWP application will use to connect to Azure AD, the other that the Web API will connect with. In order for a user to sign into the UWP application and request access to the Web API, these two Azure AD applications need to be connected. This is done by selecting the native application (ie ExhcnageContactsClient) from the list of Azure AD applications, selecting All Settings, followed by Required permissions, followed by the Add button. Type the start of the name of the WebAPI Azure AD application eg “exchange” to bring up the list of applications that can be added

image

image

As you can see from the images, this brings up No Results. This is because there appears to be an issue with the way that Azure AD applications are registered when created through the new Azure portal. Note that this is true at the time of writing this post, but may well be fixed in the future as the Azure AD management experience comes out of preview. The following step is required in order to fix this issue: Click on the Overview node, then at the top of the overview pane, click the link to the Classic portal. Alternatively you can just go to https://manage.windowsazure.com

image

Once in the classic portal, from the list of icons on the left side, select Active Directory (diamond icon), then select the WebAPI Azure AD application, followed by the Configure tab. Once on the configure tab, remove the trailing slash from the Sign-on URL (eg https://localhost:8859) and click Save. Then add the slash back to the Sign-on URL (eg https://localhost:8859/).

image

Doing this seems to re-register (correctly) the Web API Azure AD application. Whilst in the Classic portal, scroll down and locate the section entitled “single sign-on” and retrieve the App ID URI – this is the resource identifier for the Web API

image

Web API Resource Id: https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c

In the Azure portal (https://portal.azure.com) navigate back to the UWP Azure AD application (ie ExchangeContactsClient), All settings, Required permissions, Add and then again enter the start of the name of the WebAPI Azure AD application (eg “exchange”). This should now display the Web API Azure AD application (ie ExchangeContactsWeb).

image

Select the Azure AD application (ie ExchangeContactsWeb) and click Select to move onto selecting permissions

image

Check the box alongside “Access ExchangeContactsWeb” and click Select, followed by Done to complete the process of setting up permissions.

 

Building the Web Application

Add a new controller,ContactsController, into the Web API project.

image

In order to take advantage of Azure AD in order to authorize access to the Web API I need to add a reference to Microsoft.Owin.Security.ActiveDirectory.

image

At this point, it’s also worth making sure that other NuGet packages are updated – when preparing this sample the Newtonsoft.Json package had to be updated, along with making sure the binding redirect in web.config is updated

<dependentAssembly>
  <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
  <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>

The other NuGet reference that the ContactsController will need is Microsoft.Graph so that information can be retrieved on behalf of the user.

image

Next I’ll add a Get method to the new ContactsController. I’ll also apply the Authorize attribute to the ContactsController which will ensure any request has a bearer token. I’ll come back to the Get method later and add implementation details to retrieve Contacts

[Authorize]
public class ContactsController : ApiController
{
    public async Task<IEnumerable<string>> Get()
    {
        return new[]{"To be determined"};
    }

}

In order to use Azure AD to authenticate requests it’s also necessary to modify the Startup.Auth.cs

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Audience = ConfigurationManager.AppSettings["ida:Audience"],
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
                TokenValidationParameters = new TokenValidationParameters
                {
                    SaveSigninToken = true
                }
            });
    }
}

The Startup relies on two app settings that need to be added to the web.config

<add key="ida:Tenant" value="btro365dev.onmicrosoft.com" />
<add key="ida:Audience" value="https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c" />

The Tenant value is the name of the tenant where the Azure AD applications are defined. You’ll notice that the Audience value is the Web API Resource Id that was recorded earlier.

 

Building the UWP Application

I’ll start by adding a simple button to the MainPage of the application by modifying the file MainPage.xaml to include the following:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <Button Click="AuthenticateClick">Authenticate</Button>
    </StackPanel>
</Grid>

In the code behind file, MainPage.xaml.cs, I’ll add the following:

private const string Authority = "https://login.microsoftonline.com/btro365dev.onmicrosoft.com/";
private const string WebAPIResourceId = "https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c";
private const string UWPClientId = "1b64d2a6-32f4-4dba-9e3f-73def5520baa";
private static Uri RedirectUri { get; } = new Uri("https://ContactsClient");

private const string BaseServiceUrl = "http://localhost:8859";


private async void AuthenticateClick(object sender, RoutedEventArgs e)
{
    var authContext = new AuthenticationContext(Authority);

    try
    {
        var result = await authContext.AcquireTokenAsync(WebAPIResourceId, UWPClientId, RedirectUri,
            new PlatformParameters(PromptBehavior.Always, false));

        using (var httpClient = new HttpClient())
        {
            // Once the token has been returned by ADAL, add it to the http authorization header, before making the call to access the To Do list service.
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",result.AccessToken);

            // Retrieve the list of contacts
            var response = await httpClient.GetAsync(BaseServiceUrl + "/api/contacts");

            if (response.IsSuccessStatusCode)
            {
                // Read the response and databind to the GridView to display To Do items.
                var contacts = await response.Content.ReadAsStringAsync();
                Debug.WriteLine(contacts);
            }
        }

    }
    catch (AdalException)
    {
        // Handle both user cancelling sign in and/or authentication failure  
    }
}

This code defines a number of constants as follows:

Authority: This is the url where the user is navigated to in order to be authenticated against Azure AD – the BTR Office Dev tenant is clearly visible at the end of the Authority
WebAPIResourceId: This identified the resource that the initial authentication attempt is request access to
UWPClientId: In order to access Azure AD the UWP application uses the Azure AD native application setup earlier
RedirectUri: As the authentication is done via a web page, the RedirectUri defines where the browser will be navigated to at the end of the authentication process. In this case it’s a fake Uri, which has to correspond with the RedirectUri specified in the Azure AD native application.
BaseServiceUrl: This is the base url of the Web APIs that the application will be retrieving data from.

The code uses ADAL to acquire an access token, which can then be presented when invoking a Get operation on the ContactsController.

 

When you run the solution, you should see a web browser appear, as well as the ExchangeContacts application. Clicking the Authenticate button launches a familiar dialog that prompts for email address and password. At this point the user has to be a member of the btro365dev.onmicrosoft.com  tenant.

image

After signing in, the user will also be prompted to grant permission for the application to access information.

image

Side Note on the Access Token

After the authentication process is completed, it’s possible to extract the access token and then use a website like jwt.io, to unpackage the access token. For example, the following is taken from the results.AccessToken object after the user signs into the application.

eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFEUk5ZUlEzZGhSU3JtLTRLLWFkcENKaEFrMWJhQjJnRHpaN1J3OUh4WkI4dEdJUVFGdzI4WWVDd2dlRFYxRUZhRjJvMFd5MzFORG0tS0dWZTc1Rm9JOGdvSlBJa1hLSkVydmQzV19MajQwMWlBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiSTZvQnc0VnpCSE9xbGVHclYyQUpkQTVFbVhjIiwia2lkIjoiSTZvQnc0VnpCSE9xbGVHclYyQUpkQTVFbVhjIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC85MjY2ZmE2Yy0yYTU4LTRmMjQtYTI0Yi0yYTEzMTk4NTliM2UvIiwiaWF0IjoxNDc2ODg2MzAxLCJuYmYiOjE0NzY4ODYzMDEsImV4cCI6MTQ3Njg5MDQ5NywiYWNyIjoiMSIsImFtciI6WyJwd2QiXSwiYXBwX2Rpc3BsYXluYW1lIjoiRXhjaGFuZ2VDb250YWN0c1dlYiIsImFwcGlkIjoiODhlNDA1MWItOWY4OC00Y2NiLTlkMGItZTdmY2E0NmM0NDMwIiwiYXBwaWRhY3IiOiIxIiwiZV9leHAiOjExMDk1LCJmYW1pbHlfbmFtZSI6IlJhbmRvbHBoIiwiZ2l2ZW5fbmFtZSI6Ik5pY2siLCJpcGFkZHIiOiI2MC4yNDEuMTg1LjUwIiwibmFtZSI6Ik5pY2sgKE9mZmljZSAzNjUgRGV2KSIsIm9pZCI6IjdkY2NhYWQxLTZiZDgtNDZjMi1hZGM3LWQ1ODY2MjllMTAxMiIsInB1aWQiOiIxMDAzQkZGRDhFRDRBREUxIiwic2NwIjoiVXNlci5SZWFkIiwic3ViIjoiaW4wQklSdFNOblhHckhTNWlncGdCb2JvdU9Nc0x3V2NkRFhNVXdPbjNaZyIsInRpZCI6IjkyNjZmYTZjLTJhNTgtNGYyNC1hMjRiLTJhMTMxOTg1OWIzZSIsInVuaXF1ZV9uYW1lIjoibmlja0BidHJvMzY1ZGV2Lm9ubWljcm9zb2Z0LmNvbSIsInVwbiI6Im5pY2tAYnRybzM2NWRldi5vbm1pY3Jvc29mdC5jb20iLCJ2ZXIiOiIxLjAifQ.CfeVUjnJt8dGdKGFEK39piuhB4imbWJh06uqoonfU-gQmHB4VWgY0i43b-YyXZRP9z4SD7dXGiS1IzDUX4GT3VvlsCXq48RkkbSKVzZLVZk_VojiPDn3jSczw70VKFZrXqPCfRcvhbwnFBGTlY_06vtDT3jE-TACLc8jR3D_mTSL9d8akWsxUhVIw6vKaRuyTpBtnO7KO8KS87oLf0wJlKaSfWTO5Nykp5AUhQHfAOij33XOejy5dNIWkml00kO1agBP4WMCHm3EklLlOrnpW8K71KHweqflVK8Zzy8H6XORt3UZIFiCUUF1ORPxQgHpSNJ8Sqw7LlKGPxC6NHd9wA

Entering this into the site http://jwt.io this token can be extracted to show relevant information about the user and their permissions.

{
  "aud": "https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c",
  "iss": "https://sts.windows.net/9266fa6c-2a58-4f24-a24b-2a1319859b3e/",
  "iat": 1476887372,
  "nbf": 1476887372,
  "exp": 1476891272,
  "acr": "1",
  "amr": [
    "pwd"
  ],
  "appid": "1b64d2a6-32f4-4dba-9e3f-73def5520baa",
  "appidacr": "0",
  "e_exp": 10800,
  "family_name": "Randolph",
  "given_name": "Nick",
  "ipaddr": "60.241.185.50",
  "name": "Nick (Office 365 Dev)",
  "oid": "7dccaad1-6bd8-46c2-adc7-d586629e1012",
  "scp": "user_impersonation",
  "sub": "Qu6BNhi6dbma-rLraV_3B06be5DsdohiMlt8hJsHpVM",
  "tid": "9266fa6c-2a58-4f24-a24b-2a1319859b3e",
  "unique_name": "nick@btro365dev.onmicrosoft.com",
  "upn": "nick@btro365dev.onmicrosoft.com",
  "ver": "1.0"
}

As you can see, the information in this json the user is nick@btro365dev.onmicrosoft.com. What’s not immediately obvious is that this token has been issued by the BTR Office Dev tenant, which is the tenant that the Azure AD applications are defined – to be expected in a single tenanted scenario. In the Classic portal you can see the tenant Id when you select the Azure AD instance – it’s the guid that appears in the address bar. This is much less obvious in the new portal. This guid matches the guid in the iss field in the access token (ie "iss": https://sts.windows.net/9266fa6c-2a58-4f24-a24b-2a1319859b3e/)

image

 

Accessing Graph API

In the previous section we can see that the audience of the access token is https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c, which essentially is the identifier of the Web API in Azure, meaning that this access token can be presented when making requests to the Web API. However, if we then want to call on another service, in this case the Microsoft Graph API, we have to exchange this access token for one that is valid for the Graph API. The following code retrieves an access token for connecting to the Graph API and then uses it to retrieve the display name of the current user (Currently we haven’t assigned enough permissions to the Azure AD apps in order to query the Contacts for the user but by default they have permission to query information about themselves)

[Authorize]
public class ContactsController : ApiController
{
    private static string Authority { get; } = ConfigurationManager.AppSettings["ida:Authority"];
    private static string WebAPIClientId { get; } = ConfigurationManager.AppSettings["ida:WebAPIClientID"];
    private static string WebAPIAppKey { get; } = ConfigurationManager.AppSettings["ida:AppKey"];
    private static string GraphResourceId { get; } = ConfigurationManager.AppSettings["ida:GraphResourceId"];

    public async Task<IEnumerable<string>> Get()
    {
        var accessToken = await RetrieveAccessToken();
        return await RetrieveContacts(accessToken);
    }

    private static async Task<string> RetrieveAccessToken()
    {
        var clientCred = new ClientCredential(WebAPIClientId, WebAPIAppKey);
        var bootstrapContext =
            ClaimsPrincipal.Current.Identities.First().BootstrapContext as
                System.IdentityModel.Tokens.BootstrapContext;
        var userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null
            ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value
            : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
        var userAssertion = new UserAssertion(bootstrapContext?.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer",
            userName);
        var authContext = new AuthenticationContext(Authority);

        var result = await authContext.AcquireTokenAsync(GraphResourceId, clientCred, userAssertion);
        var accessToken = result.AccessToken;
        return accessToken;
    }


    public static async Task<IEnumerable<string>> RetrieveContacts(string accessToken)
    {
        var graphClient = new GraphServiceClient(
                    "https://graph.microsoft.com/v1.0",
                    new DelegateAuthenticationProvider(
                        async (requestMessage) =>
                        {
                            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
                        }));


        var data = graphClient.Me.Request();
        var getresult = await data.GetAsync();
        Debug.WriteLine(getresult != null);

        return new[] { getresult.DisplayName };
         
    }
}

This code relies on some additional web.config app settings

<appSettings>
  <add key="ida:Tenant" value="btro365dev.onmicrosoft.com" />
  <add key="ida:Audience" value="https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c" />
  <add key="ida:WebAPIClientID" value="88e4051b-9f88-4ccb-9d0b-e7fca46c4430" />
  <add key="ida:AppKey" value="T35aTVE9vrA5TEGCg9Jyw8wOzO47/IZpcN3NPeMDF/A=" />
  <add key="ida:Authority" value="https://login.microsoftonline.com/btro365dev.onmicrosoft.com" />
  <add key="ida:GraphResourceId" value="https://graph.microsoft.com" />
</appSettings>

 

Multi-Tenanted

So far we have an application that a user can sign into and invoke a protected service in order to retrieve information from the Graph API. Unfortunately this only works for users that are part of the BTR Office Dev tenant. For example if I sign in with the user tester@builttoroam.com, I see the following error: AADSTS50020: User account 'tester@builttoroam.com' from identity provider 'https://sts.windows.net/9236ecf1-cfae-41f7-829c-af7e3d09a7e6/' does not exist in tenant 'BTR Office Dev' and cannot access the application '1b64d2a6-32f4-4dba-9e3f-73def5520baa' in that tenant. The account needs to be added as an external user in the tenant first. Sign out and sign in again with a different Azure Active Directory user account.

image

Essentially this is saying that we’ve attempted to sign into a single-tenanted application. More specifically we’re attempting to sign into an application via an authority that doesn’t know or understand about the user we’re attempting to sign in with. The first change we’ll make is to the sign in authority in the UWP application.

private const string Authority = "https://login.microsoftonline.com/common/";

Now when we sign in, we see a different error: AADSTS70001: Application with identifier '1b64d2a6-32f4-4dba-9e3f-73def5520baa' was not found in the directory builttoroam.com

image

In this case, the error is saying that the UWP client application (ie the application with Azure Ad Client Id '1b64d2a6-32f4-4dba-9e3f-73def5520baa') doesn’t exist within the Built to Roam directory. This is correct, since it was created in the Btr Office Dev tenant. To address this issue, we need to indicate that this application should be enabled for other tenants (ie multi-tenanted). Open the Azure Ad application for the UWP application in the Azure portal and click the Manifest button. Adjust the “availableToOtherTenants” attribute to “true”

image

Now when you run the UWP application and attempt to sign in with a foreign user (eg tester@builttoroam.com) you see a different error, this time it appears in code, rather than the Azure authentication UI: Additional information: AADSTS50001: The application named https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c was not found in the tenant named builttoroam.com.  This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant.  You might have sent your authentication request to the wrong tenant.
This can be a little confusing as it’s not immediately obvious where the identifier “https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c “ comes from – the guid doesn’t match the application Id for any of the Azure Ad applications. It is in fact the Web API Resource Id, and it’s essentially saying that the Azure Ad application for the Web API doesn’t exist in the Built to Roam tenant. Again, this is true, since it was created in the Btr Office Dev tenant. Again, we need to adjust the Azure Ad application for the Web API to allow use for other tenants, by modifying the availableToOtherTenants attribute in the manifest.

image

Again, if you run the UWP application and sign in using a foreign user, you’ll see another, different, exception: Additional information: AADSTS65005: Resource '88e4051b-9f88-4ccb-9d0b-e7fca46c4430' does not exist or one of its queried reference-property objects are not present.

This error is much harder to diagnose as the error basically just says that either the Web API doesn’t exist (the resource it references is the Application Id of the Azure Ad application for the Web API) or that it isn’t configured correctly, but it doesn’t say what configuration isn’t correct. This is actually a very poorly documented configuration change required to get multi-tenancy to work. You have to let the Web API know about the UWP application by updating the manifest of the Web API Azure Ad application to include the application id of the UWP Azure Ad application in it’s list of known client applications. Set the knownClientApplications attribute to include the application id of the UWP Azure AD application (ie 1b64d2a6-32f4-4dba-9e3f-73def5520baa)

image

Running the UWP application and signing in using a foreign user now yields a permissions prompt, granting the UWP application permissions to access the user’s profile:

image

After giving approval, the UWP application will receive an access token eg eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ikk2b0J3NFZ6QkhPcWxlR3JWMkFKZEE1RW1YYyIsImtpZCI6Ikk2b0J3NFZ6QkhPcWxlR3JWMkFKZEE1RW1YYyJ9.eyJhdWQiOiJodHRwczovL2J0cm8zNjVkZXYub25taWNyb3NvZnQuY29tL2E1MjE1MWVkLThlODYtNDgyNy1iNjU3LTFjZDIwMDYxYjg2YyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkyMzZlY2YxLWNmYWUtNDFmNy04MjljLWFmN2UzZDA5YTdlNi8iLCJpYXQiOjE0NzY5MjAwNTYsIm5iZiI6MTQ3NjkyMDA1NiwiZXhwIjoxNDc2OTIzOTU2LCJhY3IiOiIxIiwiYW1yIjpbInB3ZCJdLCJhcHBpZCI6IjFiNjRkMmE2LTMyZjQtNGRiYS05ZTNmLTczZGVmNTUyMGJhYSIsImFwcGlkYWNyIjoiMCIsImVfZXhwIjoxMDgwMCwiZmFtaWx5X25hbWUiOiJVc2VyIiwiZ2l2ZW5fbmFtZSI6IlRlc3QiLCJpcGFkZHIiOiIxMTAuMTc0LjQ1LjIxOSIsIm5hbWUiOiJUZXN0IFVzZXIiLCJvaWQiOiJhNGE4OTA2Zi1hY2NmLTQyNDQtYmMyNC1kZmE5ODg3YTFiYTEiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJzdWIiOiJEMHVZTnF5QnJabkdidXRmbUhTaGg5WlR5UjhFcW51YW1ULURYeFlocmdnIiwidGlkIjoiOTIzNmVjZjEtY2ZhZS00MWY3LTgyOWMtYWY3ZTNkMDlhN2U2IiwidW5pcXVlX25hbWUiOiJ0ZXN0ZXJAYnVpbHR0b3JvYW0uY29tIiwidXBuIjoidGVzdGVyQGJ1aWx0dG9yb2FtLmNvbSIsInZlciI6IjEuMCJ9.YjLGoycr8pRdMaoJRD6FqhVzrV-TDsw3RJdzQ_IIwULAsyUVtjgQtq0wlsYo6O19JLxq99LhZMt4VwgCpaJzwoLQcL1TOOBR9LiBsEs9NdF2LJjMKLtC2_9tnaCjZA1o0ZqThWlwYlFfFRlRXn9M4Dx1CM-pRen3t4qnIP4jfkSFhVEKKxLnm_frUebpYDn2b3OyvlisP3V1uAhIHLUrjTr5vB4RZPkjfaWDxMFr2J4zzalnlTBgeB8FvbPxPfqr47AssfQ81gczKlFOI1lpnc2ddLndzNAoSG3TmrkesBYO_mtXHNjkQiersbbs-q3Mt1F4kY7AOMg64_9R72_wpg

If you expand this token, you’ll see that whilst the Audience hasn’t changed (since we’re still requesting access to the same resource), the issuing authority has (eg "iss": https://sts.windows.net/9236ecf1-cfae-41f7-829c-af7e3d09a7e6/). The issuing authority is now the Built to Roam tenant.

Even though the token now looks correct, when you attempt to call the Web API you’ll get a 401 Unauthorized exception, with almost no further information in the exception in the UWP application, nor will there be any exception thrown within the Web API. Luckily there is a configuration setting on the Web API that allows you to see more information about authentication failures. Add the following within the <configuration> tags of the Web.config file:

<system.diagnostics>
  <switches>
    <add name="Microsoft.Owin" value="Verbose" />
  </switches>
</system.diagnostics>

Now you’ll see something similar to the following in the Output window when debugging:

Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Error: 0 : Authentication failed
System.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10205: Issuer validation failed. Issuer: 'https://sts.windows.net/9236ecf1-cfae-41f7-829c-af7e3d09a7e6/'. Did not match: validationParameters.ValidIssuer: 'null' or validationParameters.ValidIssuers: 'https://sts.windows.net/9266fa6c-2a58-4f24-a24b-2a1319859b3e/'.
   at System.IdentityModel.Tokens.Validators.ValidateIssuer(String issuer, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateIssuer(String issuer, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateToken(String securityToken, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.Owin.Security.Jwt.JwtFormat.Unprotect(String protectedText)

Again, this error states what is failing but doesn’t really give much of an indication of what to do to fix it. This error essentially is saying that the authentication, despite configuring Azure Ad to be multi-tenanted, is still setup to only validate the Btr Office Dev users (ie against the https://sts.windows.net/9266fa6c-2a58-4f24-a24b-2a1319859b3e/ issuer). You just need to modify the Startup class of the WebAPI to disable issue validation:

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Audience = ConfigurationManager.AppSettings["ida:Audience"],
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
                TokenValidationParameters = new TokenValidationParameters
                {
                    SaveSigninToken = true,
                    ValidateIssuer = false
                }
            });
    }
}

Running again…. and you’d hope we’re close by now… you guessed it…. a different exception. This time it occurs when attempting to retrieve information from the Graph API: Operation not supported as user tester@builttoroam.com not found in tenant 9266fa6c-2a58-4f24-a24b-2a1319859b3e

Looking at this, it’s clear that the wrong tenant is being used. This is because when we’re requesting the access token for the Graph API resource, we’re again doing this against the Btr Office Dev tenant (to be honest, I’m not sure why that works at all but it does seem to issue an access token, that is probably useless for accessing any external resource not defined within the Btr Office Dev tenant). The fix is to change the Authority used by the Web API that’s in the web.config file:

<add key="ida:Authority" value="https://login.microsoftonline.com/common" />

Now, hey presto, it works… the user (in fact any Azure Ad user from any tenant) can sign into the UWP application and retrieve their display name via a call to the Web API.

 

Retrieving Contacts from Exchange

The last step is for us to extend this to connect through to Exchange (ie Office 365) in order to retrieve a list of contacts. Retrieving Contacts can now be done via the Graph API but there are still some things, such as querying for rooms, that can only be done via the Exchange Web Services (EWS). So, for this exercise we’re going to use the EWS to connect to Office 365 in order to retrieve a list of contacts.

Add the Microsoft.Exchange.WebServices NuGet package to the WebAPI project.

image

I’ll update the service code to retrieve an access token for the Office 365 instead of the Graph API and then retrieve contacts using EWS

private static string Office365ResourceId { get; } = ConfigurationManager.AppSettings["Office365ServerUrl"];
private static string EWSUrl { get; } = ConfigurationManager.AppSettings["EWSUrl"];

public async Task<IEnumerable<string>> Get()
{
    var accessToken = await RetrieveOffice365AccessToken();
    return RetrieveContacts(accessToken);
}


private static async Task<string> RetrieveOffice365AccessToken()
{
    var clientCred = new ClientCredential(WebAPIClientId, WebAPIAppKey);
    var bootstrapContext =
        ClaimsPrincipal.Current.Identities.First().BootstrapContext as
            System.IdentityModel.Tokens.BootstrapContext;
    var userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null
        ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value
        : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
    var userAssertion = new UserAssertion(bootstrapContext?.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer",
        userName);
    var authContext = new AuthenticationContext(Authority);

    var result = await authContext.AcquireTokenAsync(Office365ResourceId, clientCred, userAssertion);
    var accessToken = result.AccessToken;
    return accessToken;
}

public static IEnumerable<string> RetrieveContacts(string accessToken)
{
    var exchangeService = new ExchangeService
    {
        Url = new Uri(EWSUrl),
        TraceEnabled = true,
        TraceFlags = TraceFlags.All,
        Credentials = new OAuthCredentials(accessToken)
    };

    var contactsfolder = ContactsFolder.Bind(exchangeService,
                                            WellKnownFolderName.Contacts,
                                            new PropertySet(BasePropertySet.IdOnly, FolderSchema.TotalCount));
    var numItems = contactsfolder.TotalCount < 50 ? contactsfolder.TotalCount : 50;
    var view = new ItemView(numItems);

    // To keep the response smaller, request only the display name.
    view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ContactSchema.DisplayName);
    // Request the items in the Contacts folder that have the properties that you selected.
    var contactItems = exchangeService.FindItems(WellKnownFolderName.Contacts, view);

    return contactItems.Items.Select(x => (x as Contact)?.DisplayName).ToArray();


}

This code relies on two additional app settings in the web.config file

<add key="Office365ServerUrl" value="https://outlook.office365.com" />
<add key="EWSUrl" value="https://outlook.office365.com/ews/exchange.asmx" />

Update 20/11/2016: At this point you may see build issues with your code due to Visual Studio not being able to correctly resolve some types. To resolve this you need to add a reference to the System.IdentityModel assembly.

bo8

If you attempt to run this you’ll run into exceptions where the Azure AD applications don’t have permissions on the Office 365 Exchange Online resource. To resolve this open both Azure Ad applications (ie for the Web API and the UWP application) and add the Office 365 Exchange Online (Microsoft.Exchange) resource

image

Make sure you assign the “Access mailboxes as the signed-in user via Exchange Web Service” option which is a delegated permission that doesn’t require administrator approval.

image

When you run the application and sign in, the first time for each user, you’ll see a permissions request, giving access to the Exchange mailbox for the user.

image

Once approval has been granted, the UWP application will be able to connect to the Web API, and retrieve information from Office 365 via the Exchange Web Services.

Using BuildIt.States for Managing States

Almost every software development course at some point covers object orientated programming where the concept of encapsulation is drummed in. We’re taught to create classes that track state – a typical example is an Order that has a series of items, and then goes through various states as the order is processed. All this information is held within the Order object, including some basic functions such as calculating the total of the items being ordered. As the systems we work on grows in complexity, so does the complexity of the classes that are used to encapsulate aspects of the system. Unfortunately this often results in large, bloated classes, where it’s hard to make changes without fear of breaking other parts of the system.

One common mistake that seems to creep in over time is that it becomes difficult to manage what state a class is in. This can result from either a lack of documentation about what states the class can be in, or the states themselves aren’t clearly defined. Take the Order example, the Order class may have properties such as OrderTimestamp and OrderId which are set when the Order is placed. If the Order is rejected, the OrderTimestamp may be reset, leaving the class is some weird state where it has an OrderId, yet no OrderTimestamp. This is one of the scenarios that BuildIt.States is designed to help with.

Before we jump in, we need to set down a basic understanding of how we define states. States can appear in groups but within a group, there can only ever be one current state. For example in the Order scenario, there might be a group called TransactionStates, and the Order can only be in one of the states, Unprocessed, Processing, Processed, OrderRejected, at any given time. This leads me to the starting point of working with BuildIt.States: I’m going to define an enumeration that defines the states that my class can go between – you’ll notice this includes a Default (I often use Base instead) which BuildIt.States will use to determine if the state has been set or not.

public enum MainStates
{
    Default,
    One,
    Two,
    Three,
    Four
}

The next thing we need is our class, in this case one that inherits from NotifyBase, and raises a PropertyChanged event when the CurrentState property changes.

public class MainViewModel:NotifyBase
{
    private string currentState;

    public string CurrentState
    {
        get { return currentState; }
        set
        {
            currentState = value;
            OnPropertyChanged();
        }
    }
}

Defining the states that this class can be in is as simple as adding a reference to the BuildIt.States NuGet package and then defining each of the states:

public IStateManager StateManager { get; } = new StateManager();

public MainViewModel()
{
    StateManager
        .Group<MainStates>()

        .DefineState(MainStates.One)
        .ChangePropertyValue(vm => CurrentState, "State One")

        .DefineState(MainStates.Two)
        .ChangePropertyValue(vm => CurrentState, "State Two")

        .DefineState(MainStates.Three)
        .ChangePropertyValue(vm => CurrentState, "State Three")

        .DefineState(MainStates.Four)
        .ChangePropertyValue(vm => CurrentState, "State Four");

}

The notation for defining state groups and states is very fluid in nature and we’re always looking for ways to make defining states more intuitive. Essentially each of these states updates a single property, CurrentState, with a new constant value.

Making use of this class is as simple as creating an instance of the MainViewModel and setting it as the DataContext for the page:

public sealed partial class MainPage : Page
{
    private MainViewModel ViewModel { get; } = new MainViewModel();
    public MainPage()
    {
        this.InitializeComponent();

        DataContext = ViewModel;
    }

    private void StateOneClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.One);
    }

    private void StateTwoClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Two);
    }

    private void StateThreeClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Three);
    }

    private void StateFourClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Four);
    }
}

When this is run, clicking through each of the buttons triggers a state change in the MainViewModel instances. This in turn causes the CurrentState property to change, which is shown on the page via data binding. The really awesome thing about the way states are defined, is that you can have any number of properties being set, and the library is smart enough to set the property values back to what they were originally when the class moves to a different state.

*Note that this library is currently in beta

Migrating BuildIt to .NETStandard

At the beginning of the year I blogged quite a bit about a set of libraries that we use at Built to Roam that are available either from NuGet (https://www.nuget.org/packages?q=BuildIt) or as source on GitHub (https://github.com/builttoroam/BuildIt). These started a few years ago as an accumulation of helper functions for building, as the time Windows Phone applications. Since then the libraries have matured a bit and have evolved somewhat. The BuildIt.General library is still just a collection of helper method, whilst some, like BuildIt.Lifecycle, are more framework in nature. Over the coming weeks we’re investing a bit into tidying up these libraries, including:

  • Migrating any of the libraries that were targeting PCL profile 259 across to .NET Standard 1.0
  • Updating, where possible, all NuGet references
  • Setting up an automated build and release process, including support for publishing directly to NuGet
  • Rationalise the number of libraries on NuGet – namely where there are platform specific libraries, these will be combined in with the core library (eg BuildIt.General.UWP will get packaged with BuildIt.General and will be installed for UWP projects)
  • Add some additional packages
    • BuildIt.Media.UWP – This allows you to easily add Cortana voice commands for controlling media playback with the MediaElement control
    • BuildIt.Web.Config (this name may change) – This allows you to easily define application configuration values server side and have them flow to the client application

Right now, we’re going through and migrating the libraries to .NET Standard. This is a painful process as there are often NuGet references that don’t work with .NET Standard – we’re either removing these or deciding to wait on the package author to update. During this phase a lot of the packages will be marked as beta -  you should be able to start using these libraries but just be aware we haven’t completed the migration, so things may change over the coming weeks.

NetStandard, what is it and why do I care?

Over the past couple of years there hasn’t been a single project where at some point or another it hasn’t encountered NuGet pain – this is the pain associated with trying to upgrade packages, only to discover that you have to carefully select specific package versions due to incompatibilities, and then try and fight the nasty Visual Studio NuGet package manager interface to get them to install correctly. I’m no expert on topics like PCL Profiles, so I thought that I’d spend some time researching a bit more about what’s going on, and just why NuGet seems to fragile. This interest was also driven by the recent release of the .NET Platform Standard (ie NetStandard) and the fact that I need to migrate the BuildIt libraries we use, away from PCL Profiles (yay!) across to NetStandard.

As I said, I’m no guru on this, so rather than post third or fourth hand info. Here’s where I started: Oren Novotny’s post entitled Portable- is dead, long live NetStandard. Start there, and make sure you follow the links in his post as they provide some essential background reading on the topic.

Cryptic Build Failure in Release Mode for Universal Windows Platform Application

We’ve just managed to solve an issue that’s been plaguing us for a while when we attempt to do a Release build (either via the Store –> Create App Package, or just by setting the build configuration to Release) we were seeing an error message similar to:

RHBIND : error RHB0011: Internal error: 'declModule == m_pLoaderModule'

This error makes no sense, and there’s nothing at all helpful to go on from any of the usual logs etc. A quick search only returned two links, one of which was to a GitHub thread (https://github.com/dotnet/core/blob/master/Documentation/ilcRepro.md) posted by Microsoft that talks about capturing a .NET Native Repro…. not quite what I was interested in. However, further down the post there’s a section entitled “Compilation Failure on Update 1” which lists almost exactly the error we were seeing. The section refers to a new feature called SharedLibrary but doesn’t really talk about how to turn it on or off. It does however link to another post https://blogs.msdn.microsoft.com/dotnet/2015/09/28/whats-new-for-net-and-uwp-in-win10-tools-1-1/.

Initially I didn’t think that there was anything relevant in the post, since it was entitled “What’s new for .NET and UWP in Win10 Tools 1.1” and starts off talking about app-locally and shared appx framework packages. It then talks about how to enable this feature….but in the other post it said that SharedLibrary was on by default…. Anyhow, instead of following this post and setting the UseDotNetNativeSharedAssemblyFrameworkPackage to true (ie enabling it), I figured I’d try setting it to false (ie <UseDotNetNativeSharedAssemblyFrameworkPackage>true</UseDotNetNativeSharedAssemblyFrameworkPackage>). For example the Release section of the UWP project file now looks like:

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
  <OutputPath>bin\x86\Release\</OutputPath>
  <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
  <Optimize>true</Optimize>
  <NoWarn>;2008</NoWarn>
  <DebugType>pdbonly</DebugType>
  <PlatformTarget>x86</PlatformTarget>
  <UseVSHostingProcess>false</UseVSHostingProcess>
  <ErrorReport>prompt</ErrorReport>
  <Prefer32Bit>true</Prefer32Bit>
  <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
<UseDotNetNativeSharedAssemblyFrameworkPackage>false</UseDotNetNativeSharedAssemblyFrameworkPackage>
</PropertyGroup>

Doing this fixed the Release build for this application and allows us to create a package ready for Store deployment. Hope this helps others.

Updating BuildIt

It's been a while but I've just published an update to the BuildIt libraries with the aim to streamline the syntax for declaring states. For example, the following are the state declarations for the Flickr viewer sample application:
StateManager.Group<RegionStates>()
 .WithHistory()
  .DefineStateWithData<RegionStates, MainViewModel>(RegionStates.Main) 
   .WhenChangedTo(vm => vm.Load())
   .OnDefaultCompleteWithData(vm => vm.SelectedPhoto)
    .ChangeState(RegionStates.Details)
     .InitializeNewState<RegionStates, MainViewModel, DetailsViewModel, Photo>  
         ((vm, d) => vm.Photo = d)
  .DefineStateWithData<RegionStates, DetailsViewModel>(RegionStates.Details);

Triggering State Changes in BuildIt.States

The state management capability that BuildIt.Lifecycle uses is actually provided by a standalone library BuildIt.States which focusses on tracking states and allowing transitions between states. BuildIt.Lifecycle builds on this to adapt it to generating view models for specific states, along with the glue that connects states and transitions to the appropriate platform implementation (eg Pages and Navigation). The nice thing about the state management library being separate is that it can iterate independently. In this case, we’ve updated the library to include support for triggers.

One of the new features added to the Universal Windows Platform (UWP) for Windows 10, are state triggers. Out of the box, UWP comes with an AdaptiveTrigger class which is used to trigger a state change once a minimum width or height (or both) have been reached by a Window. The way triggers work is that they evaluate a particular condition and once the condition has been met, the IsActive property is changed to true. Once all triggers for a particular state are set to IsActive, the framework changes the active visual state. We’ve adapted this concept to apply it to state management within the BuildIt.States library.

Taking the FlickrViewer application that I discussed in my post, Building a Flickr Viewer App with BuildIt.Lifecycle, I’ll modify the MainViewModel to use triggers. Here you’ll see that in addition to adding triggers to the state definition, we’re also making use of an instance of the LoadingManager. A common scenario is to have states for when data is being loaded, and when it has been loaded. To handle this, the state management library includes a LoadingManager class which tracks which page/viewmodel state is used for both Loading and Loaded states. The nice artefact of using the LoadingManager is that the MainViewModel doesn’t explicitly need to indicate when it’s loading or not loading data. Instead it simply wraps the loading operation in a using statement. Behind the scenes this links to the LoadingTrigger instances used in the state declaration.

public enum MainStates
{
    Base,
    Loading,
    Loaded
}

LoadingManager<MainStates> LoadingManager { get; } = new LoadingManager<MainStates>()
{
    LoadingState = MainStates.Loading,
    LoadedState = MainStates.Loaded
};

public MainViewModel(IFlickrService flickr)
{

    StateManager
        .Group<MainStates>()
        .DefineState(MainStates.Loading)
            .AddTrigger(new LoadingTrigger<MainStates>(LoadingManager) {ActiveValue = MainStates.Loading})
        .DefineState(MainStates.Loaded)
            .AddTrigger(new LoadingTrigger<MainStates>(LoadingManager) {ActiveValue = MainStates.Loaded});
    Flickr = flickr;
}

public async Task Load()
{

    using (LoadingManager.Load())
    {
        var photos = await Flickr.LoadPhotos();
        photos.DoForEach(Photos.Add);
    }         
}

Building a Flickr Viewer App with BuildIt.Lifecycle

Last week at the Mobile .NET User Group I presented on the BuildIt.Lifecycle for the first time. The main motivation wasn’t to try and get people to start using it (although I’d definitely welcome feedback from anyone who does), it was really to try to get developers to start thinking differently about the way that they write applications. Instead of thinking of their application in terms of the apis that any one platform offer (and I treat XForms as just another platform, even though it sort of in-part aggregates iOS/Windows and Android) or in terms of raw navigation constructs (eg Activities/Intents, ViewControllers or Pages), but more in terms of states within their application.

Applications are littered with states, whether they be the states of a button (Normal, Focussed, Pressed, ToggledOn etc) or visual states of a Page (a Windows concept but you can think of visual states as being the different layouts of any given page/view of your application). In fact if you think of your application as a whole you realise that you can map the entire navigation within your application as just a series of state transitions, with your pages/views being the states that the application can be in. This is indeed the foundation of BuildIt.Lifecycle.

One other point I’ll make before jumping into building the Flickr Viewer application, which should demonstrate the core of the BuildIt.Lifecycle framework, is that most application frameworks, at least for mobile platforms, have been built around the notion of a single window or frame that houses the content that the user is currently looking at. As such most of the frameworks have some metaphor that maps to the application as a whole (often called the App or Application class), and is assumed to be a singleton. In exploring the use of states to model applications, it became evident that there are some platforms, such as Windows and Mac, where this assumption breaks down, and that in fact the framework needs an additional metaphor that maps to each window within an application. I’ve settled on Region for the timebeing, and there’s no surprises that there is a mapping between an instance of a Region in the framework to a Window presented at runtime. This should make more sense once we explore creating the application; alternatively there’s a post on working with Additional Windows using Regions with BuildIt.Lifecycle.

Let me start by giving an example of visual states, just to warm up and get us all thinking about using states to represent an application, or parts of the application. I’m going to start by creating a new Universal Windows Platform project, based on the Blank App (Universal Windows) project template, called FlickrViewer.

image

Next I’ll create another project, this time called FlickrViewer.Core, based on the Class Library (Portable) template, keeping the defaults in the Add Portable Class Library targets dialog.

image

To complete the setup of the projects, I just need to add a reference from the FlickrViewer UWP project to the FlickrViewer.Core PCL project.

image

The last reference I’m going to add initially is to the Microsoft.Net.Http and Newtonsoft.Json NuGet packages (Note that under the Install and Update Options the Dependency behaviour is set to Highest, and both packages are install into both projects).

image 

I’m going to add the FlickrService class (and corresponding IFlickrService interface) that’s listed at the end of this article, which I’ll use to download content from the public flickr feed, to the PCL. This application is going to consist of two pages, the first will display a list of images retrieved from the Flickr public feed; the second page will display the details of the image selected from the first page. I’ll add another page at this point called DetailsPage.xaml, based on the Blank Page item template.
Next, I’m going to switch across to Blend and create a couple of visual states: a Loading state, for when data is being loaded; and a Loaded state, for when data is available to be displayed on the screen. The following XAML for the MainPage includes a ListView, which will be visible once data has loaded (ie Loaded state), and a ProgressRing, which will be visible and active while data is being loaded (ie Loading state).

<Page x:Class="FlickrViewer.MainPage"
      xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:FlickrViewer"
      xmlns:d="
http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="MainStates">
                <VisualState x:Name="Loading">
                    <VisualState.Setters>
                        <Setter Target="progressRing.(UIElement.Visibility)" Value="Visible" />
                        <Setter Target="progressRing.(ProgressRing.IsActive)" Value="True" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Loaded">
                    <VisualState.Setters>
                        <Setter Target="listView.(UIElement.Visibility)" Value="Visible" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <ListView x:Name="FlickrListView" Visibility="Collapsed">
          
<ListView.ItemTemplate>
                <DataTemplate>
                    <Grid Height="100" Margin="0,10">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Image Source="{Binding media.m}"
                               Stretch="UniformToFill"
                               HorizontalAlignment="Center"
                               VerticalAlignment="Center" />
                        <TextBlock Text="{Binding title}"
                                   Grid.Column="1"
                                   TextWrapping="WrapWholeWords"
                                   FontSize="20"
                                   Margin="10,0"/>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <ProgressRing x:Name="LoadingProgress"
                      HorizontalAlignment="Center"
                      VerticalAlignment="Center"
                      Visibility="Collapsed"
                      Width="100"
                      Background="Red"
                      Height="100" />

    </Grid>
</Page>

When the MainPage loads, I’ll create an instance of the FlickrService and invoke the LoadPhotos method in order to retrieve data to be displayed on the MainPage.

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    VisualStateManager.GoToState(this, "Loading", true);
    var flickr = new FlickrService();
    var photos = await flickr.LoadPhotos();
    FlickrListView.ItemsSource = photos;
    VisualStateManager.GoToState(this, "Loaded", true);
}

Running the application at this point will display the progress ring while the data is being downloaded (Loading state), followed by the list of photos once the data has been retrieved (Loaded state).

image

So now that you’ve got the idea of visual states, let’s move on to talking about the application in terms of states. I’m going to use the BuildIt.Lifecycle framework, so I’ll start by adding references to the NuGet packages. Into the FlickrViewer project, I’m going to add the BuildIt.Lifecycle.UWP package; into the FlickrViewer.Core project, I’m going to add the BuildIt.Lifecycle package (there will be some refactoring coming which will consolidate these into a single package soon but for now there are platform specific packages to be added).

As with most frameworks I need to add a class to the PCL that will correlate to the application as a whole. There are a couple of different options available as base classes; in this case I’m going to pick the one that is already setup to be able to handle multiple regions, despite not actually requiring it for this application. Currently this base class does require the DefineApplicaitonRegions method to be defined, but in this case since we are only going to define a single region, PrimaryRegion, there is no need to do anything within this method. The type, PrimaryRegion, is provided as a generic argument when inheriting from the RegionAwareBaseApplication class, which registers and identifies the PrimaryRegion class as the first region of the application.

public class RootApplication : RegionAwareBaseApplication<PrimaryRegion>
{
    protected override void DefineApplicationRegions()
    {
    }
}

Next, I need to define the PrimaryRegion class, and for this I’m going have it inherit from the StateAwareApplicationRegion class. It’s possible to define regions of the application that aren’t state aware, meaning that the developer has to provide some other mechanism for navigating between pages/views. In this case, we want to think of our application in terms of states. Rather than thinking about the navigation through our application as going from MainPage to the DetailsPage, I’ll define two states, Main and Details, between the application will transition. These states are easily defined as enum values, and used within the PrimaryRegion to define what makes up each state:

public class PrimaryRegion : StateAwareApplicationRegion
{
    public enum RegionStates
    {
        Base,
        Main,
        Details
    }

    public PrimaryRegion()
    {
        StateManager.Group<RegionStates>()
            .DefineState(RegionStates.Main)
            .DefineState(RegionStates.Details);
    }
}

On of the interesting things about the pages of the PrimaryRegion is that they correspond to pages within the application, which in turn need a view model to data bind to. This is how most developers think of this relationship. Actually it’s almost the other way around. Each of the states within the PrimaryRegion will have a view model (think of this as the data that is related to that state). The platform specific implementation of moving to a particular state will display a page that correlates to the state, and will data bind the corresponding view model to the page. Hopefully this helps set the stage for the next step – we’re going to go back to the StateManager within the PrimaryRegion, and this time change to defining view models for each state:

public PrimaryRegion()
{
    StateManager.GroupWithViewModels<RegionStates>()
        .StateWithViewModel<RegionStates, MainViewModel>(RegionStates.Main)
        .EndState()
        .StateWithViewModel<RegionStates, DetailsViewModel>(RegionStates.Details)
        .EndState();
}

You’ll notice that this makes use of two view models, MainViewModel and DetailsViewModel, which I’ll need to create in the PCL. The code associates each of the view model types with the corresponding state enum value. For the timebeing the view models will be relatively basic, only inheriting from NotifyBase which is a simple implementation of the INotifyPropertyChanged interface.

public class MainViewModel:NotifyBase
{ }
public class DetailsViewModel:NotifyBase
{ }

So far I’ve added two states, with view models, to the PrimaryRegion but it doesn’t know which state to start at. By overriding the CompleteStartup method, it’s possible to direct the StateManager to go directly to the Main state.

protected override async Task CompleteStartup()
{
    await base.CompleteStartup();

    await StateManager.GoToState(RegionStates.Main);
}

The navigation to actual pages in the UWP application is handled at the UI layer, and relies on there being a known association between the state that the application is in, and the corresponding page that should be displayed. Some frameworks rely on convention to do this; we take the approach that we prefer this to be explicit, which has the secondary benefit of avoiding reflection. When the application launches, I need to register the MainPage and DetailsPage to the corresponding state:

public App()
{
    this.InitializeComponent();
    this.Suspending += OnSuspending;

    LifecycleHelper.RegisterView<MainPage>().ForState(PrimaryRegion.RegionStates.Main);
    LifecycleHelper.RegisterView<DetailsPage>().ForState(PrimaryRegion.RegionStates.Details);
}

I’m also going to replace all the startup logic that would normally reside in the OnLaunched method in the App.xaml.cs file, with the following code:

protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
    var core = new RootApplication();
    var wm = new WindowManager(core);
    await core.Startup();
}

From this code you can I’m creating an instance of the RootApplication, which knows about the PrimaryRegion, which in turn manages the state transitions between Main (ie MainPage) and Details (DetailsPage). The WindowManager introduces all the glue necessary to navigate to the appropriate pages with the application, and to ensure the window completely loads by calling the Activate method.

For the timebeing I’m going to replace the contents of the MainPage with the following TextBlock and Button, contained within a vertical StackPanel.

<StackPanel>
    <TextBlock Text="{Binding Data}"
                FontSize="40" />
    <Button Click="GoToSecond">Go</Button>
</StackPanel>

Into the MainViewModel I’ll add a simple property that returns a static value:

public string Data { get; } = "Hello World!";

Running the application displays Hello World! on the screen, indicating that the MainViewModel has been setup as the DataContext for the MainPage that’s being displayed.

image

Next, is to wire up the Go button to transition the application to the Details state, in order to display the DetailsPage. The change in state needs to be controlled by the StateManager that belongs to the PrimaryRegion. This means that in order to change state, the Main state needs to raise an event, or send a message, to signal to the PrimaryRegion. In actual fact, it’s the MainViewModel that will raise the event but rather than simply define a custom event I will instead inherit from the BaseViewModelWithCompletion class, using the DefaultCompletion enum which defines a single usable value of Complete (if the state had multiple states it could transition to, I could define a new enum that has a value for each state to transition to). The MainViewModel class now looks like:

public class MainViewModel : BaseViewModelWithCompletion<DefaultCompletion>
{
    public string Data { get; } = "Hello World!";

    public void Complete()
    {
        OnComplete(DefaultCompletion.Complete);

    }
}

The Complete method simply gets invoked by the event handler for the Button

private void GoToSecond(object sender, RoutedEventArgs e)
{
    (DataContext as MainViewModel).Complete();
}

The last thing is to handle the completion of the MainViewModel/Main state in the PrimaryRegion. This can be done by extending the definition of the Main state.

StateManager.GroupWithViewModels<RegionStates>()
    .StateWithViewModel<RegionStates, MainViewModel>(RegionStates.Main)
        .OnComplete(DefaultCompletion.Complete)
        .ChangeState(RegionStates.Details)
    .EndState()
    .StateWithViewModel<RegionStates, DetailsViewModel>(RegionStates.Details)
    .EndState();

Clicking the Button will transition the application from the Main to Details state, and in doing so navigate from the MainPage to the DetailsPage. You’ll also see that a back button appears in the top navigation bar, allowing the transition back to the Main state – this works without having to manually define the back button behaviour.

image

I’ll return now to the MainPage and look at how to populate it with data. There are three main steps to this:

- Register the FlickrService
- Associated the FlickrService with the MainViewModel
- Use the FlickrService to populate data within the MainViewModel

The registration of services happen at an application level but can be done either within the RootApplication, if the implementation of the services is accessible within the PCL (like our FlickrService), of it can be done on App startup as part of the call to Startup using a delegate callback to register platform specific services. For example either the following:

RootApplication

protected override void RegisterDependencies(ContainerBuilder builder)
{
    base.RegisterDependencies(builder);

    builder.RegisterType<FlickrService>().As<IFlickrService>();
}

Or, App.Xaml.cs

await core.Startup(builder => {
       builder.RegisterType<FlickrService>().As<IFlickrService>();
});

In this case, since the FlickrService doesn’t rely on any platform specific implementation I’ll register it in the RootApplication.

Next, we want the instance of the FlickrService to be passed into the MainViewModel so that we can use it to retrieve feed data. To do this we rely on constructor injection by specifying an IFlickrService parameter to the MainViewModel constructor.

public IFlickrService Flickr { get; }

 

public MainViewModel(IFlickrService flickr)
{
    Flickr = flickr;
}

And then I need to expose a collection of photos and provide a method that will invoke the LoadPhotos method on the IFlickrService.

public ObservableCollection<Photo> Photos { get; } = new ObservableCollection<Photo>();
public async Task Load()
{
    var photos = await Flickr.LoadPhotos();
    photos.DoForEach(Photos.Add);
}

A lot of other MVVM style frameworks rely on the view models inheriting from a base view model which has init/dispose style methods defined for when the view model comes into focus or leaves focus (ie the user arrives or leaves at a page). In this case, because we’re defining our application behaviour in terms of states, we want to invoke code when we arrive at the Main state. Again we do this within the PrimaryRegion by adding a call to WhenChangedTo to the Main state definitiion.

.StateWithViewModel<RegionStates, MainViewModel>(RegionStates.Main)
    .WhenChangedTo(vm => vm.Load())
               
    .OnComplete(DefaultCompletion.Complete)
    .ChangeState(RegionStates.Details)
.EndState()

Before running the application at this point we need to return to our MainPage.xaml and return the layout to what we initially created with the ListView, the ProgressRing and the visual states. I needed to make two minor adjustments:

- Make sure the ListView is visible initially – since we don’t have anything to drive the Loaded/Loading visual state changes, yet
- Add the ItemsSource attribute to be data bound to the Photos property ie ItemsSource=”{Binding Photos}”

Running the application now should display a list of photos, similar to what I had at the beginning of this post. To add back the visual states, all I need to do is adjust the MainViewModel to include its own state manager:

public class MainViewModel : BaseStateManagerViewModelWithCompletion<DefaultCompletion>
{
    public enum MainStates
    {
        Base,
        Loading,
        Loaded
    }

    public MainViewModel(IFlickrService flickr)
    {
        StateManager.Group<MainStates>().DefineAllStates();
        Flickr = flickr;
    }

Into the MainViewModel we’ve added a new enumeration, whose values match the names of the visual states. I’ve also adjusted the base class for the MainViewModel to be one that already has a state manager defined. And finally I’ve called DefineAllStates which will create all the states that correlate to the values in the MainStates enumeration. That’s it! Run the application again, and the visual state changes are already wired up.

The final stretch of this application is handling when the user selects an item from the list of photos. The selected photo needs to be passed through to the details page so that the details of the photo can be displayed on the page. A lot of developers prefer to use command binding to pass through the click event to the method in the view model. To keep it simple I’m just going to wire up an event handler for the ItemClick event on the ListView

<ListView x:Name="FlickrListView"
            ItemsSource="{Binding Photos}"
            IsItemClickEnabled="True"
            ItemClick="FlickrListView_OnItemClick"
>
private void FlickrListView_OnItemClick(object sender, ItemClickEventArgs e)
{
    (DataContext as MainViewModel).DisplayPhoto(e.ClickedItem as Photo);
}

Inside the DisplayPhoto method on the MainViewModel I’m going to track the SelectedPhoto before calling the OnComplete method.

public Photo SelectedPhoto { get; private set; }
public void DisplayPhoto(Photo photo)
{
    SelectedPhoto = photo;
    OnComplete(DefaultCompletion.Complete);
}

In order to pass the selected photo into the DetailsViewModel, the state manager in the PrimaryRegion needs to be updated to hand the selected photo into the DetailsViewModel when the Details state is transitioned to.

StateManager.GroupWithViewModels<RegionStates>()
    .StateWithViewModel<RegionStates, MainViewModel>(RegionStates.Main)
        .WhenChangedTo(vm => vm.Load())
       
.OnCompleteWithData(DefaultCompletion.Complete, vm => vm.SelectedPhoto)
        .ChangeState(RegionStates.Details)
    .EndState()

    .StateWithViewModel<RegionStates, DetailsViewModel>(RegionStates.Details)
        .WhenChangedToWithData<RegionStates, DetailsViewModel, Photo>((vm, data) =>
        {
            vm.Photo = data;
        })
    .EndState();

There are two updates to the StateManager:
- The OnComplete in the Main state is replaced with OnCompleteWithData which is used to extract the SelectedPhoto so that it can be passed through to the new state (in this case the Details state)
- A call to WhenChangedToWithData is used to pass through the selected photo into the Photo property on the DetailsViewModel.

Of course, the DetailsViewModel needs to be updated to include the Photo property. As the Photo property may not be set by the time the DetailsViewModel is set as the DataContext on the page, it’s important that the Photo property raises the PropertyChanged event in the setter.

public class DetailsViewModel : NotifyBase
{
    private Photo photo;

    public Photo Photo
    {
        get { return photo; }
        set
        {
            photo = value;
            OnPropertyChanged();
        }
    }
}

The last thing to do is to update the design of the DetailsPage.xaml to render the photo:

<Page x:Class="FlickrViewer.DetailsPage"
      xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:FlickrViewer"
      xmlns:d="
http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Image Source="{Binding Photo.media.m}"
               HorizontalAlignment="Center"
               VerticalAlignment="Center"
               Stretch="UniformToFill" />
        <Grid VerticalAlignment="Bottom">
            <Border Background="Black"
                    Opacity="0.9"/>
            <TextBlock Text="{Binding Photo.title}"
                       TextWrapping="WrapWholeWords"
                       FontSize="30"
                       Foreground="White"
                       MaxLines="3"
                       Margin="20,10" />
        </Grid>

    </Grid>
</Page>

Running the application now gives the following interface for viewing the public Flickr feed.

image


********************************************************************************************************************************************************
                 Flickr Download Service

********************************************************************************************************************************************************

public interface IFlickrService
{
    Task<IEnumerable<Photo>> LoadPhotos();
}

public class FlickrService : IFlickrService
{
    public async Task<IEnumerable<Photo>> LoadPhotos()
    {
        var client = new HttpClient();
        var json = await client.GetStringAsync(
                    "
http://api.flickr.com/services/feeds/photos_public.gne?format=json&nojsoncallback=1");
        var photos = JsonConvert.DeserializeObject<FlickrData>(json);
        return photos.items;
    }
}

public class Media
{
    public string m { get; set; }
}

public class Photo
{
    public string title { get; set; }
    public string link { get; set; }
    public Media media { get; set; }
    public string date_taken { get; set; }
    public string description { get; set; }
    public string published { get; set; }
    public string author { get; set; }
    public string author_id { get; set; }
    public string tags { get; set; }
}

public class FlickrData
{
    public string title { get; set; }
    public string link { get; set; }
    public string description { get; set; }
    public string modified { get; set; }
    public string generator { get; set; }
    public List<Photo> items { get; set; }
}

Conditional Back Button Visibility with BuildIt.Lifecycle

In my post, Adding Back Button Support to Xamarin.Forms with BuildIt.Forms, I showed the basic support I’d added to BuildIt.Lifecycle to handle showing/hiding the back button depending on whether there were previous states. The back button visibility is actually more complex than that as there may be conditions on the current page (ie the current state/view model) that determine whether clicking back should be possible. To keep things simple I’m going to assume that if clicking back is possible, the back button will be shown, otherwise it will be hidden – this may not suit everyone as you may want to show the back button but have it disabled (personally I don’t like this, as it’s hard for the user to understand why the back button is disabled). I’ve just added support to the states and corresponding viewmodel management to detect if the current view model is in a blocked state.

There is an interface IIsAbleToBeBlocked that a view model can implement in order to both return an IsBlocked property and raise an event when it changes. This interface has also been added to the BaseViewModel class to make it easier for developers. For example this method can be used within a view model to toggle the visibility of the back button. If IsBlocked is true, the back button will be hidden.

public async void Run()
{
    for (int i = 0; i < 10; i++)
    {
        IsBlocked = !IsBlocked;
        await Task.Delay(1000);
    }
}

Note that the IsBlocked property works in conjunction with the HasHistory property on the state group (which maps to the back stack at a page level). If there is no history in the state group (ie at the first stage of the application – the first page of the application), then the back button won’t be shown, irrespective of the IsBlocked property.

Arriving or Leaving a ViewModel with BuildIt.Lifecycle

Often when arriving at a page/view it’s necessary to invoke some code in order to load data, or refresh the contents on the page. Of course, this needs to happen within the ViewModel. For BuildIt.Lifecycle, this is means implementing the IArrivingViewModelState interface which defines a single method, Arriving, which will get invoked when the user arrives at the page/view (and the corresponding viewmodel).

public async Task Arriving()
{
    await Task.Delay(2000);
    Name += ".... arrived ....";
}

Note that the method returns a Task, so you can do asynchronous code in order to retrieve data.

On the Windows platform the Universal Windows Platform has methods OnNavigatedTo, OnNavigatingFrom and OnNavigatedFrom which can be overridden in the code behind of a Page. These correspond to when a user arrives, is about to leave and has left a page. The Arriving method in BuildIt.Lifecycle maps to the OnNavigatedTo method. There are two more interfaces, IAboutToLeaveViewModelState and ILeavingViewModelState, which can be used to define methods AboutToLeave and Leaving. These methods map to the OnNavigatingFrom and OnNavigatedFrom methods.

One thing to note about the AboutToLeave method is that it has a CancelEventArgs as a parameter. The code in the AboutToLeave method can set the Cancel property on this parameter to true in order to cancel the navigation away from the page (note that this maps to cancelling the state change which drives the change in pages).

public async Task AboutToLeave(CancelEventArgs cancel)
{
    cancel.Cancel = true;
}

Adding Back Button Support to Xamarin.Forms with BuildIt.Forms

In my previous post I discussed the support I added for hardware and virtual back buttons in a Universal Windows Platform application (UWP) using BuildIt.Lifecycle. At an application level the back button (irrespective of whether it’s a hardware back button, such as on a phone, or a virtual back button, such as in desktop or tablet mode) is designed to return the user to the previous state of the application. In most cases this correlates to going to either the previous page in an application, or to the previous application, if the user is on the first page of the current application. Occasionally, there may be sub-states within a page, in which case the back button should be able to step back through those states, before causing the application to go back to the previous page.

This means that the back button should be applied at the highest level of the active window, which means passing it into StateManager of the region that correlates to the active window. In a UWP application, this is relatively straight forward as the application can subscribe to the BackRequested event, for example:

SystemNavigationManager.GetForCurrentView().BackRequested += BackRequested;

In the event handler, the StateManager for the region is queried to find out if a previous state exists. If it does, a call to GoBackToPreviousState is made.

Unfortunately Xamarin.Forms (XForms) doesn’t offer a global event for the back button. Instead it’s up to every page to override the OnBackButtonPressed method and return true if the back navigation should be cancelled. Having every page of the XForms application inherit from a custom base page isn’t an option I wanted to force upon users of this library. Luckily it’s not necessary to intercept the OnBackButtonPressed method on every page; it can instead be intercepted in the NavigationPage at the root of the application. By providing a CustomNavigationPage class, and requiring that it be used as the root of the application, it’s possible for the back button to be intercepted and applied to the active region.

Back Button Support in BuildIt.Lifecycle

Previously I’ve dealt with going back to previous pages based on user interaction on the current page (eg hitting a back button that triggers an “end of state” behaviour to go back to the previous page). However, another common scenario is for the user to press tha back button, either on their device (eg the Windows Phone hardware back button) or a virtual back button (eg the virtual button that’s available to Windows 10 UWP applications either in the task tray (running in tablet mode) or in the top navigation bar, when running in desktop mode). This wasn’t currently handled, so I’ve added handlers for both the hardware back button and the virtual back button to the UWP branch of BuildIt.Lifecycle. This work isn’t totally complete because at the moment it assumes that the decision as to whether the current page supports a back operation is determined only by the root level StateManager – this may not be the case if you have a view model that has business logic that determines whether the current page can be navigated way from.

This update also supports hiding and showing the virtual back button when a UWP application is run in desktop mode eg:

image image

Book: Mobile Strategies for Business: 50 Actionable Insights to Digitally Transform Your Business

If you’re interested in mobile strategies for line of business applications, you can’t go past this read, recently authored by Rob Tiffany. The book itself actually stems from a series of tweets Rob did a while ago. Each section starts with a tweet, followed by a more detailed discussion that both sets context and discusses current thought leadership in the area of mobile strategies for business applications.

One of the biggest takeaways, which actually couples the content of Rob’s book with my own thoughts on enterprise applications, is that businesses need to do more to move quicker in the modern technology enviornment. This means getting rid of antiquated processes, such as SOEs, in favour of more agile mechanisms such as Windows as a service. Applications are no different, old/legacy applications should be migrated, updated, rebuilt or retired in order to allow organisations to be more agile.

I also believe that applications within an organisation, whether they be mobile, desktop or web, should have a lifecycle in which they are created, maintained and then retired. If you aren’t maintaining, and ideally updating/improving, an application, you’d better look at retiring it. If you don’t, you’ll risk slowing your organisation down over time.

Fixing Back Behaviour and Navigation Button in Xamarin Forms with BuildIt.Lifecycle

There were two issues that I identified in my post, Using BuildIt.Lifecycle with Xamarin Forms, which were to do with the navigation between pages

1. The back operation actually did a forward navigation to a new page

2. The navigation button was always showing that there was a previous page, even if there wasn’t

The first issue was fixed with an update to the BuildIt.Lifecycle.XForms library which picks up on the IsNewState flag during state transition to determine whether to do a forward navigation (ie a PushAsync) or a backward navigation (ie a PopAsync).

The second issue was fixed by looking at the Navigation.NavigationStack and based on whether there were any entries in there, toggle whether the navigation bar is shown. The following would hide the navigation bar (it’s a static method on the NavigationPage class).

NavigationPage.SetHasNavigationBar(NavigationRoot, false);

Visual States in XForms with BuildIt.Lifecycle

When I created the layout for the AboutPage in my post, Using BuildIt.Lifecycle with Xamarin Forms, I cut out most of the elements to make it quicker to get something up and running. The irony is that fixing up the AboutPage to include a SplitView like pane was actually relatively quick, although there’s a bit of polish that needs to be added to make it look great. The following is the XAML for the AboutPage which includes two columns: the left column, initially hidden, includes the Close button which allows the user to navigate back to the home page of the app; the right column holds a couple of buttons that can switch states of the page between Expanded and Minimised. Note that there is another button that sits in the top left corner which will simply toggle between the states.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="
http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SimpleStates.XForms.Pages.AboutPage">
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto"/>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid BackgroundColor="Yellow"
          x:Name="SplitPane"
          IsVisible="False">

      <Button Clicked="CloseClick"
              VerticalOptions="Center"
              HorizontalOptions="Center"
              Text="Close"/>
    </Grid>

    <StackLayout Grid.Column="1"
                 VerticalOptions="Center"
                 HorizontalOptions="Center" >
      <Label  Text="About Page"
              FontSize="40" />
      <Label  Text="{Binding AboutTitle}"
              FontSize="40" />
      <Label  Text="{Binding Data}"
              FontSize="40" />
      <Button Clicked="ExpandClick" Text="Expand"/>
      <Button Clicked="CollapseClick" Text="Collapse"/>
    </StackLayout>
    <Button
      Clicked="splitViewToggle_Click"
      Text="="
      HorizontalOptions="Start"
      VerticalOptions="Start"/>
  </Grid>
</ContentPage>

Unfortunately the XForms XAML doesn’t support defining visual states, so we have to define these in code using the StateManager class. By specifying the IHasStates interface, the framework will automatically associate the StateManager on the AboutPage with the StateManager in the AboutViewModel, keeping them in sync.

public partial class AboutPage : IHasStates
{
    public IStateManager StateManager { get; }
   
    public AboutPage()
    {
        InitializeComponent();

        StateManager = new StateManager();
        StateManager
            .Group<AboutExpandStates>()
                .DefineState(AboutExpandStates.Minimised)
                .DefineState(AboutExpandStates.Expanded)
                    .Target(SplitPane)
                        .Change(x => x.IsVisible, (x, c) => x.IsVisible = c)
                        .ToValue(true);
    }

Using BuildIt.Lifecycle with Xamarin Forms

Leaving the Universal Windows Platform behind for a little bit I wanted to show that the BuildIt.Lifecycle framework can be used to drive a Xamarin Forms (XForms) application.

The first step is to create a Xamarin Forms project. In this case I’ll select the Portable option.

image

This will actually create four projects, one which is contains the actually application logic, including the XAML markup for the pages, and then three platform specific projects for iOS, Droid and Windows Phone. The platform specific projects are where any code required for device integration or custom UX goes for each platform.

After creating the projects, the first thing to do is to upgrade the Xamarin.Forms NuGet reference to the latest version (v2.0.1.6495 at time of writing).

The next thing to do is to add references to the BuildIt.Lifecycle NuGet packages including the Xamarin Forms specific package (https://www.nuget.org/packages/BuildIt.Lifecycle.XForms ). I had a few issues here because I initially had the dependency setting in the NuGet manager set to Lowest and it refused to install one of the dependencies (NuGet still isn’t clever enough some times to resolve everything properly). Switching this to Highest, which I think should be the default, fixed this issue.

Of course, the core XForms project needs a reference to the SimpleStates.Core library which contains all my application, region and view model classes. At this point I realised I hadn’t set the PCL profile correctly on the project. Updating this turned out to be a bit of a mission as Visual Studio insisted the project had to be switched to NuGet v3, which you can’t do with any packages installed (according to the error message). So I had to uninstall all the NuGet packages (in the correct order) one at a time, and then update the targets as per the Change Targets dialog for the project.

image

Now that the projects have all the references I need, it’s time to wire up the application. To do this I need to initialise the BuildIt.Lifecycle application, and I need a XForms page that maps to each of the pages (ie my states) in the application. Creating the pages is the easiest thing as they all come straight from the Forms Xaml Page template (no changing of base page required!!).

image

The image shows me creating the MainPage but I also added a SettingsPage, AboutPage and LandingPage into the Pages folder in my XForms PCL project.

Hooking up the BuildIt.Lifecycle framework was also relatively easy. In the App.cs, I simply replace the in-code page that’s created when you create the new project with the following:

public class App : Application
{
    public App()
    {
        LifecycleHelper.RegisterView<MainPage>().ForState(AppStates.Home);
        LifecycleHelper.RegisterView<SettingsPage>().ForState(AppStates.Settings);
        LifecycleHelper.RegisterView<AboutPage>().ForState(AppStates.About);

        LifecycleHelper.RegisterView<LandingPage>().ForState(AdditionalStates.Landing);

        MainPage = new NavigationPage();
        StartApplication();
    }

    private async void StartApplication()
    {
        var core = new SimpleStatesApplication();
        var wm = new WindowManager(MainPage as NavigationPage, core);
        await core.Startup(builder =>
        {
            builder.RegisterType<FormsDataService>().As<IDataService>();
        });
    }
}

This also requires an implementation of IDataService which I called FormsDataService and returns slightly different Contacts than the UWP version did, just to prove the point.

public class FormsDataService : IDataService
{
    public async Task<IEnumerable<string>> LoadContacts()
    {
        return new[] { "XF: Joe", "XF: Bob", "XF: Frank" };
    }
}

My application will now run and display the MainPage but won’t show any content. To fix this I simply needed to go through each of the pages, translate the UWP XAML into XForms and then wire up any event handlers in the code-behind (which route through to the ViewModel anyhow). The XAML and code behind (where required) for the four pages is at the end of this post…. You’ll note that I cheated on the About page just to get something displaying (I’ll come back to that to implement visual states etc) and that neither the About, nor the Landing page currently have any code behind.

That’s it – I can run the application and my page transitions work without me having to do anything. This is very much in early stages as you’ll see that the back navigation isn’t working properly (it’s actually a forward navigation at the moment) and the navigation back button exists even on the first page of the application, which isn’t correct. In coming posts we’ll clear these issues up.

 

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="
http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SimpleStates.XForms.Pages.MainPage">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition/>
    </Grid.RowDefinitions>
    <StackLayout >
      <Label Text="Main Page"
                  
                 FontSize="40" />
      <Button Clicked="SettingsClick">Settings</Button>
      <Button Clicked="AboutClick">About</Button>
      <Button Clicked="AnotherWindowClick">Another Window</Button>
    </StackLayout>
    <ListView Grid.Row="1" ItemsSource="{Binding Contacts}"></ListView>
  </Grid>
</ContentPage>

public partial class MainPage
{
    public MainPage()
    {
        InitializeComponent();
    }
    private MainViewModel ViewModel => BindingContext as MainViewModel;
    private void SettingsClick(object sender, EventArgs e)
    {
        ViewModel.DisplaySettings();
    }

    private void AboutClick(object sender, EventArgs e)
    {
        ViewModel.DisplayAbout();
    }
    private void AnotherWindowClick(object sender, EventArgs e)
    {
        ViewModel.OpenAnotherWindow();
    }
}

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="
http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SimpleStates.XForms.Pages.SettingsPage">

  <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
    <Label Text="Settings Page"
               FontSize="40" />
    <Label Text="{Binding SettingsTitle}"
               FontSize="40" />
    <Button Clicked="GoBackClick">Go Back</Button>
  </StackLayout>
</ContentPage>

public partial class SettingsPage
{
    public SettingsPage()
    {
        InitializeComponent();
    }
    private void GoBackClick(object sender, EventArgs e)
    {
        (BindingContext as SettingsViewModel)?.CompleteSettings();
    }
}

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="
http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SimpleStates.XForms.Pages.AboutPage">
  <StackLayout VerticalOptions="Center" HorizontalOptions="Center" >
    <Label  Text="About Page"
                   FontSize="40" />
    <Label  Text="{Binding AboutTitle}"
             FontSize="40" />
    <Label  Text="{Binding Data}"
             FontSize="40" />
  </StackLayout>
</ContentPage>

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="
http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SimpleStates.XForms.Pages.LandingPage">
  <Label Text="Landing" VerticalOptions="Center" HorizontalOptions="Center" FontSize="40" />
</ContentPage>

Windows Hello (Beta) on Lumia 950 XL

Yesterday, after my Lumia 950 XL arrived, I noted that one of the two features I was going to try was Windows Hello. I want to start by saying that I now have this on both my Surface Book and the Lumia 950XL, and I’ve been using it on the former for quite some time now. Windows Hello on the Surface Book absolutely rocks – it’s not as instant sign on as say the Touch ID sign in capability on the iphone, which is virtually instantaneous on the latest iphones/ipads, but it is still relatively quick and definitely hands free. The latter is useful if you don’t have the keyboard attached.

Unfortunately my experience on the Lumia 950 XL has been disappointing at best, frustrating in some cases. I’ve gone in and repeatedly try to improve recognition but despite this Windows Hello only recognises me less than 50% of the time. What’s worse is that after not recognising me a couple of times it stops trying and forces me to use PIN to unlock. It would be good if it would prompt and suggest PIN to unlock, followed by perhaps a suggestion to improve recognition (perhaps to allow for different lighting conditions etc) but this should only be a suggestion, the camera should still try to identify me, especially since my head is in front of the camera and it should be able to at least detect the presence of a head, even if it can’t identify that it’s me.

The disappointing thing is that even when it does recognise me, it’s no quicker than me swiping up and entering my 4 digit PIN, and you look much less of an idiot doing it. I feel that the integration of a finger print reader would have been much better – less chance of you putting your finger in the wrong place and less environment factors to account for. Not to mention the technology is probably cheaper than the camera required to do Windows Hello with a camera.

This bring me to the final point of this post which is that I’ve bought a production device which comes with the RTM build of Windows 10 Mobile. Now of course, Windows is now a service, which means that patches and updates should come through progressively but at this point no updates have come out for regular customers. If you go to Settings and look at setting up Windows Hello, it is clearly marked as Beta…. WTF! Why have I got Beta features on a device I’ve paid a lot of money for? I don’t know when it became acceptable to ship Beta features to end customers but I think it traces back to Google (if you recall Google was in Beta for years before this tag was removed from their service). Beta testing is there for a purpose, to iron out bugs before you ship to end customers. Now that’s not to say that you can’t have some end customers as beta testers, but they should be invited/request to take part, rather than assume that every customer will tolerate unpolished, incomplete or broken features. Microsoft shipping Beta features to end customers just points to why Apple dominates the mobile market and why iOS customers rarely switch to other platforms.