Demystifying the SDK Project

I am often, and rightfully, accused of living on the bleeding edge. It can be quite painful being there as ideas are not always fully flushed out, and tooling is often just not there yet. When Microsoft began the push towards .NET Core and .NET Standard, I knew this was an area that I needed to be. It was clear to me that this was a major shift that was going to make .NET development more appealing to a variety of developers, and businesses. As I set out to learn this new paradigm I both struggled and enjoyed the massive project system simplification that was introduced in the xproj format with a json configuration. For a variety of reasons though at the 11th hour Microsoft completely changed directions going back to the csproj and ditching the whole concept of a json configuration altogether. For months I struggled to understand what was going on. 

Why I struggled

There were a lot of reasons I struggled. The project system has a lot of loose but very important couplings with MSBuild. Frankly I had heard of msbuild, but I knew so little about it that I simply called it "The Compiler" (which is very inaccurate). Another reason that I struggled is that there isn't exactly a lot of documentation to explain how the project system works, or what elements mean. Then of course have you ever looked at the older style of csproj? There is a lot of nonsense xml going on there. You can kind of figure out some stuff. You can for instance figure out that any of your code files that need to be compiled needed a Compile tag to include it in the compilation, but what on earth is all of the other crazy stuff going on there?

Breaking Through

The new SDK Style projects really help make what's going on in the project system easier to understand and customize because it's not polluted by a lot of insanity. You don't need to add a bunch of duplicate settings for Debug vs Release since it's already assumed these build configurations exist and we have some standard assumptions about them, like Release builds need to be optimized, while Debug configurations need all of our debug symbols to be able to step into them. Then of course we make some standard assumptions like all of your code files should be compiled (known as File Globbing). What's left over is often a file that has a PropertyGroup with a single TargetFramework.

PropertyGroup vs ItemGroup

While this can get a little crazy when we start looking at creating custom build targets, we'll keep this simple for now. A PropertyGroup, is exactly what it sounds like. It's an area where you can declare Properties (think variable declarations), that will be used in the build process. There are a number of built in Properties (Well-Known & Common properties) that really come from msbuild, these include things like specifying the Assembly Name, where the build output should go, and some specialty variables that can be used to get things like the path to the Project File, or the current directory. While these properties can help us there are a number of other properties that can come into play from all over, and we can frankly make up properties as we see fit (more on that later).

Ok so now we have an idea about the PropertyGroup so what about ItemGroup's? Well ItemGroup's are all about grouping Items we need to do SOMETHING with. I admit that probably doesn't clarify what I mean. So let's look at the Xamarin Essentials csproj. It's a good use case where the decision was made to turn off the default file globbing.

  <ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
    <Compile Include="**\*.netstandard.cs" />
    <Compile Include="**\*.netstandard.*.cs" />
  </ItemGroup>
  <ItemGroup Condition=" $(TargetFramework.StartsWith('uap10.0')) ">
    <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.1.5" />
    <SDKReference Include="WindowsMobile, Version=10.0.16299.0">
      <Name>Windows Mobile Extensions for the UWP</Name>
    </SDKReference>
    <Compile Include="**\*.uwp.cs" />
    <Compile Include="**\*.uwp.*.cs" />
  </ItemGroup>

There is a lot going on in this snippet so let's break this up. First you'll notice some conditions on these ItemGroup's. You do not have to ever use a Condition, but you can also put a Condition on Any Element. As I mentioned before, the EnableDefaultCompileItems Property was set to false, meaning that when this project is built, it will not compile ANY of the code unless we do something to include code. What you see here is that they have adopted a practice in which each file contains a platform identifier. This then allows them to have a condition in which the TargetFramework is evaluated and determine which C# files should be included in the compilation. Often times you may see multiple ItemGroup's in a csproj, with each Group containing a single set of Items, for instance only Embedded items, or Compile items, Project References. You'll notice here though that the ItemGroup can contain any set of Items, as the UWP ItemGroup contains a PackageReference, an SDKReference for Windows Mobile, and adds the UWP C# code.

Multi-Targeting

Perhaps one of my favorite features of the SDK Style Project is that it makes Multi-Targeting that much easier. As you may have noticed in the snippet above from the Xamarin Essentials csproj, they have a single Project that targets both UWP and netstandard. Honestly, Microsoft only get's partial credit here. The new Project system introduces the ability to specify TargetFrameworks rather than a single TargetFramework if we so choose. Unfortunately the team only thought about Full Framework Targets like net45 and netcore/netstandard targets, which is why I say they get partial credit. For the Xamarin Developer (or even the 3 UWP developers out there), this gets really frustrating. Luckily the community has Microsoft MVP/RD Oren Novotny, who developed a completely custom SDK that ships via NuGet which introduces support for all kinda of new targets including UWP, Xamarin iOS, Android, Mac, and even Tizen and WPF.

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
    <!-- Standard SDK Sytle Project that doesn't support cool targets -->
    <<TargetFramework>netstandard2.0</TargetFramework>
</Project>

So what do we have to do to start Multi-Targeting more fun targets as a Xamarin Developer? Well it's actually pretty simple, again thanks to Oren, the Microsoft team added support so that all we need to do is replace the value in the Sdk attrubute of the Project. To start with let's look how you might do this if you only care about a single Project. 

<Project Sdk="MSBuild.Sdk.Extras/1.6.47" ToolsVersion="15.0">
    <!-- Single Multi-Targeting Project... You control the version here as part of the Sdk string -->
    <TargetFrameworks>netstandard2.0;xamarin.ios;xamarin.android;uwp10.0.16299</TargetFrameworks>
</Project>

Suddenly you have the ability to create a single project that targets all of the platforms you want. But what about those cases where you still need to break code up into multiple projects? Well again it's very simple. Simply add MSBuild.Sdk.Extras as the Sdk value and then drop in a file called global.json next to your solution. (NOTE: You'll notice that this is what I've done for Prism)

{
    "msbuild-sdks": {
        "MSBuild.Sdk.Extras": "1.6.47"
    }
}

Of course you could ask why should you care about Multi-Targeting? Well have you ever noticed that you have to do some crazy thing like:

global::SomeProject.Platform.CoolRenderer.Init();

Suddenly you're referencing a bunch of Init methods that look like this:

public static void Init()
{
    // The Linker Sucks
}

public static void Init()
{
    // Watch the build is going to warn me about a variable I'm not actually using for anything....
    var a = DateTime.Now;
}

To me this has always been code smell. Ultimately the real reason you're having to do this so often is to ensure that the Linker sees an actual reference in code that goes into the Platform specific binary. This was a problem with the old project system since we had to have a sharable project (PCL), and then platform projects each of which needed to be bundled into a single NuGet. By Multi-Targeting you've already made references into the assembly to keep it from being stripped out reducing the legwork you need to do, to tell the Linker to pay attention to something else.

Multi-Targeting Snafu

Multi-Targeting is a fantastic tool. Unfortunately for those working on a Mac there is a little bit of legwork you need to do. Visual Studio Mac does not currently support Multi-Targeting projects. It really should, and is very overdue in my opinion. If you agree, I suggest pinging Jordan Matthiesen (@JMatthiesen) to let him know this needs to be a top priority for the team (and in the next alpha release)... I did say there is a little bit of legwork you need to do though, I never said it doesn't work. MSBuild LOVES Multi-Targeting so you can build these projects from the command line all day long. In fact, as one of the nice things that Mac developers get for FREE, both MSBuild and NuGet are added to your PATH when you installed Visual Studio Mac making building from the command line very easy. Generally for these Multi-Targeting projects I simply move my workflow into Visual Studio Code where I can easily write code and build from the integrated terminal.

I should probably admit the pain doesn't entirely stop there. UWP is simply an unresolvable target. The solution? Earlier I mentioned Conditions can be applied to any element, which includes the TargetFramworks element. If you lookup the well known MSBuild variables there is an OS variable. Unfortunately it's a bit simplistic meaning you're not going to figure out if you're on a Mac or Ubuntu or Centos, or Windows 7 or Windows 10... but you can at least figure out one thing... are you on Windows or not. So what does that look like:

<Project Sdk="MSBuild.Sdk.Extras">
    <PropertyGroup> 
        <TargetFrameworks>netstandard1.0;netstandard2.0;Xamarin.iOS10;MonoAndroid71;MonoAndroid80;MonoAndroid81;uap10.0.16299</TargetFrameworks>
        <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.0;netstandard2.0;Xamarin.iOS10;MonoAndroid71;MonoAndroid80;MonoAndroid81;</TargetFrameworks>
    </PropertyGroup>
</Project>

Packaging

Some of you may be wondering why you should be packaging your code? I've talked with a number of developers over the years who are engaged in a process in which for each release the entire code base is pulled from source control and built and released in one go. I've heard some interesting arguments for the practice, though I completely disagree with them. To be clear obviously something has to be built, but all of your common support libraries should be built and packaged as they are updated. There are actually a few benefits to this:

  1. This reduces build times... Imagine you have a single support library that's used in 5 applications that are released across your organization. This literally eliminates 4 completely unnecessary builds of that single project. Of course the reality is that you probably have a bunch of support libraries making the results that much greater.
  2. Versioning... It is a little scary when you think about it, but so many companies NEVER version their code. I have literally seen projects that started 15 years ago that are still on version 1.0.0.0 (from the template). In my experience these are companies that are probably storing your passwords in clear text, prefer http over https, and think a 56k modem is high speed internet instead of a painful memory of the 1990's. If you aren't versioning your code you really have no idea when a problem was introduced, if a problem has been fixed, or a regression has been made... you only have guesses.
  3. Garbage In -> Garbage Out... because you've built and shipped that project independent of the rest of your monolithic applications, it means that you have had a chance to validate the code base before it finds it's way into use by others in your development team or a production environment. For many (realistically) this means that you are protecting yourself from that developer who checked in code that doesn't build. For others it means that you have ensured that all of your unit tests for that project have both run and passed.
  4. Testability... I know what you're thinking, you're perfect, and so are the rest of the developers on your team. I totally understand, that's why I like to wear the shirt declaring "I don't always test my code, but when I do, I do it in Production". But for that time when maybe you forgot to update that one repo that you aren't responsible for, but that repo is required to build the project you are responsible for. The simple truth is as a .NET developer you're used to looking at the package manager for Updates. When your support libraries are packaged and available to your team via a private or public NuGet feed, it becomes easy to discover that an update is available. Because the discoverability is actually going up, it means that the entire team really has a better opportunity to test the code in development before it ever sees production.

How do you get started?

Maybe you didn't need convincing, maybe you just need to know how to get started. Well for starters, let's completely toss out the idea of using a nuspec. They're annoying and frankly if you're multi-targeting... they are error prone. There are still a few monolithic projects out there like Xamarin.Forms that still require the use of a nuspec (largely due to the issues around Packing that the NuGet team needs to fix/implement), but the reality is that if you're using a Sdk Style project you probably don't need it.

Earlier I mentioned that you could completely make up properties to put in the PropertyGroup of your csproj. Well when the Sdk Style projects were created, the folks at Microsoft decided to make up some new Properties to help with the very common task of packaging your projects. Many of these properties can be found at the links below. Some are a little harder to discover such as the GeneratePackageOnBuild property. By default this is false, however when you set this to true, all you need to do is build your project and each build will generate a new NuGet package for any packable projects in your solution. You'll find there is no right or wrong way as much as there is a way that makes sense for the project you are working on. Many of my projects, including Prism include a Directory.build.props in the solution directory, this allows me to set this value in a single place. Since IsPackable is true by default this means that you need to have some logic to set IsPackable to false on projects that should not be packed such as Tests and Samples.

Project References... Package References Oh My

You may know a little bit about a Project Reference and Package Reference. The difference here being that a Package Reference comes in from a NuGet feed, while a Project Reference is a Reference to a local project in the file system. So what happens then when you want to build and package a project? What happens to those Project References? A friend of mine recently asked if I could come take a look at a project he had been working on. Well every Project Reference is assumed to be a Reference that will be needed by the generated package. This means that there is no need to have some crazy conditional includes for a Package configuration.

<Project Sdk="MSBuild.Sdk.Extras">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup Condition=" $(Configuration) != 'NuGetRelease' ">
        <ProjectReference Include="../AnotherProject/AnotherProject.csproj" />
    </ItemGroup>

    <ItemGroup Condition=" $(Configuration) == 'NuGetRelease' ">
        <PackageReference Include="AnotherProject" Version="$(Version)" />
    </ItemGroup>
</Project>

All you actually need is just your ProjectReference. When the project is built, this assumes that it is being Packed and will actually pick up whatever the version number is that, that specific project was packed with.

<Project Sdk="MSBuild.Sdk.Extras">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <ProjectReference Include="../Foo/Foo.csproj" />
    </ItemGroup>
</Project>

Because it will pick up the other project automatically it means that you just need to ensure that the Pack target is invoked.

> dotnet pack MyProject.csproj -c Release
> msbuild MyProject.csproj /p:Configuration=Release /t:pack

Earlier I mentioned the GeneratePackageOnBuild element which is false by default. All we need to do is set this to true like in the following example or add it to our Directory.build.props file and EVERY build will now generate a package automatically.

<Project Sdk="MSBuild.Sdk.Extras">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
        <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    </PropertyGroup>
</Project>

Directory.build.props

For those paying attention, you've heard me mention the Directory.build.props... this is one of my favorite files, and in some ways a replacement for the nuspec*, in other ways it's just something I use to make my DevOps processes smoother. This is a slightly refined version of what I have published previously.

<Project>
  <PropertyGroup>
    <Product>$(AssemblyName) ($(TargetFramework))</Product>
    <DefaultLanguage>en-US</DefaultLanguage>
    <Authors>Your Name Here</Authors>
    <Copyright>© $([System.DateTime]::Now.Year) Your Name Here</Copyright>
    <PackageIconUrl>Uri to an icon image (png)</PackageIconUrl>
    <PackageLicenseUrl>Uri to the license</PackageLicenseUrl>
    <PackageProjectUrl>Uri to the project</PackageProjectUrl>
    <RepositoryUrl>Uri to clone the project</RepositoryUrl>
    <PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
    <RepositoryType>git</RepositoryType>
    <!-- Root control Version Prefix -->
    <VersionPrefix>1.0.0</VersionPrefix>
  </PropertyGroup>

  <!-- CI Helpers -->
  <PropertyGroup>
    <PackageOutputPath>$(MSBuildThisFileDirectory)/Artifacts</PackageOutputPath>
    <PackageOutputPath Condition=" $(BUILD_ARTIFACTSTAGINGDIRECTORY) != '' ">$(BUILD_ARTIFACTSTAGINGDIRECTORY)</PackageOutputPath>
    <IsPackable Condition=" $(ProjectName.Contains('Sample')) ">false</IsPackable>
    <IsPackable Condition=" $(ProjectName.Contains('Test')) ">false</IsPackable>
    <GeneratePackageOnBuild>$(IsPackable)</GeneratePackageOnBuild>
    <IS_PREVIEW Condition=" $(IS_PREVIEW) == '' ">false</IS_PREVIEW>
    <IS_RELEASE Condition=" $(IS_RELEASE) == '' ">false</IS_RELEASE>
    <VersionPrefix Condition=" $(BUILD_BUILDNUMBER) != '' ">$(VersionPrefix).$(BUILD_BUILDNUMBER)</VersionPrefix>
    <VersionSuffix>ci</VersionSuffix>
    <VersionSuffix Condition=" $(IS_PREVIEW) ">pre</VersionSuffix>
    <VersionSuffix Condition=" $(IS_RELEASE) "></VersionSuffix>
  </PropertyGroup>
</Project>

You'll notice that in this Directory.build.props file I have split it into two PropertyGroups to make it a little easier to read. So let's take a look at the first PropertyGroup.

  • Product: The Product line here gets updated to include both the Target Framework and Assembly Name instead of just the Assembly Name. This is particularly helpful for multi-targeting projects as it can help identify which framework specifically was being used when an error occurred.
  • You'll notice several elements here that contain placeholders for Uri's for specific to your project, and your name. These are all elements that came from the nuspec which are now taken care of and will be uniform across your entire solution helping to ensure that you don't have to duplicate values all over. 
  • VersionPrefix: This is the root version number that I want to control. Every single build will start with this version string.

Ok great, now let's take a little closer look at what's going on in the CI Group.

  • PackageOutputPath: Maybe you have just one project, or maybe you have 10 that are built and packaged for your solution. Even with one, it can get a little tedious to have to drill down into the Project's output folder {Path To Project}/bin/{Build Configuration} each time you want to get the generated NuGet. When you have multiple projects though this gets really annoying. By setting this value we ensure that all of the packages are created in a common location making it easier to find. By default we are creating an Artifacts folder under the current directory (where the Directory.build.props is located). On VSTS however we are defaulting that location to be in the Artifact Staging Directory defined by VSTS.
  • IsPackable: By default this is true, so we have a check to see if the Project Name contains either the word Test or Sample. If it contains either one we mark the project as NOT packable.
  • GeneratePackageOnBuild: By default this is false meaning you either need to explicitly invoke the Pack target. By setting this to true we will generate the Packages on each build. If this is too much, or you don't want to accidentally ship a Debug build, you could add a condition to only set it to true when the build Configuration is Release.

*NOTE:
Just to prevent some confusion here, there is still a nuspec in the process, only it is automatically generated by the build task rather than you having to maintain it as part of your project.

Helpful Links

For more information and to see how I build many of my tools and support libraries see this post I wrote on the new Project Format. Still have questions feel free to leave a comment or reach out on Twitter.

Azure Active Directory B2C for Xamarin Applications

You may have heard about Azure Active Directory B2C before. There have been a number of posts on the topic previously, including an episode with Matthew Soucoup on the Xamarin Show. So why yet another blog post? Well to be honest the documentation can be a little confusing, and there is more to the setup of a tenant than you may have read about. There is absolutely nothing difficult about it in any way. However if you miss some critical configuration steps you'll struggle to ever authenticate with Azure Active Directory.

Why Azure Active Directory B2C

Well for starters most of our apps today need some sort of authentication. There is a huge liability with storing user credentials, so while you might be able to use an OSS solution to implement your own OAuth flow, you're now taking the direct responsibility for properly maintaining the security of your users. If you're a large Enterprise that may not be a huge problem for you. For the rest of us (and even those large Enterprises), there is is a lot of benefit in offloading these tasks to 3rd parties like Microsoft. Not to mention that with the B2C offering we can further push off the responsibility to a number of common OAuth providers like Facebook, Twitter, LinkedIn, Google, etc.... and by checking a box you can enable 2-Factor authentication.

Ultimately what this means is that remove identifying user information from your own database storing only the Active Directory ObjectId for the user in your own database making breaches inherently less damaging as there is nothing more than a Guid in your database.

Beyond the security topic, cost is also important, particularly to a small business. While some of my larger clients have had projected user bases that may be in the hundreds of thousands or millions, for the vast majority of my clients Azure Active Directory B2C represents an Enterprise Grade OAuth service that will cost them absolutely NOTHING as their realistic projected user base ranges from a couple of users to less than 5,000. Since Azure Active Directory B2C gives you 50,000 users and 50,000 authentications per month for free, this results in the service being 100% free for them to use.

Basic Concepts

It is important to remember the Azure Active Directory B2C is built on top of Azure Active Directory. This means that you do not have some magical new offering from Microsoft, but an existing, trusted, enterprise grade offering with some extensions that make a Business offering suitable to use directly with your Customers. This also means that IAM for your staff is handled through standard Active Directory user groups. 

Azure Active Directory / B2C both follow some basic OAuth concepts. Among these concepts is that you may have 1 - * Client Applications that are authenticating with the service. It can be a little confusing and this is probably where you're likely to go wrong in the configuration (more on that in a minute).

Working with Azure Active Directory B2C might be a little confusing for Xamarin developers who are looking for that Native approach. Since we are working with an OAuth service we are forced to use a web view to actually authenticate. This means you cannot create that fully native view that makes a rest call as the user will have to Register or Login using the web view from the MSAL library. 

Configuring the Application in Azure

When you first open your B2C tenant you should see something like the following (be sure to grab the tenant name circled as you will need it later for your Xamarin app):

You'll need to begin by setting up an application. While there is no specific requirement that you set up more than one, my personal preference is to secure each application with it's own Application Id and limit what it has access to. For the purposes of this post I'll be setting up two applications, one for the Web API, and one for the Mobile App. It's worth noting here that this configuration is going to be a lot of back and forth as we set things up.

We'll begin by adding a new Web API  application. To start we'll give this the name Awesome API, because let's face it... it's awesome. Then be sure to add a Reply URL. For now we'll add a localhost, this can be updated later. Next be sure to completely ignore the horribly wrong optional comment for the App ID... it's not... For this we'll give it the ID api.

Now let's add an application for our Mobile App. Since this is for our mobile app, we just want the Native Client.....

Ok, I lied... so this is one of the things that isn't very obvious, but in order to be able to add scopes (which we'll need in our app), we actually have to enable the Web App / Web API section. Remember I said earlier to ignore the complete lie that App ID is optional. If we don't set the App Id we won't be able to add a scope, and we can't actually do that unless Web App / Web API is enabled.

IMPORTANT: After you've created the application for the Mobile app, be sure to open it back up, copy the Application Id, and set the Custom Redirect URI, under the Native Client. The Redirect URI will always be:

msal{Your Application Id}://auth

Now both of our applications have a basic configuration, we can go into the applications and set up the scopes. You'll see by default we have the user_impersonation scope. This is apparently used for the Microsoft Graph, and we'll want to set up our own scope. I personally haven't seen any documentation on right or wrong scopes, but as I understand it we actually will want to at least add a read scope here for our applications.

With our scopes set in both applications, we can now take a look at the API Access, and here is one of those areas where again things aren't really obvious.

You might be thinking as I did, that your application has permission to talk to itself... because why wouldn't it, right? Well it actually doesn't unless you add permission for each application to have access to itself under API Access. What happens if you skip this step? Well for starters you won't get an Access Token, and then what is the point of using Azure Active Directory B2C because you went through a bunch of setup to not have a token...

Finally for the Mobile App, be sure to add both the Mobile App itself with all permitted scopes, and the Web Api with all permitted scopes. When you're done, it should look something like this.

Adding a Policy

Earlier I mentioned that you will be using a Web View from the MSAL library to work with your B2C tenant. The way that this is exposed is with Policies. At the time of this article there are currently 6 policies that you can configure. These are fairly straight forward. To start, you'll likely want to add a policy to allow users to either Sign Up or Sign In. You can alternatively separate these tasks so that in your underlying UI you have separate Login and Register buttons with each one bringing you to a UI from B2C that makes sense for that work flow. If you have configured any Identity Providers (not covered by this article), you will be able to choose whether to use those and/or the local account. 

Setting up the Xamarin App

To use Azure Active Directory or Azure Active Directory B2C in your Xamarin or Xamarin Forms application you will need to install the Microsoft.Identity.Client (which is still only available as a preview package on NuGet). There is actually fairly decent setup instructions for considerations you'll want to have setting up the client in your Xamarin iOS and Android applications in the official sample app on GitHub. While I would hardly consider the sample anywhere close to demonstrating best practices as it fully exposes the Tenant and Application Id in source control, not to mention I am very much against static references, I will say it is a great sample to validating that you have correctly configured your new B2C Tenant. 

Going back into the Azure portal grab the Application Id for the Mobile App, along with the tenant name from the first step. Finally grab the read scope from the mobile app. If you're using the Azure sample app, you just need to update these couple of fields and run the app. If you put a break point in the MainPage.xaml.cs after the call to AcquireTokenAsync you should be able to evaluate the AuthenticationResult and see both an IdentityToken and AccessToken along with the expiration. If you see both, your tenant is correctly configured and you can now use Azure Active Directory B2C to correctly authenticate. 

Developer Toolkit for Visual Studio Mac

Several years ago when I was still just a web developer wanting to break into mobile development, I asked myself how does anybody do this? You have to learn Java for Android, Objective-C or Swift for iOS.... of course then I learned about Xamarin. Without a doubt Xamarin makes the tedious tasks of mobile app development far easier by centralizing your code in one common language, and even further with Xamarin Forms by abstracting the UI into reusable code. That doesn't mean that creating a new app is by any means easy. In fact setting up a new app can take a lot of time.

Nearly a year and a half ago I introduced the Prism QuickStart Templates which were the first .NET Standard templates using the new project format available for Xamarin apps. The project took on a life of it's own and was loved by many even despite it's limited availability in the CLI. As I set out to bring the templates into Visual Studio for Mac, it again took on a life of its own. A number of developers and MVP's were gracious enough to give me their feedback on things they would like to see, and while it may have delayed my ability to release, what we have today is simply stunning.

Prism Template Studio and Developer Toolkit

Ok I admit it, it's a mouthful, and if you have a better name feel free to tweet it to @DanJSiegel. Why the mouthful, because it is absolutely jammed pack with so many tools, so many helpers, and so many templates, that every time I explain it someone asks, "well what about...", and I keep either responding yeah it does that too... or yeah we could add that. It's probably that second one that has admittedly  generated the most delay in getting this out. Whether you use vanilla Xamarin Forms or Prism you'll want to install the Prism Template Studio and Developer Toolkit. 

Templates

As the name suggests it contains the a Template Pack. This Template Pack isn't quite like anything you've seen before. There are 14 new project templates that ship in this Template Pack, including 7 projects for Unit and UI Testing, 3 more for building Prism Modules, and another 3 for Prism Applications, plus a new basic Xamarin Forms project template.

Each of the templates bring something special for different developers. You can still go with the traditional flat "Official" template, or one includes PropertyChanged.Fody with projects and tests separated into src and tests folders. You can also take advantage of the powerhouse QuickStart Template or the App Center Connected App. Both of these provide the to setup a project in VSTS and automatically configure a Build in App Center.

Tools

To start there is some integrated tooling for all of your Xamarin projects to enable support for the Mobile.BuildTools, you can connect an existing project to an app in App Center, and even get some quick links to the Prism Docs, GitHub issues, and StackOverflow. Over time you can expect to see additional tooling for App Center, and refinements to do more with VSTS and better expand on your ability to get started with Unit and UI Tests.

Get started today by making sure Visual Studio Mac is up to date, and then simply install the Prism Template Studio and Developer Toolkit from the Extension Manager.

Prism 7.1 Preview 3

Today we released the 3rd Preview for Prism 7.1. This is a very significant release for us and contains some very exciting changes.

Forms Dependency Resolver

At Build we released a special preview for Xamarin Forms. In that preview we released the much awaited ability to use your Application's DI Container to resolve types inside of Xamarin Forms such as your Renderers or Platform Effects. It was a great feature but there were some issues caused on Android by the transition from a default constructor to one that requires the Android Context. Preview 3 fixes this by adding a specific Android target to each of the DI packages to handle passing the Context to the Container while resolving your Renderers.

We asked the community and while people were very torn on the subject, it was very overwhelming that using the DependencyResolver is something that should be configurable. As a result we've updated PrismApplication's constructor to accommodate this. First we removed the optional parameter for IPlatformInitializer and simply provided both a Default constructor and one that takes IPlatformInitializer. Second we added a new constructor that takes both IPlatformInitializer and a boolean to control whether we should set the DependencyResolver. As you may have guessed both of backwards compatible constructors call the new constructor, and by default will pass false to prevent PrismApplication from setting the DependencyResolver. 

Just as with Preview 2, you can still override SetDependencyResolver in order to provide your own logic.

Known Issues

FFImageLoading is a very popular image handling library. Unfortunately the CachedImageRenderer as 2 completely unnecessary constructors as they will never be used by Xamarin Forms and they only serve to confuse a DI Container. By default most DI containers will attempt to resolve a type based on the constructor with the most arguments. In the event that more than one constructor exists with the same "Highest" argument count, it will select the first one. This is the case in the CachedImageRenderer which results in the container attempting to resolve the Renderer with CachedImageRenderer(IntPtr, JniHandleOwnership).

In order to handle this you will need to add a specific registration for the Renderer in your Android Initializer. This will look different based on which container you are using. If you're using DryIoc, you can easily add either of the following examples to fix the issue:

public class AndroidInitializer : IPlatformInitializer
{
    public void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.GetContainer().Register<CachedImageRenderer>(made: Made.Of(() => new CachedImageRenderer(Arg.Of<Android.Content.Context>())));
        // OR with Reflection
        containerRegistry.GetContainer().Register<CachedImageRenderer>(made: Made.Of(typeof(CachedImageRenderer).GetConstructor(new[] { typeof(Android.Content.Context) })));
    }
}

Modularity

Modularity has been on my personal hit list for a while now, and Preview 3 makes some major changes to help accomplish the final goal of aligning the Modularity API between WPF and Xamarin.Forms as well as making it available for UWP. To start with we've moved the Modularity Exceptions from WPF to Prism.Core, along with ModuleInfo, IModuleInitializer, and IModuleManager. Among the changes, this means that Xamarin.Forms apps will be able to listen for the ModuleLoaded event and capture any exceptions that may occur during the Module's Initialization. 

For WPF developers defining their ModuleCatalog in XAML this means a break as ModuleInfo is now in Prism.Core. Rest assured though that some care has been taken to ensure that any API changes are addative and beneficial. An example of this is that the constructor's from Prism.Form's version of ModuleInfo were added to ModuleInfo in Prism.Core. For Prism.Forms developer's a bigger break in ModuleInfo was introduced by changing ModuleType from Type to string. While I say bigger break, this should only affect developers who are directly referencing ModuleInfo's ModuleType property. Since the Modularity API in Prism.Forms favor's generics this should have a minimal impact for most developers.

XAML Navigation

Yep, I said it... This was an amazing idea and PR that came from the community. Over the past week I've had a chance to dogfood this one, and I have high hopes for what this will empower developers to do. Up until now you would need to have a ViewModel, inject the NavigationService, create a command, and an action for the command that uses the NavigationService to navigate to some other page, and then bind that command to some Button. Now with XAML Navigation you can simply have:

<Button Text="Continue"
              Command="{prism:NavigateTo ViewB}" />

Just as an example this could be used to completely eliminate a ViewModel on a Page that is simply a landing page that simply prompts the user to continue. This could be very useful for pages used in OnBoarding new users where you are explaining how to do something in your app. There is full documentation on this feature in the Prism Docs. Be sure to read more there on how to use NavigationParameters which would again make it easier to handle scenarios where you are try to Navigate based on a Cell in a ListView or a RepeaterView that so many of us have implemented.

Additional Notes

Perhaps one of the first things that developers have had to learn with Prism.Forms is that you must name INavigationService 'navigationService' in your constructor otherwise it won't be injected into your ViewModel. While that hasn't been the case in DryIoc for a while, this is now a thing of the past for Autofac and Unity as well. 

While you may not have heard of this one before, SourceLink is an amazing new tool for OSS libraries to empower developers debugging experience. Sadly this only works in Visual Studio on Windows and is only in the Backlog for Mac for now, but for those working in Visual Studio 2017 this will let you step into Prism's code while you debug. 

Last but certainly not least. A few months ago Oren Novotny began talking to me about signing NuGet packages. After hearing what he had to say, I had to agree wholeheartedly that it was something we should do for our user base. Beginning with Preview 3, we are now signing each NuGet package as part of our release pipeline. This means that when you consume our packages you will be able to verify that the package actually comes from the Prism team and has not been altered between us and you.

Be sure to try out the new Prism 7.1 preview today and let us know what you think. Be sure there is more great stuff to come.

Prism 7.1 Preview 1

Maintaining a library can be exceptionally difficult. As time progresses new demands arise that weren't there when the API was first created. Sometimes simple work arounds can be found to prevent breaking library consumers when they upgrade. Sometimes the changes are no brainers that have no negative affects. Sometimes changes simply aren't made because the potential breaks are simply too risky. Other times the benefits simply outweigh the break and changes are made.

Prism 7.1 is largely the result of changes that the Prism Team has come to realize had to be made. As part of the overall Prism 7.X effort, the team has been working on bringing the API closer together across each platform target where possible. Currently this is perhaps most evident with the introduction of the Prism.Ioc namespace allowing developers to more easily port from one DI Container to another, and even create Prism Modules that are sharable across projects with different DI Containers.

In this release have made some major changes to better unify the API between Xamarin Forms and our ongoing work with Jerry Nixon to bring Template 10 to Prism for UWP. This effort though represented the need to create a binary incompatibility, a need to create some breaking changes, and an opportunity to greatly improve the API for Xamarin Forms developers. So what are the changes? For starters we've migrated most of the Prism.Navigation namespace from Prism.Forms to Prism.Core. After a lot of deliberation we ultimately decided that these changes should not be available to WPF developers as it just doesn't make sense for WPF applications. 

In addition to the binary incompatibility caused by moving the classes from one binary to another, this creates a secondary break in the WPF will NOT be supported for Xamarin Forms developers.

I mentioned that there are breaking changes and some opportunities for improvements as well. The break that you will encounter should be fixable with a simple Find/Replace in your IDE or text editor, as NavigationParameters is now INavigationParameters which changes the method signatures for INavigatingAware, INavigatedAware, INavigationAware, IConfirmNavigation, IConfirmNavigationAsync, and INavigationService. While that may provide you with some unique opportunities for testing, that isn't the exciting change. The change is the return type from INavigationService from a simple Task to Task<INavigationResult>. Why is that so great? Well for one thing if the Navigation failed for some reason you'll have access to a Boolean to more easily execute that logic. It's also great though because until now the NavigationService could make it harder to determine what type of exception may have been thrown. INavigationResult fixes this by returning the actual exception that was thrown allowing you greater control over what to do with it.

var result = await _navigationService.NavigateAsync("BadPage");

if(!result.Success)
{
    await _pageDialogService.DisplayAlertAsync(result.Exception.GetType().Name, result.Exception.Message, "Ok");
}

 

Perhaps my single favorite improvement in Prism 7.1 for Xamarin Forms developers is the inclusion of the ContainerProvider. This was born out of a desire to be able to declare types such as a TypeConverter that may rely on some service in your application. The ContainerProvider will allow you to declare in XAML, types that do not have a default constructor and inject any of your applications services into that type. 

<?xml version="1.0" encoding="UTF-8" ?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:prism="clr-namespace:Prism.Ioc;assembly=Prism.Forms"
    xmlns:converters="using:Prism.Forms.Tests.Mocks.Converters"
    Title="{Binding Title}"
    x:Class="Prism.DI.Forms.Tests.Mocks.Views.XamlViewMock">
    <ContentPage.Resources>
        <ResourceDictionary>
            <prism:ContainerProvider x:TypeArguments="converters:MockValueConverter" x:Key="mockValueConverter" />
        </ResourceDictionary>
    </ContentPage.Resources>
    <Entry x:Name="testEntry"
           Text="{Binding Test,Converter={StaticResource mockValueConverter}}" />
</ContentPage>

Unity

Unity has been one of the most popular containers for Prism Developers. I have no doubt that this has a lot to do with the fact that it is the container Brian has used for years, has used in his demos and that was most widely available in the Prism Template Pack. The Unity team has made some major design changes in Unity 5.X. For Prism developers using Unity we have long since had a dependency on the Unity NuGet package. In it's current state, this actually broke Prism.Unity.Forms for netstandard1.0. 

The Unity team has redefined the Unity NuGet package to be an all inclusive package that presents several problems. For Xamarin Forms developers, it introduces references to 6 more assemblies than what you actually need or would use. For WPF developers it creates a secondary, and hidden reference to CommonServiceLocator, as well as the inclusion of 5 more assemblies than what you need or Prism uses. To continue depending on this NuGet package represents an additional issue that it could continue to break Prism developers. To resolve this, Prism 7.1 has changed it's target from Unity to Unity.Container. This change will be unnoticeable to anyone who uses the new PackageReference to include NuGet's in their projects, particularly when you have your dependency on Prism.Unity or Prism.Unity.Forms and not Unity itself. For all other Unity developers, you should uninstall Unity from your projects before upgrading to Prism 7.1.

.NET Standard & the New Project Format for Xamarin Developers

.NET Standard has really changed the ballgame for .NET Developers. In large part because the entire project system has experienced a revamp. Lately I've found myself really encouraging developers to update their PCL libraries to .NET Standard 2.0. For developers who haven't made the jump it's easy to find yourself saying "no we can't do it". In reality it doesn't take as much effort as you think it does to update your projects. Why should you update your projects though? Well for starters PCL is painful, you lookup how to do something only to find out that it's not supported and sometimes there's no workaround. With .NET Standard the missing API's that lead to weird workarounds is a thing of the past.

Upgrading

Upgrading really isn't as hard as you may think. For starters your csproj is going to start out about as simple as:

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>
</Project>

Then of course we need to start adding in your dependencies. Now this is where it gets "Hard". It's hard because it means you need some familiarity with your project. You need to know what are the top level dependencies that your project has. For example if you're using Prism there are generally 3 Prism packages you're referencing, Prism.Core, Prism.Forms, and Prism.{Some Container}.Forms. It's only the last one that you actually need to reference in the new project format. You can of course add this from either Visual Studio or Visual Studio Mac or update it manually so that your project file now looks like:

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Prism.DryIoc.Forms" Version="7.0.0.396" />
  </ItemGroup>
</Project>

Assuming you wanted to get started with Prism for Xamarin Forms this would be all you would actually need as all three Prism packages are automatically brought in along with Xamarin Forms. Now let's say that you wanted to target a newer version of Xamarin Forms than 2.5.0.122203, such as the 3.0 preview that's now available. You simply need to add a new PackageReference for that version of Xamarin Forms or install it in the IDE's Package Manager.

That may seem too easy, and it is. Of course you need to make some more changes. You'll need to find the packages.config or project.json and delete those files... If you have a standard Properties/AssemblyInfo.cs you'll need to go ahead and send that one to the trash as well. With that your project is upgraded, and you're wondering why you didn't do this sooner....

Multi Targeting

Around 5 years ago I first started trying to Multi-Target. My earliest attempts were pretty bad with a csproj file for each framework I wanted to target, all part of the same solution, and it generally resulted in build errors due to file locks as I had no clue how the build system worked back then. Honestly I've never found much documentation that made it very easy, and while I eventually figured out I could do lots of MSBuild trickery to make it work, and then manually develop a nuspec to pack my library, it was always really painful. The new Project system gives us some real advantages for Mutli-Targeting that make it a real breeze.

I suppose though I should start with why on earth should you multi-target... and when would you want to? If you're a Xamarin developer chances are you want to Multi-Target. Internally and for all of my clients I generally start off with a common library. This is something that is really helpful to give me extensions, and custom controls that I may want to use across all of my apps or components like a Prism Module. A lot of that code is truly portable and I could easily handle it with a simple netstandard2.0 class library. However sometimes I'm implementing Platform Effects and Renderers for my controls that instantly require that I have a native binary for my iOS and Android projects. This is where multi-targeting really becomes very powerful. By Multi-Targeting I maintain a single Project which generates a single binary, native to the platform I need to target. Now if we expand on the basic project structure we saw above and now update our csproj to look like the following we can target both .NET Standard 1.3 & 2.0, along with Android, iOS, Mac, and UWP. It's worth noting that the non .NET Standard targets are really getting a lot of help due to the MSBuild.Sdk.Extras package from Oren Novotny.  

<Project Sdk="MSBuild.Sdk.Extras/1.5.4" ToolsVersion="15.0">
  <PropertyGroup>
    <TargetFrameworks></TargetFrameworks>
    <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">netstandard1.3;netstandard2.0;Xamarin.iOS10;Xamarin.Mac2.0;MonoAndroid80;uap10.0.16299</TargetFrameworks>
    <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard1.3;netstandard2.0;Xamarin.iOS10;Xamarin.Mac2.0;MonoAndroid80</TargetFrameworks>
  </PropertyGroup>
  <ItemGroup>
    <Compile Remove="**/Platform/**/*.cs" />
    <None Include="**/Platform/**/*.cs" />
  </ItemGroup>
  <ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
    <None Remove="**/Platform/Droid/**/*.cs" />
    <Compile Include="**/Platform/Droid/**/*.cs" />
  </ItemGroup>
  <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) ">
    <None Remove="**/Platform/iOS/**/*.cs" />
    <Compile Include="**/Platform/iOS/**/*.cs" />
  </ItemGroup>
  <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.Mac')) ">
    <None Remove="**/Platform/macOS/**/*.cs" />
    <Compile Include="**/Platform/macOS/**/*.cs" />
  </ItemGroup>
  <ItemGroup Condition=" $(TargetFramework.StartsWith('uap10.0')) ">
    <None Remove="**/Platform/UWP/**/*.cs" />
    <Compile Include="**/Platform/UWP/**/*.cs" />
  </ItemGroup>
</Project>

So what's going on here anyway? Well for starters we're establishing some conventions for our code. We are saying that anywhere in our project that we have a folder named Platform we are going to change the inclusion of those files from Compile to None. This means that the IDE will display our code while MSBuild will ignore our code. Then, we start conditionally adding code back in so that when MSBuild is compiling for iOS and it encounters code that has a path that includes Platform/iOS, that code will be added back in for compilation. 

Generating a NuGet

If you're trying to generate a library that you can easily consume in your projects, or if you're trying to make it available for the community at large, these new SDK style projects are make generating a NuGet easier than ever. You just need to worry about what targets you want to compile for, and the NuGet largely takes care of itself with very little that we actually need to add. It's really just a few properties that we need to add to our project. Of course, if you take a look at any of my projects you'll notice a recurring theme, most of my NuGet configurations aren't even in the project file at all. Along the way I've come to realize the power of a file called Directory.build.props. This is a little bit of a magic file. If it exists anywhere from the solution folder to your project folder it will automatically be picked up by MSBuild. 

Looking at a real world example

Prism has more than 15 NuGet packages that have to generated on every build. Honestly for WPF we still use the older style projects which is a painful process, but the rest of the projects all share a lot of common logic.

  • If there is a project that isn't a test project we don't want it to Generate a NuGet. 
  • The package authors are always going to the members of the Prism Team.
  • The source is always located on GitHub in the same repository.
  • We always want to provide symbols packages.

Without using the Directory.build.props in our solution directory we would have to replicate this information in every single project file. 

Setting your project up for NuGet Packaging

If you want to pack your project all you really need to do is to add the following Directory.build.props to your project:

<Project>
  <PropertyGroup>
    <Product>$(AssemblyName) ($(TargetFramework))</Product>
    <NeutralLanguage>en</NeutralLanguage>
    <Authors>Your Name Here</Authors>
    <VersionPrefix>1.0.0</VersionPrefix</VersionPrefix>
    <VersionPrefix Condition=" '$(BUILD_BUILDID)' != '' ">$(VersionPrefix).$(BUILD_BUILDID)</VersionPrefix>
    <IS_PREVIEW Condition=" '$(IS_PREVIEW)' == '' ">false</IS_PREVIEW>
    <IS_RELEASE Condition=" '$(IS_RELEASE)' == '' ">false</IS_RELEASE>
    <VersionSuffix>ci</VersionSuffix>
    <VersionSuffix Condition=" $(IS_PREVIEW) ">pre</VersionSuffix>
    <VersionSuffix Condition=" $(IS_RELEASE) "></VersionSuffix>
    <PackageProjectUrl>https://github.com/USER/PROJECT_NAME</PackageProjectUrl>
    <PackageLicenseUrl>https://github.com/USER/PROJECT_NAME/blob/master/LICENSE</PackageLicenseUrl>
    <RepositoryType>git</RepositoryType>
    <RepositoryUrl>https://github.com/USER/PROJECT_NAME</RepositoryUrl>
    <IncludeSymbols>True</IncludeSymbols>
    <IncludeSource>True</IncludeSource>
    <PackageOutputPath>$(MSBuildThisFileDirectory)Artifacts</PackageOutputPath>
    <PackageOutputPath Condition=" '$(BUILD_ARTIFACTSTAGINGDIRECTORY)' != '' ">$(BUILD_ARTIFACTSTAGINGDIRECTORY)</PackageOutputPath>
    <IsTestProject>$(MSBuildProjectName.Contains('Test'))</IsTestProject>
    <GenerateDocumentationFile>!$(IsTestProject)</GenerateDocumentationFile>
    <GeneratePackageOnBuild>!$(IsTestProject)</GeneratePackageOnBuild>
  </PropertyGroup>
</Project>

 

Secure App Builds with AppCenter

AppCenter has been touted as this wonderful new service from Microsoft. It's supposed to make it easier to build, test and distribute our apps. While there is a lot I love about AppCenter, the simplification of the Build pipeline over VSTS always seemed to be problematic to me. For years I have had a pet peeve that developers often check things into source control that should never be checked in. Sometimes it's simply a backend URL, other times it could be a Client ID. These sorts of things should never be checked in, and should be injected as part of the Build pipeline. The problem is that when you have only a very simple process in place for creating a new build it opens you up to make these sorts of poor decisions with your code base.

For those who are familiar with AppCenter you may be familiar with the fact that you can add scripts to your projects:

  • appcenter-post-clone.sh (Bash for iOS & Android)
#!/usr/bin/env bash

# Example: Clone a required repository
git clone https://github.com/example/SomeProject

# Example: Install App Center CLI
npm install -g appcenter-cli
  • appcenter-pre-build.sh (Bash for iOS & Android)
#!/usr/bin/env bash

# Example: Change bundle name of an iOS app for non-production
if [ "$APPCENTER_BRANCH" != "master" ];
then
    plutil -replace CFBundleName -string "\$(PRODUCT_NAME) Beta" $APPCENTER_SOURCE_DIRECTORY/MyApp/Info.plist
fi
  • appcenter-post-build.sh (Bash for iOS & Android)
#!/usr/bin/env bash

HOCKEYAPP_API_TOKEN={API_Token}
HOCKEYAPP_APP_ID={APP_ID}

# Example: Upload master branch app binary to HockeyApp using the API
if [ "$APPCENTER_BRANCH" == "master" ];
then
    curl \
    -F "status=2" \
    -F "[email protected]$APPCENTER_OUTPUT_DIRECTORY/MyApps.ipa" \
    -H "X-HockeyAppToken: $HOCKEYAPP_API_TOKEN" \
    https://rink.hockeyapp.net/api/2/apps/$HOCKEYAPP_APP_ID/app_versions/upload
else
    echo "Current branch is $APPCENTER_BRANCH"
fi

Simplifying Builds

While ridiculously powerful in what you can do with these scripts (I've been told you can install pretty much anything you want), this seems like far too much effort. I'll even admit that while I'm quite capable of writing whatever scripts I want, beyond a POC, I have never, and have no plans of writing scripts, to get my projects building on AppCenter. There are some things, that shouldn't require lots of work, just to make builds work from one project to another. This is where the Mobile.BuildTools comes in. The Mobile.BuildTools is an easy to use NuGet package. It simply adds tooling for MSBuild and has no binaries that are injected into your application. Because of this it can be used anywhere that you have MSBuild including Visual Studio, Visual Studio Mac, Visual Studio Code, or any Build Host including AppCenter. I have often referenced it as "DevOps in a box", or at least in a NuGet. I should probably add here, that it's called Mobile.BuildTools not just because you can use it on Mobile Apps. You can use this on literally ANY .NET Project, on ANY Platform supported by MSBuild.

Setting Up Your Application

After installing the NuGet, we can add a JSON file to our PCL or .NET Standard named secrets.json, like the following:

{
  "AppCenter_iOS_Secret": "{Your Secret Here}",
  "AppCenter_Android_Secret": "{Your Secret Here}"
}

Note that I've given it the rather long name here for illustrative purposes and to make it easier to read, but ultimately you can add as many keys as you want with whatever name you want. At build this will then automatically generate a Secrets class in your project's Helpers namespace. This will regenerate on each build, so any changes should be made to the JSON file and not the C# file. You should also add secrets.json and Secrets.cs to your .gitignore. If you're using my template packs, this is already done for you. 

I've gotten the question, what happens when I have some value that isn't a string? That's a fantastic question, and the Mobile.BuildTools has you covered there as well with support for string, int, double, and bool data types.

Protecting Your App Manifest

Sometimes secrets don't limit themselves to some constant value in our App. Sometimes we need to declare something sensitive in either our Info.plist or AndroidManifest.xml. This creates an issue for us as well. We obviously need to be able to test locally, but again we need to ensure we don't check these files in with those sensitive values. The Mobile.BuildTools again have your back. By adding these files to our .gitignore we keep from checking in sensitive values. In truth most of these manifests really aren't all that sensitive. To make it simple though we can simply check in a tokenized version of these manifests. Note that by default tokens should are delimited by double dollar signs before and after the variable name such as $$AppCenterSecret$$.

| - MyProject.sln
| - build/
| - | - AndroidTemplateManifest.xml
| - | - BuildTemplateInfo.plist

Sample BuildTemplateInfo.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDisplayName</key>
    <string>AppCenter.DemoApp</string>
    <key>CFBundleName</key>
    <string>AppCenter.DemoApp</string>
    <key>CFBundleIdentifier</key>
    <string>com.appcenter.demoapp</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>MinimumOSVersion</key>
    <string>8.0</string>
    <key>UIDeviceFamily</key>
    <array>
        <integer>1</integer>
        <integer>2</integer>
    </array>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>armv7</string>
    </array>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationPortraitUpsideDown</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>XSAppIconAssets</key>
    <string>Assets.xcassets/AppIcon.appiconset</string>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>appcenter-$$AppCenterSecret$$</string>
            </array>
        </dict>
    </array>
</dict>
</plist>

Setting Up AppCenter For Builds

Keep in mind here that our code now relies on a class called Secrets with several constants that exist nowhere in our codebase, and we have an iOS project without an Info.plist and an Android project without the AndroidManifest.xml... AppCenter offers us the ability to easily add Environment Variables. And this is where the build tools will be able to pick up what we need. 

The Mobile.BuildTools are highly configurable based on preferences, but by default a common project type such as PCL or .NET Standard library will look for any variables prefixed with Secret_, while platform targets look for this with their name like iOSSecret_ or DroidSecret_. Setting any of these in the build will generate a secrets.json and resulting Secrets class in the target project. I did of course say that we have a tokenized version of our manifests which have both the wrong name and tokens that need to be replaced. Just like with the secrets though the variables need to be prefixed, however the default prefix for this is simply Manifest_.  

Get Started

To get started install the Mobile.BuildTools into your project. These tools are free and open source, with documentation on additional configuration options that can be found on GitHub. If you have any issues or have a great idea that you would like to see added to the tools open an issue.

Want to see more? Be sure to check out the demo app.

Xamarin DevOps In A Box

Several Months ago I set out to make some of the most powerful Xamarin Project Templates. I've gotten a lot of feedback on the Prism QuickStart Templates and how they have accelerated Mobile Development for Developers. One of the features that has really caught the attention of so many developers is the Application Secrets generation. Mobile Apps so often have sensitive information such as Client Id's, or builds that require some minor changes such as pointing to one backend API for Development, another for Staging, and yet another for Production. The custom tasks that have been included in the QuickStart Templates have been helping developers for months to more easily handle these tasks.

Over time as I've made changes and improvements I've come to realize that it has left existing projects in a state where they have been unable to take advantage of changes. There has also been the fact that while they have been tied exclusively to the Prism QuickStart Templates though there is nothing about these great Build Tasks that are tied in any way to Prism. These wonderful Build Props and Build Targets have been separated out into an easy to install NuGet. Since this only contains build props and targets it adds nothing to the size of assemblies, but it does make your DevOps a whole lot easier.

Build Props

While many developers may not currently be utilizing many Build Props, the Mobile.BuildTools adds a number of properties that help you determine what type of project is building and on what type of Host. This could for example better assist you in developing Build tasks that only execute on Windows or Mac, determine if PowerShell is installed. You can also easily determine what platform the project is. We'll take a look at an example below.

Build Secrets

Modern apps are full of Client Id's, and Secrets that it can be maddening for Security. After all how do you develop an app that requires this type of sensitive information without compromising security by checking code into Source Control that contains our Id's and Secrets? Better yet how can we develop better CI/CD pipelines that are customized for an environment such as Development, Staging, or Production? This is where the Secrets Task shines. By simply including a file named secrets.json in your project root, the Secrets Task will generate a Secrets class for you. This enables you to ignore both the Secrets.cs and secrets.json files in your .gitignore. This frees your Build Server to generate your secrets.json and the rest is handled for you.

Templating Project Manifests

Sometimes our DevOps process requires having flexibility across our app manifests. While I am sure there are a multitude of reasons for why you might have this requirement the two most common use cases I see are:

  • I am developing an Application that must be tweaked for multiple customers and deployed to the App Store for each (i.e. a Banking App)
  • My application requires a setting in my manifest that exposes a Client ID or some other sensitive piece of information (i.e. I am using the Microsoft.Identity.Client for Azure Active Directory)

This is another area where the Mobile.BuildTools really shines by allowing you to include safe to check in Manifest Templates which will then be appropriately copied to your iOS or Android project. As I mentioned before this is just a sample of how the Build Props can better assist your DevOps. Each Copy task is restricted so that the AndroidManifest.xml is only copied when IsAndroidProject is true, and the Info.plist is only copied when IsiOSProject is true. 

FAQ

Q. What happens if I don't have a secrets.json included in my Project?
A. Nothing. The Task will safely execute, not having found a secrets.json file and will finish without creating anything.

Q. Can I name secrets.json something else?
A. Yes, it is a configurable Property. You can add JsonSecretsFileName to the PropertyGroup of your Project with the file name it should look for.

Q. Can you have secrets in more than one Project?
A. Yes, you can have secrets in as many projects as you want. Again the Task will only generate the Secrets class if you have a secrets.json present.

Q. The idea of a Tokenized Manifest sounds cool, but I don't need it. Can I still use the BuildTools?
A. Yes! As long as the AndroidManifest.xml or Info.plist is present when the Build is started it will not copy them over. Otherwise it would get really annoying during development to get some Tokenized manifest constantly undoing your changes.

Q. How do I find out more about setting up the Manifest Templates? Is is customizable?
A. You can find out more on GitHub. You can override the default variables to change the location of the templates, and even the Template Names. 

Q. Am I able to swap out the appxmanifest on UWP? 
A. UWP is not currently handled by default, however you can easily add support by adding ManifestDestinationPath and TemplateManifestPath to the PropertyGroup in your UWP Project.

Q. Does it work on with Visual Studio and Visual Studio for Mac?
A. Yes it work on both Mac and Windows. As part of migrating this out of the templates, the tasks have been upgraded to compiled tasks meaning it works with MSBuild without any additional requirement for PowerShell.

Getting Started

For existing QuickStart Template Projects, you will need to delete the Directory.build.props and Directory.build.targets. You can also delete the PowerShell scripts. To get started, simply install the Mobile.BuildTools NuGet into any project you need to generate App Secrets or an iOS/Android project that you want to be able to swap out the Manifest for. 

 

Prism for Xamarin Forms Preview 3

So much goes into developing a Xamarin Forms application, and Prism for Xamarin Forms is continuing to make your mobile development a little easier. Today we released Preview 3 for Prism 7, and a lot has happened since I published the Sneak Peak and the changes to Autofac.

 

Navigation

One of the big things developers love about Prism is Deep Linking like "NavigationPage/ViewA/ViewB/ViewC". Unfortunately this also exposes a bug in Xamarin Forms which the Xamarin team hasn't fixed. The result has been that the Title displayed in the NavigationPage is for ViewA rather than ViewC. Prism 7 has finally fixed this issue so that deep linking can still occur properly.

A long awaited feature is Relative Navigation. We see this all the time in web development, and beginning with preview 3 you can now simplify our Navigation like "../SomePage". This will both pop the current page and add SomePage to the Navigation Stack. Keep in mind that this feature will only work within the context of a NavigationPage. 

Another long await feature has been the ability to simply go back to the root. Prism's Navigation Service now includes a GoBackToRootAsync extension that will support this exact use case. 

TabbedPages

Prism 7 has a lot of fixes to make working with TabbedPages a joy. In past versions of Prism we've had to both explicitly set the ViewModelLocator.AutowireViewModel property on any pages that will be children of a TabbedPage, and we've had to create a TabbedPage that explicitly sets the tabs.

<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:local="clr-namespace:AwesomeApp.Views;assembly=AwesomeApp"
            x:Class="AwesomeApp.Views.MyTabbedPage">

    <local:ViewA />
    <local:ViewB />
    <local:ViewC />

</TabbedPage>

Beginning with Prism 7 you can now simply register the Xamarin Forms TabbedPage for Navigation and simply navigate like "TabbedPage?createTab=ViewA&createTab=ViewB&createTab=ViewC". But it doesn't stop there. There are times that we want to use a NavigationPage for a particular tab. We can now easily do this by adding the pipe character and navigating like: "TabbedPage?createTab=ViewA&createTab=NavigationPage|ViewB&createTab=ViewC". Best of all is that the NavigationService now better handles the children so that whether you have a traditional TabbedPage like above or one generated from the querytstring your pages will be automatically get the ViewModelLocator.AutowireViewModel set, and any Prism Behaviors will also automatically be set.

There has also been a major breaking change for selecting the active tab. In previous versions of Prism for Xamarin Forms you could set the active tab by adding the tab to select as the next Uri segment "MyTabbedPage/ViewB". This has been changed in preference of a querystring parameter like "TabbedPage?selectedTab=ViewB". Note that for those who are concerned about magic strings, we've got you covered as this is all based on the constants in KnownNavigationParameters. Putting this all together you can now navigate like:

_navigationService.NavigateAsync($"TabbedPage?{KnownNavigationParameters.CreateTab}=ViewA&{KnownNavigationParameters.CreateTab}=ViewB&{KnownNavigationParameters.CreateTab}=ViewC&{KnownNavigationParameters.SelectedTab}=ViewC");

Lifecycle

IActiveAware has been around Prism for some time but has only had limited support to handle when a page becomes the current page inside of a TabbedPage or CarouselPage. A new interface has been added to Prism.Forms called IPageLifecycleAware. This is handled through a Behavior added to every page by the NavigationService which will allow you to respond to the Appearing and Disappearing events.

Sticking with being Lifecycle aware, preview 3 has introduced a breaking change from earlier previews with IApplicationLifecycle to IApplicationLifecycleAware. While there hasn't been any actual changes to the way it works, it does better fit the naming conventions in Prism.

Modularity

Modularity has long been a core concept in Prism. Modularity has gotten a whole lot nicer in Prism 7 with a few fixes. To start with IModuleCatalog was fixed to properly return IModuleCatalog rather than ModuleCatalog when adding a Module. One of the problems with adding Modules in previous versions has been the verbosity that was required:

ModuleCatalog.AddModule(new ModuleInfo(nameof(SomeModule), typeof(SomeModule), InitializationMode.WhenAvailable));

This can now be simplified like:

// Basic Registration
ModuleCatalog.AddModule<SomeModule>();

There are of course some overloads to specify either the name or Initialization Mode. We have also added extensions to better determine whether a Module has been added to the ModuleCatalog and what the ModuleState is.

 

Xamarin Forms UI Development Made Easy with LiveXAML

I'm all about working with XAML in my Xamarin Forms apps. Developers coming from a WPF background have been used to some great tooling for visually styling their XAML for years. Xamarin Forms of course isn't so cut and dry for the obvious reason that we're dealing with an Abstraction of the UI. Chances are you've probably heard about Xamarin's Live Player. To be honest I think it's a cute idea, but really lacks what you need to be most productive. 

Naturally one of the biggest pains when working with XAML is getting the Styling just right. We do have more tools now at our disposal like the XAML Previewer in Visual Studio and Visual Studio Mac, but it lacks the touch and feel component of styling. This is where LiveXAML is making a huge difference in developing Xamarin Forms applications. LiveXAML not to be confused with Xamarin's Live Player, allows you to get the updates directly in your actual app. LiveXAML is truly one of the most amazing products I've ever worked with for XAML. 

It really is as simple as installing a single NuGet package and running the application in your Simulator or on your Device. Now you can actually see what your changes are doing, without rebuilding, in an app that is fully functional. There are no short cuts, no limitations like we see with the Live Player or the Previewer.

There are a number of challenges that are hard to handle without a data context behind them. One of them is handling a ListView with a DataTemplateSelector. It's certainly one thing to refine a single ViewCell, but when you have multiple cells that each need to be styled there is no substitute for having real working data which can only happen with your app actually running. This is one the many scenarios where using LiveXAML can really shine as you quickly update the styling and see the changes in your app. 

If you haven't had a chance to check it out head over to http://livexaml.com