## Create and pack reference assemblies (made easy)

July 9, 2018 Coding 2 comments , , , ,

# Create and pack reference assemblies (made easy)

Last week I blogged about reference assemblies, and how to create them. Since then, I’ve incorporated everything into my MSBuild.Sdk.Extras package to make it much easier. Please read the previous post to get an idea of the scenarios.

Using the Extras, most of that is eliminated. Instead, what you need is the following:

1. A project for your reference assemblies. This project specifies the TargetFrameworks you wish to produce. Note: this project no longer has any special naming or directory conventions. Place it anywhere and call it anything.
2. A pointer (ReferenceAssemblyProjectReference) from your main project to the reference assembly project.
3. Both projects need to be using the Extras. Add a global.json to specify the Extras version (must be 1.6.30-preview or later):
{
"msbuild-sdks": {
"MSBuild.Sdk.Extras": "1.6.30-preview"
}
}


And at the top of your project files, change Sdk="Microsoft.NET.Sdk" to Sdk="MSBuild.Sdk.Extras"

4. In your reference assembly project, use a wildcard to include the source files you need, something like: <Compile Include="..\..\System.Interactive\**\*.cs" Exclude="..\..\System.Interactive\obj\**" />.
5. In your main project, point to your reference assembly by adding an ItemGroup with an ReferenceAssemblyProjectReference item like this:

<ItemGroup>
<ReferenceAssemblyProjectReference Include="..\refs\System.Interactive.Ref\System.Interactive.Ref.csproj" />
</ItemGroup>


In this case, I am using System.Interactive.Ref as the project name so I can tell them apart in my editor.

6. That’s it. Build/pack your main project normally and it’ll restore/build the reference assembly project automatically.

## Notes

• The tooling will pass AssemblyName, AssemblyVersion, FileVersion, InformationalVersion, GenerateDocumentationFile, NeutralLanguage, and strong naming properties into the reference assembly based on the main project, so you don’t need to set them twice.
• The REFERENCE_ASSEMBLY symbol is defined for reference assemblies, so you can do ifdef‘s on that.
• Please see System.Interactive as a working example.

## Create and Pack Reference Assemblies

July 3, 2018 Coding 3 comments , , , ,

Update July 9: Read the follow-up post for an easier way to implement.

# Create and Pack Reference Assemblies

Reference Assemblies, what are they, why do I need that? Reference Assemblies are a special kind of assembly that’s passed to the compiler as a reference. They do not contain any implementation and are not valid for normal assembly loading (you’ll get an exception if you try outside of a reflection-only load context).

## Why do you need a reference assembly?

There’s two main reasons you’d use a reference assembly:

1. Bait and switch assemblies. If your assembly can only have platform-specific implementations (think of a GPS implementation library), and you want portable code to reference it, you can define your common surface area in a reference assembly and provide implementations for each platform you support.

2. Selectively altering the public surface area due to moving types between assemblies. I recently hit this with System.Interactive (Ix). Ix provides extension methods under the System.Linq namespace. Two of those methods, TakeLast, and SkipLast were added to .NET Core 2.0’s Enumerable type. This meant that if you referenced Ix in a .NET Core 2.0 project, you could not use either of those as an extension method. If you tried, you’d get an error:

error CS0121: The call is ambiguous between the following methods or properties: 'System.Linq.EnumerableEx.SkipLast(System.Collections.Generic.IEnumerable, int)' and 'System.Linq.Enumerable.SkipLast(Sy stem.Collections.Generic.IEnumerable, int)'.

The only way out of this is to explicitly call the method like EnumerableEx.SkipLast(...). Not a great experience. However, we cannot simply remove those overloads from the .NET Core version since:

• It’s not in .NET Standard or .NET Framework
• If you use TakeLast from a .NET Standard library, then are running on .NET Core, you’d get a MissingMethodException.

The method needs to be in the runtime version, but we need to hide it from the compiler. Fortunately, we can do this with a reference assembly. We can exclude the duplicate methods from the reference on platforms where it’s built-in, so those get resolved to the built-in Enumerable type, and for other platforms, they get the implementation from EnumerableEx.

## Creating reference assemblies

I’m going to explore how I solved this for Ix, but the same concepts apply for the first scenario. I’m assuming you have a multi-targeted project containing your code. For Ix, it’s here.

It’s easiest to think of a reference assembly as a different project, with the same name, as your main project. I put mine in a refs directory, which enables some conventions that I’ll come back to shortly.

The key to these projects is that the directory/project name match, so it creates the same assembly identity. If you’re doing any custom versioning, be sure it applies to these as well.

There’s a couple things to note:

• In the project file itself, we’ll include all of the original files




• The TargetFrameworks should be for what you want as reference assemblies. These do not have to match that you have an implementation for. For scenario #1 above, you’ll likely only have a single netstandard2.0 target. For scenario #2, Ix, given that the surface area has to be reduced on specific platforms, it has more.
• There is a Directory.Build.props file that provides common properties and an extra set of targets these reference assembly projects need. (Ignore the bit with NETStandardMaximumVersion, that’s me cheating a bit for the future ?)

In that props, it defines REF_ASSM as an extra symbol, and sets ProduceReferenceAssembly to true so the compiler generates a reference assembly.

The other key thing in there is a target we’ll need to gather the reference assemblies from the main project during packing.





With these, you can use something like #ifdef !(REF_ASSM && NETCOREAPP2.0) in your code to exclude certain methods from the reference assembly on specific platforms. Or, for the "bait and switch" scenario, you may choose to throw an NotImplementedException in some methods (don’t worry, the reference assembly strips out all implementation, but it still has to compile).

You should be able to build these reference assemblies, and in the output directory, you’ll see a ref subdirectory (in \bin\$(Configuration)\$(TargetFramework)\ref). If you open the assembly in a decompiler, you should see an assembly level: attribute [assembly: ReferenceAssembly]. If you inspect the methods, you’ll notice they’re all empty.

## Packing the reference assembly

In order to use the reference assembly, and NuGet/MBuild do its magic, it must be packaged correctly. This means the reference assembly has to go into the ref/TFM directory. The library continues to go into lib/TFM, as usual. The goal is to create a package with a structure similar to this:

The contents of the ref folder may not exactly match the lib, and that’s okay. NuGet evaluates each independently for the intended purpose. For finding the assembly to pass as a reference to the compiler, it looks for the "best" target in ref. For runtime, it only looks in lib. That means it’s possible you’ll get a restore error if you try to use the package in an application without a supporting lib.

Out-of-the-box, dotnet pack gives us the lib portion. Adding a Directory.Build.targets above your main libraries gives us a place to inject some code into the NuGet pack pipeline:

<Target Name="GetRefsForPackage" BeforeTargets="_GetPackageFiles"
Condition=" Exists('$(MSBuildThisFileDirectory)refs\$(MSBuildProjectName)\$(MSBuildProjectName).csproj') "> <MSBuild Projects="$(MSBuildThisFileDirectory)refs\$(MSBuildProjectName)\$(MSBuildProjectName).csproj"
Targets="_GetTargetFrameworksOutput">

ItemName="_RefTargetFrameworks" />
</MSBuild>

<MSBuild Projects="$(MSBuildThisFileDirectory)refs\$(MSBuildProjectName)\$(MSBuildProjectName).csproj" Targets="_GetReferenceAssemblies" Properties="TargetFramework=%(_RefTargetFrameworks.Identity)"> <Output TaskParameter="TargetOutputs" ItemName="_refAssms" /> </MSBuild> <ItemGroup> <None Include="@(_refAssms)" PackagePath="ref/%(_refAssms.TargetFramework)" Pack="true" /> </ItemGroup> </Target> This target gets called during the NuGet pack pipeline and calls into the reference assembly project using a convention: $(MSBuildThisFileDirectory)refs\$(MSBuildProjectName)\$(MSBuildProjectName).csproj. It looks for a matching project in a refs directory. If it finds it, it obtains the TargetFrameworks it has and then gets the reference assembly for each one. It calls the _GetReferenceAssemblies that we had in the Directory.Build.props in the refs directory (thus applying it to all reference assembly projects).

## Building

This will all build and pack normally using dotnet pack, with one caveat. Because there’s no ProjectReference between the main project and the reference assembly projects, we need to build the reference assembly projects first. You can do that with dotnet build. Then, call dotnet pack on your regular project and it’ll put it all together.

## Use all TFM’s with SDK-style projects in Visual Studio for Mac

August 29, 2017 Coding 4 comments , , ,

# Use all TFM’s with SDK-style projects in Visual Studio for Mac

## TL;DR

You can now use SDK-style projects, with all supported TFM’s, in Visual Studio for Mac. See getting started for details.

## Issue

While Visual Studio for Mac supports the SDK-style projects, there have been a couple of issues blocking use of TFM’s other than net, netstandard, and netcoreapp.

1. Those TFM’s are hard-coded and an SDK-style project containing any other target frameworks is blocked.
2. Xamarin on the Mac has a multi-valued MSBuildExtensionsPath property. That means that it can search for targets in different locations. Unfortunately the logic this works with is limited to the <Import /> element, so if you set properties, as is required to use LanguageTargets, it won’t work. Fortunately, with some brainstorming with Ankit Jain and Mikayla Hutchinson, we found a solution.

## Getting Started

You’ll need a few things:

1. Latest stable channel of Visual Studio for Mac
2. .NET Core 2 SDK (even if you’re not targeting .NET Standard 2 or .NET Core, the SDK style projects use these targets). Download here.
3. Matt Ward‘s Extension to VSfM that removes TFM checks on SDK-style projects. Binary | Source. Install by going to Visual Studio -> Extensions... -> Install from file...

Then, create a new SDK-style project and use the latest version of the MSBuild.Sdk.Extras package, at least version 1.1.0-beta.69:

<PackageReference Include="MSBuild.Sdk.Extras" Version="1.1.0-beta.69" PrivateAssets="all" />


At the end of the project file, just before the closing tag, you’ll also need the following, as per the MSBuild SDK Extras readme:

<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />


Here’s a complete example of using the SDK-style projects with an iOS class library:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>xamarinios10</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MSBuild.Sdk.Extras" Version="1.1.0-beta.69" PrivateAssets="all" />
</ItemGroup>

<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />
</Project>


## Building these projects

These projects will build in the IDE (VSfM, VS, etc) or the command line. If you use the command line, you must use msbuild, not dotnet build. Keep in mind that with msbuild, you must explicitly call restore first, so your build steps will look like this:

msbuild /t:restore
msbuild /p:Configuration=Release


### Notes

For the beta, since it’s a SemVer2 package, you must be using the NuGet v3 feed. If your VSfM prefs have https://www.nuget.org/api/v2/, you need to update that to be https://api.nuget.org/v3/index.json.

## Support

If you run into issues, please file a bug on the MSBuild SDK Extras project site: https://github.com/onovotny/MSBuildSdkExtras/issues and reach
me @onovotny.

## Using Xamarin Forms with .NET Standard – VS 2017 Edition

April 23, 2017 Coding 39 comments , , ,

# Using Xamarin Forms with .NET Standard – VS 2017 Edition

I have previously blogged about using .NET Standard with Xamarin Forms. Since then, the tooling has changed significantly with Visual Studio 2017 and Visual Studio for Mac. This post will show you what you need to use Xamarin.Forms with a .NET Standard class library.

Why use a .NET Standard class library instead of a PCL? There are many good reasons, but the two biggest ones are:

• Much bigger surface area. PCL’s were the least common denominator intersection of supported platforms. The end result is that while the binary worked on many platforms, there were a much more limited set of APIs available. .NET Standard 1.4 is the version that supports UWP, Xamarin Android, Xamarin iOS, and Xamarin.Mac.
• “SDK Style” project file goodness. Legacy PCL’s use the old csproj format which have tons of gunk in them. While it is possible to use the new project style to generate legacy PCLs (if you use my MSBuild.Sdk.Extras package), it’s time to move past those. If you target .NET Standard 1.0-1.2, some PCL profiles can install your library. See the full table for the list.

## Prerequisites

Using .NET Standard requires you to use PackageReference to eliminate the pain of “lots of packages” as well as properly handle transitive dependencies. While you may be able to use .NET Standard without PackageReference, I wouldn’t recommend it.

You’ll need to use one of the following tools:

## Getting Started

As of now, the project templates for creating a new Xamarin Forms project start with an older-style packages.config template, so whether you create a new project or have an existing project, the steps will be pretty much the same.

Step 1: Convert your projects to use PackageReference. The NuGet blog has details on using PackageReference with all project types. Unfortunately there’s no current migration tool, so it’s probably easiest to uninstall your existing packages, make sure the packages.config file is gone and then install the package after setting the VS Options to PackageReference. You can also do it by hand (which is what I did for my projects).

Step 2: As part of this, you can remove dependencies from your “head” projects that are referenced by your other projects you reference. This should simplify things dramatically for most projects. In the future, when you want to update to the next Xamarin Forms version, you can update it in one place, not 3-4 places. It also means, you only need the main Xamarin.Forms package, not each of the packages it pulls in.

For now, you’ll need to add the <RestoreProjectStyle>PackageReference</RestoreProjectStyle> property near the top of your iOS and Android csproj files. That tells NuGet restore to use the PackageReference mode even if you don’t have any direct packages (this is important for transitive restore). If you have any PackageReference elements in your iOS or Android csproj, then you don’t need this. For UWP, you already should have a PackageReference to the UWP meta-package (Microsoft.NETCore.UniversalWindowsPlatform version 5.3.2).

If you hit any issues with binaries not showing up in your bin directories (for your Android and iOS “head” projects), make sure that you have set CopyNuGetImplementations to true in your csproj.

At this point, your project should be compiling and working, but not yet using netstandard1.x anywhere.

Step 3: Move your PCL library to .NET Standard. This is the hard part today as there’s no tooling to automatically do this correctly. Be warned and DO NOT use this option in the PCL properties. It is broken and will create a project.json based library targeting dotnet. I hope this option is removed in a future VS Update! Instead, go to File -> New Project -> .NET Standard -> Class Library and create a new class library. If this is a new project, I’d simply delete the existing PCL and just use a new one. If it’s an existing project, you’ll want to migrate. The new format is far simpler and moving the PCL by hand is usually pretty easy. What I’ve usually done is this:

1. Close the solution in VS
2. Take the existing csproj and make a copy of it somewhere else. I’ll keep this other copy open in Notepad.
3. Copy/paste the contents of the new project you created and replace the contents of your existing project. Most of what you had in the old project isn’t really needed anymore. What you’ll likely need are settings like any signing or assembly names that don’t match the folder name/conventions. If you have ResX files with design-time generated code, you’ll need to add the following. Likewise, for Xamarin Forms pages, you’ll need this.
4. Decide which .NET Standard version to target, probably 1.4, based on the table. Here’s a cheat sheet:
• If you only want to support iOS and Android, you can use .NET Standard 1.6. In practicality though, most features are currently available at .NET Standard 1.3 and up.
• If you want to support iOS, Android and UWP, then NET Standard 1.4 is the highest you can use.
• If you want to support Windows Phone App 8.1 and Windows 8.1, then NET Standard 1.2 is your target.
• If you’re still supporting Windows 8, .NET Standard 1.1 is for you.
• Finally, if you need to support Windows Phone 8 Silverlight, then .NET Standard 1.0 is your only option.

Once you determine the netstandard version you want, in your csproj, set the TargetFramework to it — netstandard1.4, etc.

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<PackageTargetFallback>portable-net45+win8+wpa81+wp8</PackageTargetFallback>
<DebugType>full</DebugType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Xamarin.Forms" Version="2.3.4.231" />
</ItemGroup>

<ItemGroup>
<!-- https://bugzilla.xamarin.com/show_bug.cgi?id=55591 -->
<None Remove="**\*.xaml" />

<Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />
<EmbeddedResource Include="**\*.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
</ItemGroup>

</Project>


Note the addition of the PackageTargetFallback property. This is required to tell NuGet that specified TFM is compatible here because the Xamarin.Forms package has not yet been updated to use netstandard directly. Also note that DebugType set to full is required for the Xamarin tool-chain currently as they don’t yet support the new portable PDBs that are created by default.

At this point, when you reload the project, it should restore the packages and build correctly. You may need to do a full clean/rebuild.

## Seeing it in action

I created a sample solution showing this all working over on GitHub. It’s a good idea to clone, build and run it to ensure your environment and tooling is up-to-date. If you get stuck converting your own projects, I’d recommend referring back to that repo to find the difference.

## Building on command line

You will need to use MSBuild.exe to build this, either on Windows with a VS 2017 command prompt or a Mac with Visual Studio for Mac. You cannot use dotnet build for these projects types. dotnet build only supports .NET Standard, .NET Core and .NET Framework project types. It is not able to build the Xamarin projects and the custom tasks in Xamarin Forms have not yet been updated to support .NET Core.

To build, you’ll need two steps:

1. msbuild /t:restore MySolution.sln
2. msbuild /t:build /p:Configuration=Release MySolution.sln

You can also restore/build the .csproj files individually if you’d prefer.

As always, feel free to tweet me @onovotny as well.

## Multi-targeting the world: a single project to rule them all

January 4, 2017 Coding 15 comments , , , , , , ,

# Multi-targeting the world: a single project to rule them all

Starting with Visual Studio 2017, you can now use a single project to build platform-specific libraries for all project types. This blog will explore why you might want to do this, how to do it and workarounds for some point-in-time issues with the tooling.

## Intro

Since the beginning of .NET Core, the project.json format has enabled multi-targeting, that is compiling to multiple target frameworks in parallel and creating an output for each. With ASP.NET Core, it’s common to target both net45 and netcoreapp1.0 so you can deploy the site to either the desktop framework, which runs on Windows, or to the CoreCLR, which runs cross-platform. Multi-targeting is nothing more than compiling the same code multiple times, once per target platform. Each target can specify its own dependencies and ifdef‘s, so you can easily tailor the code to the specific platform.

Another example may have a library target netstandard1.0, netstandard1.3, and net45 to enable different levels of functionality based on the available surface area.

While it was also possible to target UWP, Win8, or profile-based PCL’s, using project.json, doing so required hacks like private copies of all reference assemblies, WinMD files and more. Beyond that, some things didn’t work correctly as some platforms require additional targets to generate additional outputs like .pri files on UWP for resource lookup. So while technically possible, full multi-targeting was brittle and required you to stay in a very narrow path, avoiding things like resources or GUI elements that require the full tool-chain to process.

### Enter MSBuild

With the move to MSBuild as part of the .NET Core Tooling direction change, the picture gets much better, so much so that with VS 2017 RC2, you can correctly multi-target all platform types, including UWP, profile-based PCL’s, and Xamarin iOS/Android. Not only that, but by conditionally including/excluding directories based on globs, you can reduce the need for ifdef‘s in many cases.

As part of being open sourced and enabled to run cross-platform, the build targets and tasks required to actually do the build were combined into an SDK. This went along with drastic simplification of the csproj file to have a minimal footprint, that will get even smaller, like this:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
</ItemGroup>
</Project>


Microsoft’s blog details all of the improvements in this area. For current lack of a better term, I’ll call projects based on these new tools “SDK style.” The easiest way to identify these “SDK style” projects is by looking for the Sdk attribute in the top Project element.

## Multi-targeting vs. .NET Standard Libraries vs. PCL’s

Before we go further, let’s answer this question that many people have asked — why would you want to multi-target vs just use a single portable library, whether that’s .NET Standard or an older profile-based PCL?

There are several answers to that question — first, if your code can all fit within a single .NET Standard-based library, then there’s no reason to multi-target. If you’re using a legacy profile-based PCL, at the very least consider moving up to the equivalent .NET Standard version. Don’t make more work for yourself. The decision to multi-target falls out of a need to use functionality that doesn’t exist within a .NET Standard version or if you need to target an earlier platform that doesn’t support the .NET Standard version you need. A common example is that many libraries still need to support .NET 4.5. Despite a significant amount of functionality available in .NET Standard 1.3, that .NET Standard version only supports .NET 4.6+. Chances are though that the code would work “just fine” on .NET 4.5, so it’s easy to multi-target to both net45 and netstandard1.3.

The other main reason why you’d need to multi-target is to use platform-specific code within your library. For example, on iOS you might want to use SecKeyChain for saved credentials, on Android use its Context to access shared services like preferences, and on Windows its Credential Manager. You might have a common method called GetCredential that other code uses to get the data. Today you might use dependency injection or reflection to access a “.Platform” library with a specific implementation that your common code uses. Instead, you can choose to multi-target and access the platform code directly.

## How to multi-target

Let me start by saying that the methods here are based on the new “SDK-style” projects that VS 2017 provides. They orchestrate using the existing project types that are installed by Visual Studio. As such, the build itself won’t work on a box without the other tools installed (so you’re building on a Windows box, much like you probably are today). Some of these may work on a Mac with Visual Studio for Mac but I have not tested that in any way. When you install Visual Studio 2017, make sure to install all of the tools for the project types you need (Xamarin, UWP, etc) and also the .NET Core Tooling.

There’s no UI in VS for adding additional target frameworks, but I have some samples that show what to do.

First, create a new .NET Core Class Library project. If you don’t see the following option, make sure to install the .NET Core workload in the VS Installer.

Right-click the project and select “Edit project file…”. This is new in VS 2017 – the ability to edit the project file while it’s open and have changes instantly reflected.

In the editor, after noticing how much less boilerplate code there is now, look for the TargetFramework property that looks like this: <TargetFramework>netstandard1.3</TargetFramework> property. Change that to <TargetFrameworks>netstandard1.3;net45</TargetFrameworks> to target .NET 4.5 and NET Standard 1.3. You can add however many targets you want by adding to that semi-colon list. It’s subtle, but note the difference in property names between TargetFramework and TargetFrameworks with a plural. It’s easy to miss.

For some frameworks, like .NET 4.5, that’s all you need to do. However, targeting .NET Standard and .NET 4.x is far from “the world.” We can do better! You would think it should be as easy as adding additional TFM’s like uap10.0, xamarin.ios10 or MonoAndroid70 to the list, and hopefully by the time the tools RTM it will be, but for now we need to add extra properties to the project file to tell MSBuild what to do with those.

Fortunately, and here’s the real secret, the “SDK-style” build system has a LanguageTargets property that you can specify per TFM to import the targets for that project type instead of the vanilla Microsoft.CSharp.targets import. That means we can use the “Windows Xaml”, Android, iOS, or any other platform tool-chain we need.

### Xamarin Example

In the example here, I have a class library that multi-targets to net45, uap10.0, netstandard1.3, Xamarin.iOS10 and MonoAndroid70. In this contrived library, I have a Greeter class that’s calling a Hello() method that needs platform specific code. I’m using a pattern where I have a directory for each TFM where code in there only gets included there, so no ifdef‘s are needed. For Android, Resources are supported if you need them. While the example doesn’t currently use them, you could use PList‘s, xib‘s or Story Boards on iOS, Page‘s on UWP, or any other “native” file type supported by the platform.

### Win81/WP8/PCL/Wpa81/Xamarin/Net45 Example

As a more realistic example, one of my libraries, Zeroconf, an mDNS discovery library, targets “the world.” It currently has concrete implementations for wp8, Wpa81, Win8, portable-Wpa81+Win81, uap10.0, net45, and netstandard1.3 (which supports Xamarin and CoreCLR.) In addition to the the concrete implementations, it provides a netstandard1.0 façade to support being used in portable libraries. The different concrete implementations are required due to differences in the networking stacks between the various Windows networking stacks. For now, the uap10.0 version cannot use the netstandard1.3 version until NetworkInformation is fully supported by the platform, so it continues to use the WinRT variant. You can see the platform-specific code in the platforms directory and then how they’re conditionally included by the csproj in the ItemGroups

The property groups at the top contain the LanguageTargets and properties needed. For portable-Wpa81+Win81 two extra items are required as the special PCL profile also supports WinRT. The ItemGroup here has two TargetPlatform to pull in the correct .winmd references.

### Building

You can build the libraries either in VS 2017 or the command-line. If you use the command line, you’ll want to run the following from a VS 2017 Developer Command Prompt: msbuild /t:restore followed by msbuild /t:build. If you want to create a NuGet package, you can run msbuild /t:pack. It’s important to note that you must currently use msbuild, the desktop version in the VS 2017 path, to build these and not dotnet build. The reason is that while dotnet build calls MSBuild, it’s currently using a CoreCLR version even though the desktop version is present in your VS installation. The engineering team is aware of this and in the future, dotnet build will be smart enough to call the desktop version of msbuild when present. The “regular” targets file we’re using to support the platform-specific features are designed for Desktop MSBuild. They do not yet have support for CoreCLR tasks. Bottom line, as of the current release: if your targets use build tasks, then you need to provide both CoreCLR and Desktop versions of the library in order to support both “regular” MSBuild and dotnet build.

## Common gotcha’s

There are several bugs in the tool-chain currently that are in the process of being fixed:

• Some Project-to-project (p2p) references aren’t resolving correctly. Whereas they should resolve to the “best” match, they are resolving to the first TFM in the list.
• Another bug is preventing a “legacy” csproj from doing a p2p reference with a “Portable Library can only reference other portable library” error.
• Files that are conditionally included won’t show up in the Solution Explorer. As a workaround, include all files with None as the first item group (see example).
• for iOS (and possibly Android), you need to set DebugType to full as the Xamarin ConvertPdb2Mdb task doesn’t yet support the new Portable PDB format generated by this tool-chain.
• Win8, Win81, and uap10.0 aren’t correctly understood by the NuGet targets today. As a workaround, you need to include the NugetTargetMoniker property set to the full TFM as shown here. Similarly, for legacy PCL targets, it requires Version=v0.0 in the NugetTargetMoniker here. These should hopefully be fixed by GA.
• Windows assemblies that use resources need a .pri file alongside them. They’re currently missing from the generated NuGet. Workaround is to use your own .NuSpec for now until the bug is fixed.

## Into the weeds, how it all works

This is by no means an official explanation, it’s what I’ve found from exploring the SDK build targets. Some of the terminology and concepts may change over time.

The “SDK style” projects consist of a set of targets/tasks that are pre-installed with MSBuild (and the CLI tools). You can see them in the following directory: C:\Program Files (x86)\Microsoft Visual Studio\2017\<sku>\MSBuild\Sdks where <sku> is Community, Professional, or Enterprise, depending on what you installed. The two SDK’s you’re likely to use directly are Microsoft.NET.Sdk and Microsoft.NET.Sdk.Web.

The Sdk attribute causes an Sdk.props and Sdk.targets within the specified SDK’s \Sdk directory to be imported before and after the project file. The Microsoft.NET.Sdk SDK’s targets defines an “outer” and “inner” build. The “outer-loop” is what your project file directly defines, including several TFM’s in the TargetFrameworks property. If you only have a single build with a TargetFramework property defined, then there’s only an “inner-loop”.

For an “outer-loop” build, the SDK targets imports props/targets in a buildCrossTargeting directory (soon to be renamed to buildMultiTargeting). Those get auto-included before and after the main project file (props before, targets after.) The “outer-loop” targets will eventually loop through each of the TargetFrameworks calling msbuild again in an “inner-loop” with TargetFramework set to one TFM. This “inner-loop” build is what we currently have in today’s “normal” project types. The “inner-loop” build provides an extension point for providing your language-specific targets (the Import that was at the bottom of your old csproj before) in place of the “vanilla” one it’ll include by default. By providing a LanguageTargets property for the “inner-loop,” conditioned by TFM, we can use the “original” targets that invoke the full tool-chain for the target platform. See here, here and here for UWP, iOS, and Android, respectively.

Within each conditionally defined property group, we can set properties that are specific to a particular “inner-loop.” These correspond to the properties in your existing platform-specific project file and are used by the platform-specific targets specified.

One thing you give-up currently is any UI in VS for configuring these properties. Perhaps they’ll return sometime in the future. For now, one thing I’ve found helpful is to maintain a few “dummy” projects where I can edit some settings to see the values and then put them into my multi-targeting csproj.

## Looking forward

As of today (January 4, 2017), the tooling is in a fairly rough state. The .NET Core tooling is rightfully in an “alpha” state. The MSBuild SDK is under active development and things will change before GA. There are a number of issues in the tooling that can make it hard to use today, but I expect those to be fixed soon. Most of the bugs I’ve found are slated to be fixed in the RC3 time-frame, and I’d expect things to be better with that release.

As to whether-or-not to take the plunge today: I’d suggest that if you have a tolerance for figuring this out and reporting issues you’ll encounter, then go for it. If you have a complex project today that already multi-targets a different way (most likely by using multiple “head” projects and shared code project types), I would recommend trying this out in a branch to see how far you get. I’ll be happy to help, just give me a shout. The more the community bangs on this stuff up front, the more issues can be addressed prior to GA.

### Acknowledgments

Many thanks to Brad Wilson, Joe Morris, and Daniel Plaisted for reviewing this post and providing feedback.

## Using Xamarin Forms with .NET Standard

July 9, 2016 Coding 11 comments , , , ,

# Using Xamarin Forms with .NET Standard

With the release of .NET Core and the .NET Standard Library last week, many people want to know how they can use packages targeting netstandard1.x with their Xamarin projects. It is possible today if you use Visual Studio; for Xamarin Studio users, support is coming soon.

## Prerequisites

Using .NET Standard pretty much requires you to use project.json to eliminate the pain of “lots of packages” as well as properly handle transitive dependencies. While you may be able to use .NET Standard without project.json, I wouldn’t recommend it.

You’ll need to use the following tools:

## Getting Started

As of now, the project templates for creating a new Xamarin Forms project start with an older-style packages.config template, so whether you create a new project or have an existing project, the steps will be pretty much the same.

Step 1: Convert your projects to project.json following the steps in my previous blog post.

Step 2: As part of this, you can remove dependencies from your “head” projects that are referenced by your other projects you reference. This should simplify things dramatically for most projects. In the future, when you want to update to the next Xamarin Forms version, you can update it in one place, not 3-4 places. It also means, you only need the main Xamarin.Forms package, not each of the packages it pulls in.

If you hit any issues with binaries not showing up in your bin directories (for your Android and iOS “head” projects), make sure that you have set CopyNuGetImplementations to true in your csproj as per the steps in the post.

At this point, your project should be compiling and working, but not yet using netstandard1.x anywhere.

Step 3: In your Portable Class Library projects, find the highest .NET Standard version you need/want to support.

Here’s a cheat sheet:

• If you only want to support iOS and Android, you can use .NET Standard 1.6. In practicality though, most features are currently available at .NET Standard 1.3 and up.
• If you want to support iOS, Android and UWP, then NET Standard 1.4 is the highest you can use.
• If you want to support Windows Phone App 8.1 and Windows 8.1, then NET Standard 1.2 is your target.
• If you’re still supporting Windows 8, .NET Standard 1.1 is for you.
• Finally, if you need to support Windows Phone 8 Silverlight, then .NET Standard 1.0 is your only option.

Once you determine the netstandard version you want, in your PCL’s project.json, change what you might have had:

{
"dependencies": {
"Xamarin.Forms": "2.3.0.107"
},
"frameworks": {
".NETPortable,Version=v4.5,Profile=Profile111": { }
},
"supports": { }
}


to

{
"dependencies": {
"NETStandard.Library": "1.6.0",
"Xamarin.Forms": "2.3.0.107"
},
"frameworks": {
"netstandard1.4": {
"imports": [ "portable-net45+wpa81+wp8+win8" ]
}
},
"supports": { }
}


Note the addition of the imports section. This is required to tell NuGet that specified TFM is compatible here because the Xamarin.Forms package has not yet been updated to use netstandard directly.

Then, edit the csproj to set the TargetFrameworkVersion element to v5.0 and remove any value from the TargetFrameworkProfile element.

At this point, when you reload the project, it should restore the packages and build correctly. You may need to do a full clean/rebuild.

## Seeing it in action

I created a sample solution showing this all working over on GitHub. It’s a good idea to clone, build and run it to ensure your environment and tooling is up-to-date. If you get stuck converting your own projects, I’d recommend referring back to that repo to find the difference.

As always, feel free to tweet me @onovotny as well.

## Xamarin MVP

January 25, 2016 Coding No comments

# Xamarin MVP

Xamarin just announced their newest round of MVP awards, and I am very honored to have received one. I have always thought that the C# and .NET are the best, most productive, way to create applications for iOS and Android and Xamarin’s tools make this possible.

Hope to see you at Xamarin Evolve later this April!

## xUnit for Xamarin is dead, long live xUnit for Devices!

March 16, 2015 Coding 1 comment , ,

# xUnit for Xamarin is dead, long live xUnit for Devices!

In conjunction with today’s release of xUnit 2.0 RTM, I’m happy to announce the initial release of xUnit for Devices (GitHub | NuGet). This has been a long time coming and I’d like to thank Brad Wilson and James Newkirk for their tremendous efforts over the years.

### Project rename

xUnit for Devices started out as xUnit for Xamarin. Over the course of development however, it became apparent that what we really have is an MVVM-based test runner where the view was only an implementation detail. Current support is limited to platforms Xamarin Forms supports, but in the future it’s pretty easy to add a desktop/WPF view and support any additional GUI platform as needed.

If you’ve been using xUnit for Xamarin, the easiest way to update is by using NuGet. There’s a final xunit.runner.xamarin package that pulls in the new xunit.runner.devices package. After upgrading, you can simply remove the old package and keep the dependencies. Windows Phone 8 users will need to make one additional change in the MainPage.xaml to update the assemly name from xunit.runner.xamarin to xunit.runner.devices.

### Getting Started

The RTM 1.0 release is available on NuGet and on GitHub.

For iOS and Android, create a new blank Xamarin app project to host the unit test runner. Make sure to give any capabilities/permissions you need in the appropriate manifest.

For WP8, create a new Unit Test Project and then remove the MSTestFramework reference.

Then for all platforms, install/update the xunit.runner.devices package via the GUI or Package Manager Console:
Install-Package xunit.runner.devices

Then look for the .cs.txt, xaml.txt files that are the templates for your platform and copy/paste the contents into the app. Specifically,
– iOS: replace the contents of AppDelegate.cs with AppDelegate.cs.txt
– Android: replace the contents of MainActivity.cs with MainActivity.cs.txt
– WP8: replace the contents of MainPage.xaml.cs with MainPage.xaml.cs.txt and MainPage.xaml with MainPage.xaml.txt

## xUnit Device Runners 1.0 RC3

February 23, 2015 Coding 1 comment , ,

Following the release of xUnit 2.0 RC3, the Xamarin Device Runners have been updated to work with RC3.

One note for Android users: due to a dependence on Xamarin Forms, your runner app project needs to use API level 21 as its target and SDK. You can target down to API level 15 if you wish. You can also reference other MonoAndroid or Portable Class Libraries if you want to keep your unit tests at a different API level. You also might need to specify a default theme on some devices to workaround a different Xamarin Forms bug. Please see the updated MainActivity.cs.txt for the specifics.

### Wait, what happened to RC2?

If you blinked, you missed it. RC2 of the Device Runners came out Saturday. With xUnit RC3 being a quick update from RC2, it’s best to skip to the latest.

As always, if you run into any issues, feel free to reach out to @onovotny on Twitter or post an issue on GitHub.

### Getting Started

RC3 is available on NuGet and on GitHub.

For iOS and Android, create a new blank Xamarin app project to host the unit test runner. Make sure to give any capabilities/permissions you need in the appropriate manifest.

For WP8, create a new Unit Test Project and then remove the MSTestFramework reference.

Then for all platforms, install/update the xUnit.Runner.Xamarin package via the GUI or Package Manager Console:
Install-Package xunit.runner.xamarin -Pre

Then look for the .cs.txt, xaml.txt files that are the templates for your platform and copy/paste the contents into the app. Specifically,
– iOS: replace the contents of AppDelegate.cs with AppDelegate.cs.txt
– Android: replace the contents of MainActivity.cs with MainActivity.cs.txt
– WP8: replace the contents of MainPage.xaml.cs with MainPage.xaml.cs.txt and MainPage.xaml with MainPage.xaml.txt

## Announcing: xUnit Device Runner RC1

January 31, 2015 Coding 1 comment , , , ,

# xUnit Device Runner 1.0 RC1

I’m pleased to announce the release of the xUnit Device Runners Release Candidate 1. This release adds support for the Xamarin.iOS Unified profile, required for all new iOS applications now and updates starting in July.

Other notable enhancements include a filter for searching test cases by name and status (pass/fail/not run).

To get started, please see the following posts:

If you run into any issues, please file a report in the issue tracker.