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:
- Close the solution in VS
- Take the existing
csproj
and make a copy of it somewhere else. I’ll keep this other copy open in Notepad. - 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.
- 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:
msbuild /t:restore
MySolution.slnmsbuild /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.
First time I’ve seen any samples with XAML files, I had actually heard it wasn’t currently possible so this is pretty exciting.
1) Is is possible to use wildcards to both embed the XAML files and make the corresponding cs file dependent on the XAML file?
2) Noticed that the platform projects were still in the old format. Is it possible to convert these to the new format, particularly with your SdkExtras?
Hi Dan,
I have updated the sample and snippet to show how you can use a wildcard for your Forms XAML files instead of specifying them individually.
As to the platform files, they can be moved to the new style in theory, but you may run into issues with some Designers (Xib. Storyboard, Axml, UWP XAML, etc) right now.
Hi Oren,
Thanks for the article.
I completed the first part (using PackageReference) and the code is compiling fine. When I try to run the app I get a deploy error “Ensure that this project has Microsoft.Bcl.Build installed and packages.config is located next to the project file” on the PCL of my mobile app. I added a reference to Microsoft.Bcl and Microsoft.Bcl.Build in Nuget but am still getting the error. Strangely it worked the first time after adding these 2 references but is now failing every time
I wanted to test it before moving to .NET standard to make sure that the code is still working
Will changing to .NET standard get rid of this problem?
Hi Oren,
I’ve successfully converted a Xamarin Form (PCL) solution created by VS 2017 template and I must say is slightly more complicated than you described, but your post has been really helpful and guided (and urged!) me to learn more about the new build / NuGet / .csproj ecosystem.
Would love to hear about your experience and what workarounds or additional steps you needed.
I’m doing all again to keep notes and screenshots about those nuances.
As a first example: after removing all the NuGet packages on the .Android project (note that the new template name it Android instead of Droid, maintaining Droid only for the namespace), comparing the csproj of my solution to the one in your repo I can find a notable difference (other than the obvious ones, due to different solution and project names):
My csproj file:
Your csproj file:
true
PackageReference
I had to manually add those two lines to my csproj to enable the new transitive dependencies capability and build successfully without the Xamarin.Forms NuGet package added to the .Android project.
BTW, I’ve removed the two NuGetPackageImportStamp lines, I wonder why these line are still in the csproj created by the VS2017 template…
Hi Oren,
the preview of the reply doesn’t work, nor in Edge nor in Chrome 🙁
Anyway, the code I tried to include on my previous reply was (without lesser than and greater than chars):
My csproj file:
NuGetPackageImportStamp
/NuGetPackageImportStamp
Your csproj file:
CopyNuGetImplementations>true</CopyNuGetImplementations
RestoreProjectStyle>PackageReference</RestoreProjectStyle
OK, one more fault to my score, those two lines are already in your recipe of things to do.
Here is my list:
1. For the UWP project I had to manually remove the project.json but only after unloading the project, otherwise the NuGet manager is unable to add packages again (An error occurred while reading file project.json) and then also the project.lock.json. After that I was able to reload the project and add the Microsoft.NETCore.UniversalWindowsPlatform package.
In your UWP csproj I can’t found the CopyNuGetImplementations and RestoreProjectStyle lines. These are no needed for UWP projects?
I wasn’t be able to simply add a new .NET Standard library and add the Xamarin.Forms package, but I’ve succeded on modifying the PCL lib to .NET Standard manually changing the csproj file with your posted code.
Hi Oren,
One more question. I did the 2nd step (to convert to .NET Standard) only to find out that MSAL in it’s current version (1.0.304142221-alpha) doesn’t support .NET standard. Is there a way to achieve the same functionality without MSAL?
For MSAL, the dev branch has .NET Standard support. They have a nightly MyGet feed on their site: https://github.com/azuread/microsoft-authentication-library-for-dotnet
Out of curiosity, is there a way to handle Resx files similar to how you have it handling the Xaml files? Also if you want Xaml Compilation, would the best route be to add the assembly attribute somewhere like outside the namespace of the App, or is it possible to have it as an element of the csproj like Compile ?
Hi Dan,
Yes, you can do the same thing with ResX files. Here is an example:
https://github.com/Reactive-Extensions/Rx.NET/blob/594d3eeae9d60df6d2cd584cccf75d774e57e3ec/Rx.NET/Source/src/System.Reactive/System.Reactive.csproj#L15-L16
Great post! Halas, it doesn’t seem like Xamarin Studio for Mac (in its latest beta) nor Visual Studio for Mac do support this PackageReference option, at least in the Nuget preferences dialog. Any idea if / when it will be?
Yes – same issue for me too. Not sure if/when it will be supported. In fact it’s sad that the two products are not keeping their features in sync, defeats the whole purpose of developers being able to easily switch computers/platforms and still get the work done.
Great information. Surprised to see no vs2017 xamarin template yet. One thing I encountered so far going through this, is that after converting to the new style project format, you have to remove a bunch of assembly attributes from your assemblyinfo.cs file, as VS2017 now generates these attributes causing duplicates.
Good point. I generally just delete the entire file and make sure the properties are set in the csproj.
Thanks for this post! Helped me along the way while I tried to get EF Core working with Xamarin.Forms and targeting all 3 mobile platforms in .NET Standard library. Mentioned this post in my README at https://github.com/cwrea/XamarinTodo.
Great guide i am running now on .net standard. One question how can i enable global Xaml compilation because now i dont have a AssemblyInfo.cs on my .net standard project
You can just add an AssemblyInfo.cs file, or call it whatever you want, with the one required assembly-level attribute. You just don’t need all of the other things normally in that file.
Thanks! Very helpful, especially with sample. 🙂
Thanks, this is a great article. I upgraded my project to use Netstandard 1.4 without any problems.
However, Visual Studio for Mac doesn’t seem to recognize
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
and if you open your Droid/iOS projects on a Mac, you will have to add all the packages referenced by your shared library to those projects individually. Not sure what the correct channel for raising that issue is.I have the same issue. Have you found any solution for this?
No, I have just stopped using VS for Mac since the upgrade. I only used it to test iPhone simulator debugging. Now a days I’m just using my PC for all dev work (skipping the iOS debugging completely), running a Mobile Center build and distributing it straight to my team members with iOS devices. 🙂
Thank you, Oren.
After six days looking for an solution to convert to .NETStandard your article resolved all.
Congratulations and thank you very much!
🙂
It’s working but now I don’t have intelligence on camp files, any idea how to fix it?
Hey does anyone know how to get Netstandard 2.0 preview with this?
Re TFM, though your example XamFormsSample targets .NetStandard 1.4, on downloading the project, it is actually using V1.6.1
( picked up from local packages folder ).
When I try and change to 1.4 thru Nuget Package Manager, I get the message
‘Blocked By Project’.
Whilst UWP is working under 1.6.1. how can I use 1.4, do I need to use 1.4 if 1.6.1 is working?
Many Thanks
Just a note, I found I had to use the beta channel for Visual Studio for Mac (15.3) to get the PackageReferences to work in the head ios and droid apps. VS2017 for Windows was quite happy.
Having this same with F# would be nice too (maybe UWP with desktop bridge and maybe with Paket). 🙂
This really saved my life.
I was having a lot of problems get Mac Visual Studio to recognize a converted xamarin forms project (from PCL to netstandard).
I recreated it as per your instructions in a few hours, and it worked great.
THANK YOU
I have been trying to get a new Xamarin.Forms working on .Net Standard using Visual Studio 2017 (v15.3.0) Community for over one week. All I get was a whole series of errors which I try to fix one by one and then another comes along. Thank you so much for this article and sample solution which works perfectly.
I don’t know why Microsoft or Xamarin did not come up with a good template themselves. Hope this is the case in the near future.
Hey guy have a hamburger! The sample worked on VS2017 with the Standard library. I added Prism for Xamarin Forms and it still worked.
Oren, is it required to convert to packagereference in order to convert to .Net Std? I have a Xamarin.forms solution i am trying to convert to .Net Std but am having issues with package reference.
Required, no, but highly recommended.
Hi Oren,
I did every possible step on your blog but no matter what I do, it never creates those System.pdbs and dlls in the Android Project bin and Im getting around 4717 errors alltogether. (VS 2017).
Below is my csproj.
netstandard2.0
portable-net45+win8+wpa81+wp8
full
MSBuild:UpdateDesignTimeXaml
BTW: I tried using the below snippet but I was getting duplicate resource error so I switched back.
<Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />
Any idea where im going wrong?