2017/10/24

Return to Xamarin and So Long to PCL

Working on a new project and using C# for the majority of the PC client. We need a mobile app as well, so Xamarin seemed like the logical choice to maximize code reuse.

When previously working with Xamarin I was introduced to PCL. But, I was forever running into problems with platforms I was targeting and the ones supported by packages on nuget.

Apparently well aware of its flaws Microsoft has since deprecated PCL in favor of .Net Standard. We've started targeting the bleeding edge .Net Standard 2.0 since it provides the widest API coverage and meets our platform requirements. What follows is my experience getting a multi-platform (initially just Android and UWP) Xamarin.Forms app using .Net Standard 2.0 building and running with Visual Studio 2017 Community.


Creation

Using the VS 2017 new project wizard, there's currently no obvious way to create a Xamarin app that uses .Net Standard 2.0. Under Other Languages, Visual C#, there's Cross Platform App (Xamarin). Next, for UI Technology choose Xamarin.Forms and Code Sharing Strategy choose Portable Class Library (PCL). From there the following two links got me started converting the PCL project to .Net Standard:


Building

Building for the first time resulted in a bunch of errors similar to the following:
 obj\Debug\netstandard2.0\mobile_app.AssemblyInfo.cs(14,12,14,54): error CS0579: Duplicate 'System.Reflection.AssemblyCompanyAttribute' attribute  
 obj\Debug\netstandard2.0\mobile_app.AssemblyInfo.cs(15,12,15,60): error CS0579: Duplicate 'System.Reflection.AssemblyConfigurationAttribute' attribute  
 obj\Debug\netstandard2.0\mobile_app.AssemblyInfo.cs(16,12,16,58): error CS0579: Duplicate 'System.Reflection.AssemblyDescriptionAttribute' attribute  
To fix this, I need to remove Properties/AssemblyInfo.cs from the project.
 App.xaml.cs(6,7,6,14): error CS0246: The type or namespace name 'Xamarin' could not be found (are you missing a using directive or an assembly reference?)  
 MainPage.xaml.cs(6,7,6,14): error CS0246: The type or namespace name 'Xamarin' could not be found (are you missing a using directive or an assembly reference?)  
 App.xaml.cs(10,32,10,43): error CS0246: The type or namespace name 'Application' could not be found (are you missing a using directive or an assembly reference?)  
 MainPage.xaml.cs(10,37,10,48): error CS0246: The type or namespace name 'ContentPage' could not be found (are you missing a using directive or an assembly reference?)  
 App.xaml.cs(19,33,19,40): error CS0115: 'App.OnStart()': no suitable method found to override  
 App.xaml.cs(24,33,24,40): error CS0115: 'App.OnSleep()': no suitable method found to override  
 App.xaml.cs(29,33,29,41): error CS0115: 'App.OnResume()': no suitable method found to override  
For this, right-click VS project, Manage NuGet Packages, and add Xamarin.Forms.
 error : Project 'mobile_app\mobile_app\mobile_app\mobile_app.csproj' targets '.NETStandard,Version=v2.0'. It cannot be referenced by a project that targets 'UAP,Version=v10.0.10586'.  
I couldn't just build a UWP application with .NetStandard 2.0, it required upgrading Visual Studio 2017 to 15.4 and setting the Minimum Version of the UWP project to "Windows 10 Fall Creators Update" (may first need to set Target Version to the same).
 Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified.  
 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'  
   at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)  
   at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)  
   at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)  
   at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(CustomAttributeRecord caRecord, MetadataImport scope, Assembly& lastAptcaOkAssembly, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, Object[] attributes, IList derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg)  
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes, Boolean isDecoratedTargetSecurityTransparent)  
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeAssembly assembly, RuntimeType caType)  
   at System.Reflection.RuntimeAssembly.GetCustomAttributes(Type attributeType, Boolean inherit)  
   at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType, Boolean inherit)  
   at System.Attribute.GetCustomAttribute(Assembly element, Type attributeType, Boolean inherit)  
   at System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T](Assembly element)  
   at Microsoft.Build.Tasks.ProcessResourceFiles.ReadAssemblyResources(String name, String outFileOrDir)  
Updating Microsoft.NETCore.UniversalWindowsPlatform package to the latest version on nuget solved this. There's also a warning about incompatible versions of Xamarin.Forms, but for that I just removed the reference to the old assembly from the UWP project.


Running

 DEP3321: To deploy this application, your deployment target should be running Windows Universal Runtime version 10.0.16299.0 or higher. You currently are running version 10.0.15063.674. Please update your OS, or change your deployment target to a device with the appropriate version.  
Here we're targeting Fall Creators Update but I wasn't running it yet. Previously I would have to enroll in Windows 10 Insider Preview, but as of today Fall Creators Update is officially released. Finally, I'm not sure if this is actually required for UWP apps, but it's needed for Android so I'll mention it here anyway. Xaml files need to be available at runtime, so right-click each and in Properties set "Build Action" to "Embedded resource".



No comments: