.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="Microsoft.NET.Sdk" 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>
  <ItemGroup>
    <PackageReference Include="MSBuild.Sdk.Extras" Version="1.2.2" PrivateAssets="All" />
  </ItemGroup>
  <ItemGroup Condition=" $(TargetFramework.StartsWith('uap10.0')) ">
    <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.0.6" />
    <SDKReference Include="WindowsMobile, Version=10.0.16299.0">
      <Name>Windows Mobile Extensions for the UWP</Name>
    </SDKReference>
  </ItemGroup>
  <Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />
</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 7.0 for Xamarin Forms Sneak Peek

Prism 7.0 Sneak Peek

If you're a Xamarin developer, chances are you've been through a struggle or two with NetStandard. NetStandard offers a lot of advantages, but support has been slow going in many cases. Xamarin Forms only recently began shipping NetStandard. Prism users have been asking for a while now to have NetStandard support. Obviously for WPF users NetStandard really doesn't offer any advantages, and for UWP it just creates a few headaches, but that hasn't stopped requests for the Core to support NetStandard or for Prism Forms to be converted. For a while now I've been either pointing people to my preview templates or telling them to use the PackageTargetFallback attribute with the new csproj format. Well, I'm happy to say that Prism for Xamarin Forms is now available in NetStandard!

While NetStandard support is fantastic, I probably wouldn't take the time to write a post just about that. One of the problems we all face is when we run into an issue with a library in our code base, and the issue is fixed on GitHub. The problem is that it may be days, weeks, even months before it is available. So suddenly you have to uninstall the NuGet packages, add the open source library as a git submodule. As Prism moves into the 7.0 update, I'm also very happy to announce the official Prism MyGet feed that is tied into the builds so when new features are added you can immediately expect a new CI package available on MyGet so you can immediately start using the features you need without having to wait for an official release. 

https://www.myget.org/F/prism/api/v3/index.json

Whats New Since 6.3

You may be thinking that NetStandard is great and all but that isn't really new. As part of Prism updating to Xamarin Forms 2.3.5, you will now have full support for working with Prism on macOS applications. 

Another change you can look for starting now in the 7.0 addresses the overhauled OnPlatform starting in Xamarin Forms 2.3.4. Unfortunately the new Xamarin API for OnPlatform uses magic strings, and is cumbersome to say the least if you're working with it from C# code and not in XAML. Prism has updated the IDeviceService and provided a new RuntimePlatform enum. We have also updated Platform dependent View Registrations to use this new RuntimePlatform enum. This will ultimately be a lot cleaner than the previous type based registrations.

Container.RegisterTypeForNavigationOnPlatform<MainPage, MainPageViewModel>("Main",
     new Platform<MainPage_Android>(RuntimePlatform.Android),
     new Platform<MainPage_iOS>(RuntimePlatform.iOS));

Following the deprecation of the previous OnPlatform functions within the Xamarin Forms Device class, we have updated IDevice to deprecate this feature as well and added access both the Xamarin Forms Platform string and our RuntimePlatform enum.

I have been a huge advocate for directly binding to your model's properties. It really saves a lot of headaches with validation and ensuring that changes made on the view update your model to be persisted to your data store. That said even with Prism's DelegateCommand.ObservesProperty, this has been a shortcoming. Thanks to a community contribution this will now be possible in Prism 7.0

ObservesProperty(() => Property.NestedProperty.NestedPoperty)

Another major improvement addresses exceptions thrown during navigation. Prism Forms will now properly log and re-throw exceptions that are thrown when you're navigating. This has been a major pain point in the past where the exceptions were effectively swallowed by the NavigationService and you had no idea what threw an exception or even what the exception was. Many times you might have simply found yourself getting an exception thrown because your MainPage was null and the platform excepted something. 

There have also been a number of reported Navigation Bugs fixed in Prism 7.

Prism for UWP Developers

If you're developing UWP applications with Prism there are a couple of gotcha's that you'll need to know about. 

Starting in Prism 7.0 we've decided to split all of the Platforms/Containers into separate packages. We've done this so that we can rev the platforms separately from one another, and if we update an issue with Prism.Autofac.Wpf, Prism.Autofac.Windows user's won't see a package update and think that something changed. This only affects UWP developers who are using Prism for UWP. You simply need to uninstall the Prism.{Container} package and install the Prism.{Container}.Windows package. (note that this update is not yet available but will be soon)

Whether you're using Prism for UWP or Prism for Xamarin Forms, note that there is a bug with the .NET SDK that will affect you if Prism 7 is the first NetStandard package that you are using. It is easily overcome by adding the file Directory.Build.props next to your solution file, with the following contents:

<?xml version="1.0" encoding="utf-8"?>
<Project>
  <!-- Workaround for https://github.com/dotnet/sdk/pull/908 -->
  <Target Name="GetPackagingOutputs" />
</Project>

Note that if you are developing a UWP application with the Prism QuickStart Template for Xamarin Forms, this has already been added for you.

Whats Coming

As amazing as NetStandard is to finally have behind us, I'm still even more excited by what's coming in 7.0. I wouldn't call this an exhaustive list, but here are some highlights of some features to keep an eye out for in Prism 7:

  • Querystring navigation is one of the most amazing things about the Prism Navigation Service, and it's about time that you should be able to dynamically create tabs or use modal navigation through the querystring.
  • Removal of support for the Xamarin Forms DependencyService. This really leads to some bad practices, and with IPlatformInitializer there is simply no need to rely on the Dependency Service for Platform specific types.
  • An ability to use MVVM and the ViewModelLocator with custom Views as well as Xamarin Forms Pages.

 

Azure Mobile Client Helpers

To be honest, I forget now exactly when I first heard about the Azure Mobile Client library. I do however remember an initial sense of excitement for being able to add Online/Offline syncing to my apps. That excitement gradually faded a little when I started to deep dive into the library and realized that every project I wanted to use the Azure Mobile Client, meant that there were a number of helpers I would need to recreate. If you're familiar with the Azure Mobile Client, the chances are you may have seen tutorial either by or inspired by Adrian Hall's guide. Even Xamarin's "Connect App" template uses this basic approach. Honestly I don't mind providing an implementation for an interface or two in my projects, but it gets a little old when I have to redevelop everything in my projects.

It was for this reason that I decided to wrap the abstractions and some basic implementations into a reusable library. The AzureMobileClient.Helpers library wraps what you need to quickly get off the ground running with the AzureMobileClient. But it's really about more than simply providing the base classes you need to be successful. It's also about helping you to develop the code that follows best practices, and helps keep your code testable. 

So what does getting started even look like? Well let's say we have the classic TodoItem.

public class TodoItem : EntityData
{
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }
}

We don't need to define any of the fields specific to our Azure Mobile Services Entity as it's already defined in the EntityData base class. Since I'm all about Developer Experiences, and trying to make things to where we have to write as little code as possible to have a fantastic app, I'll use Mobile Center to quickly setup a Mobile Backend. 

Create an Easy Table

Navigate to the Tables tab and create your first table. Note that when you first go to the Tables tab you'll be asked to link the app to your Azure account. The Mobile Center will automatically go out and provision a new Mobile App Service and setup everything in a Resource Group for your app. You should be aware that you can go into the Azure Portal at any time to manage the resource. When Mobile Center sets everything up it will use a SQLite database which is great for testing, and not so great for Production. If you want to set this up to be more than a demo, before you create your first table go into the Azure Portal and configure either a SQL Server connection or Storage connection under Mobile -> Data Connections. For this example we're not going to set up any authentication, but you can do this easily from Mobile Center. The great thing about Easy Tables is that the data store allows for a dynamic schema so all we need to provide for this is a table name and click Create.

Set the table name

Really with very little effort and Zero code on your part, your mobile backend is ready. Notice I said it's 'Zero code on your part', and not 'Zero code'. Behind the scenes it is setting up a Node.js backend adding the files you need. You can go into the App Service Editor at any time and make manual changes if you need to. All you need to do now is setup your Xamarin application. Keeping things simple let's set up the application using Prism with a NetStandard1.4 Core library so that we can use the latest NetStandard release of the Azure Mobile Client and the Helpers library I mentioned before.

Now in order to keep things a little easier I want to keep a singular app context that I can use so I can easily scale from 1:N models without having to update the dependencies I'm injecting into my ViewModels. To do this I'm going to reference the Container specific implementation for the library so I can more easily set this up. For this we'll use the DryIocCloudAppContext and provide our Tables very much like we would using Entity Framework and the DbContext.

public class AwesomeAppContext : DryIocCloudAppContext
{
    public AwesomeAppContext(IContainer container)
        : base(container, AppSettings.DbName)
    {
    }

    // NOTE: This must be here for the AppContext to pick up your Model Type
    // and ensure that the table is created in the SQLite store
    ICloudSyncTable<TodoItem> TodoItems => SyncTable<TodoItem>();
}

Now, we just need to register our services:

protected override void RegisterTypes()
{
    Container.Register(typeof(ICloudSyncTable<>), typeof(AzureCloudSyncTable<>), reuse: Reuse.Singleton);
    Container.RegisterInstance<IMobileServiceClient>(new MobileServiceClient(AppSettings.BackendUri));
    Container.Register<AwesomeAppContext>(Reuse.Singleton);

    Container.RegisterTypeForNavigation<NavigationPage>();
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterTypeForNavigation<TodoItemDetailPage>();
}

With our services we're all set. We just need to add AwesomeAppContext to the constructor of our ViewModel and we can access our data. 

public class MainPageViewModel : BaseViewModel, INavigatedAware
{
    private AwesomeAppContext _context { get; }

    public MainPageViewModel(AwesomeAppContext context)
    {
        _context = context;
        TodoItems = new ObservableRangeCollection<TodoItem>();
    }

    public ObservableRangeCollection<TodoItem> TodoItems { get; }

    public async void OnNavigatedTo(NavigationParameters parameters)
    {
        await _context.TodoItems.SyncAsync();
        TodoItems.ReplaceRange(await _context.TodoItems.ReadAllItemsAsync());
    }
}

Finally we can go from idea to working app in under 10 minutes with full Online/Offline Sync. You can see the full working TodoDemo app on GitHub.

Xamarin Package Authoring

Whether you're just a .NET developer or a Xamarin developer we've all used NuGet. Chances are if you're anything like me, you may have started down the development path on some project and developed out some really awesome tools to help you. Then maybe you were in a fancy design meeting. Maybe you were busy thinking how Rome didn't become a great Empire by having meetings... 

Rome didn't have meetings

Perhaps you're more like me and you were either at Starbucks or on your way to Starbucks, and a great idea struck. Then you realized that all of the functionality you need you just implemented on this other project. Obviously the answer is to decouple the code you wrote from your last project and put it into it's own project. The problem you ran into though is that you develop on a Mac and NuGet is for PC right?

Now I could go into authoring packages with the new csproj format using dotnet pack. But truthfully that is a topic all by itself. It's actually something that many developers may not realize you can do. I mean if you go to NuGet.org all you can find is the download for the Windows exe. What people may not realize though is that it's much easier to start authoring packages using the Xamarin toolset than you may realize.

When you installed Xamarin Studio or the newly released Visual Studio for Mac along with the IDE and tooling for Android & iOS development, you actually got Mono. Now if you go to Google and search for Mono because you have no clue what I'm talking about, don't worry, we're not talking about the infectious disease. If you go down under WebMD to the Mono Project you'll see what we're talking about. Bundled in Mono is NuGet and even better the executable is already added to your path so once you open the terminal you can just execute NuGet commands. Now there is one caveat, and it is an important one. Mono for some unknown reason refuses to update the bundled version from 2.12 so you're good if you want to query a NuGet feed or pull a package, but that's pretty much it. Fear not though, you just need to run sudo nuget update -self, and it will update to the latest version the same as if you ran it on Windows. 

There are of course some gotcha's here:

  1. If you're building platform specific code that includes the full net framework like net45 you're going to have to build the source on Windows. That said if you built it on your PC but maybe had the project in your DropBox then you can pack the Windows built binary on the Mac
  2. Xamarin Studio/Visual Studio for Mac updates. The updates typically include an Update for Mono which will reset your NuGet version back to 2.12 unless they ever decide to update the bundled version so after running updates on the IDE you will need to update NuGet before packing your projects.