Using "Unsupported" DI Containers with Prism

Developers around the world rely on Prism to build some pretty amazing apps. When I first saw Prism I was amazed at how quickly and easily I could develop an application with complex needs, but with easy to follow, testable, and maintainable code. As is so often the case, developers tend to have very strong opinions. Which Dependency Injection Container to use is certainly no exception. To some extent developers choices come from what they have experience with.

For a variety of reasons the Prism team cannot support every container that developers may want to use. Prism 7 however made some major changes that make it easier than ever to use a container that isn't officially supported or shipped by the Prism team. Prism imposes very few requirements in order to use a container.

  1. The container must support Transient and Singleton registrations
  2. The container must support registering a specified instance
  3. The container must support keyed registrations / resolving by name
  4. The container must be mutable to support Prism Modularity

In the past when implementing support for your own container, you would still need a fair amount of knowledge of the container, and how Prism is supposed to work. Because of the container abstraction, this requirement has been reduced to only needing to understand the container you want to use.

Amazingly you can introduce support for your container by overriding one additional method from PrismApplicationBase in either Prism.Forms or Prism.WPF, and implementing a single class that handles the mapping between Prism's container abstraction and the container you want to use.

There are some extremely performant containers available such as Grace. As it turns out Grace is a fantastic example as it is virtually on par or slightly more performant than my favorite DryIoc. It's also a mature codebase with releases going back to 2013. It meets all of our "Must Support" items, and it's mutable so it even works with Prism Modularity. Unfortunately for Grace, over it's 5 year history, it has only accumulated around 76,000 downloads. Due to this low user adoption, no matter how performant it may be, it isn't a popular enough container to justify adding to Prism as a supported container.

Adding a Container Extension

Prism 7's IOC Abstraction simply provides a mapping for the most common Registration and Resolution methods. In the case of the Grace DI Container we simply need to add this single class:

public class GraceContainerExtension : IContainerExtension<IInjectionScope>
{
    public GraceContainerExtension()
        : this(new DependencyInjectionContainer())
    {
    }

    public GraceContainerExtension(IInjectionScope injectionScope)
    {
        Instance = injectionScope;
    }

    public IInjectionScope Instance { get; }

    public bool SupportsModules => true;

    public void FinalizeExtension() { }

    public void Register(Type from, Type to) =>
        Instance.Configure(c => c.Export(to).As(from));

    public void Register(Type from, Type to, string name) =>
        Instance.Configure(c => c.Export(to).AsKeyed(from, name));

    public void RegisterInstance(Type type, object instance) =>
        Instance.Configure(c => c.ExportInstance(instance).As(type));

    public void RegisterSingleton(Type from, Type to) =>
        Instance.Configure(c => c.Export(to).As(from).Lifestyle.Singleton());

    public object Resolve(Type type) =>
        Instance.Locate(type);

    public object Resolve(Type type, string name) =>
        Instance.Locate(type, withKey: name);

    public object ResolveViewModelForView(object view, Type viewModelType)
    {
        Page page = null;

        switch(view)
        {
            case Page viewAsPage:
                page = viewAsPage;
                break;
            case BindableObject bindable:
                page = bindable.GetValue(ViewModelLocator.AutowirePartialViewProperty) as Page;
                break;
            default:
                return Instance.Locate(viewModelType);
        }

        var navService = Instance.Locate<INavigationService>(withKey: PrismApplicationBase.NavigationServiceName);
        ((IPageAware)navService).Page = page;
        return Instance.Locate(viewModelType, new[] { navService });
    }
}

Once we've added this single class we only need to add to update our App as follows:

public partial class App : PrismApplicationBase
{
    protected override IContainerExtension CreateContainerExtension() =>
        new GraceContainerExtension();
}

As I mentioned, Prism's IOC abstraction only provides the most common functionality. This means that you could find an advanced scenario where you need direct access to the underlying container. To achieve a more complex registration, you can add an extension method like we provide in the Container specific packages:

public static class ContainerExtensions
{
    public static IInjectionScope GetContainer(this IContainerRegistry containerRegistry) =>
        ((IContainerExtension<IInjectionScope>)containerRegistry).Instance;
}

You can find a full working sample app on GitHub.

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>

 

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.

 

Prism Template Pack in Visual Studio for Mac

Prism users have long enjoyed some great Template packs available for Visual Studio and Xamarin Studio. Visual Studio for Mac though has been a real challenge due to problems with the Mono Addins site not building the Prism Addin. It's been a very common request among our Mac users to get this support back.

Since we have been unable to rely on the Mono Addins site, we have decided to simply host our own feed for Prism Users. This new feed will allow you to add and update the Prism Template Pack in Visual Studio for Mac.

So how do you get the Template Pack? Well for starters you will need to add the Prism feed to your Extensions Repositories. Once you have it added, simply refresh the Gallery. You can either use the search bar or expand IDE extensions to find the Prism Template Pack.

Keep in mind that the new Prism Template Pack for Visual Studio for Mac now includes a DryIoc Project template in addition to the Unity Template. Both project templates will create project with the latest stable versions of Prism and Xamarin Forms.

Breaking Changes for Prism Autofac Users

History

It's certainly been no secret that I've told user's that Autofac wasn't really a good choice for Prism Forms. To be honest just looking at the benchmarks between Autofac and DryIoc or SimpleInjector which may soon be supported, Autofac just isn't that appealing to me. The truth though, is that I wasn't just steering people away from Prism Autofac for this reason alone.

Before Prism introduced .NET Standard support, we were limited to targeting Autofac 3.5. As anyone familiar with Autofac is likely aware, the ContainerBuilder.Update(Container) method was deprecated. Autofac quite annoyingly wants to be an immutable container. This is problematic for frameworks like Prism, or any developer who wants to dynamically load dependencies (more on this later). Also part of the problem was that Autofac is a bit unique in the way that it handles registering and resolving. Most containers are responsible for registering dependencies, telling you if something is registered, and resolving that dependency, but Autofac wants to be different with a ContainerBuilder that is used for registering, a central IContainer that knows nothing about itself, but is happy to resolve IComponentContext if you need to inject something into a class to resolve dependencies in a factory method like the one used by the NavigationService to resolve your Views... 

Major Breaking Changes

Prism Forms is architected for a Container that knows how to do stuff, continuing to have the Autofac PrismApplication derive from PrismApplicationBase<IContainer> was a poor choice. To help fix the way Autofac works with Prism Forms this was updated to PrismApplicationBase<ContainerBuilder>. That alone though would provide for a poor experience so this was updated to ensure that the Container property is still the IContainer that is set when the builder is built, and a Builder property was added to give you direct access to the ContainerBuilder being used in PrismApplication to register all of the Prism services. Unlike the builder previously used by PrismApplication, this builder waits to call Builder.Build() until after it registers the base Prism services, anything in your RegisterTypes() and anything in your IPlatformInitializer.

To make this work though, we also had to break all of your View Registrations. The extension methods that we typically include in Prism Forms are based on the Container for registrations. But this never made sense for Autofac, leading to extension methods that would create a builder, and then update the Container. To better align with the intent of how Autofac is meant to work the methods were updated to be based on the ContainerBuilder.

public class App : PrismApplication
{
    protected override void RegisterTypes()
    {
        Builder.RegisterType<Foo>().As<IFoo>();
        Builder.RegisterTypeForNavigation<ViewA>();
    }
}

public class iOSInitializer : IPlatformInitializer
{
    public void RegisterTypes(ContainerBuilder builder)
    {
         builder.RegisterType<SpeakImp>().As<ISpeak>();
    }
}

Modularity

Modularity hasn't been huge in the Prism Forms community like it is in the WPF community. For developers who are familiar with it, Modules are often a major part of their app development. Unfortunately Autofac's desire to be immutable poses some major problems for Modularity with Prism. Prism relies on container mutability for Modules. Part of this is that we must resolve the ModuleCatalog before we run it and initialize any of the Modules. The other part is that Prism allows us to load Modules on demand. This could for instance allow us to ship an application like Lyft and only load the Driver Module if the user is a Driver. Since Autofac is immutable this creates a major problem for us, and OnDemand Modules are out of the question due to the limitations imposed on us by the container. As such the recommended guidance for Autofac users will be to architect modules as follows:

public class AwesomeModule : IModule
{
    public void Initialize() { }

    public static void Initialize(ContainerBuilder builder)
    {
        builder.RegisterType<FooService>().As<IFooService>();
        builder.RegisterTypeForNavigation<ViewA>();
    }
}

public class App : PrismApplication
{
    protected override void RegisterTypes()
    {
        // Initialization must be done before the Container is built.
        AwesomeModule.Initialize(Builder);
    }

    protected override void ConfigureModuleCatalog()
    {
        // Not actually needed for Autofac since all registrations must be done
        // before we build the container.
    }
}

Getting Started

These changes are all available starting with Prism 7.0.0.30-ci in the Prism MyGet feed. If you have not already done so, you can add that feed in either Visual Studio or Visual Studio for Mac and update your existing Prism Application's to the latest CI build. 

If you are starting with a new Project you will want to check out the updated QuickStart Templates which now includes the only Module project template, and full support for the updated Autofac implementation.

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.