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

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

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

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

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

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

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

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

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

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

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

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

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

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

image

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

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

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

LogHelper.Log(“test”);

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

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

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

image

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

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

image

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

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

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

image

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

Building Cross Platform Applications with Visual Studio 2017

Building Cross Platform Applications with Visual Studio 2017

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

Visual Studio 2017 is still in RC

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

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

image

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

image

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

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