UWP Class Library to Multi-Architecture NuGet Package
UWP Class Library to Multi-Architecture NuGet Package
Here's an overview of the UWP AppServices class library, and creating a NuGet package for UWP class libraies.
Join the DZone community and get the full member experience.Join For Free
The State of API Integration 2018: Get Cloud Elements’ report for the most comprehensive breakdown of the API integration industry’s past, present, and future.
Like I already announced in my last blog post about UWP AppServices, I am going to show you how to create a NuGet package for UWP class libraries. I am going to go through the whole process, and provide you the steps I found as easiest (it may be the case that there are other ways for the single steps, too). I am continuing with my AppServices sample to show you all the steps I did.
The first step is to download the latest NuGet.exe. This command line application will do all the work that is needed to create the package. Once downloaded, let’s do some modifications to our project.
It is good practice to put all the NuGet stuff into a folder in your project. That’s what we’re doing now, adding a folder named NuGet and put the NuGet.exe file in it (copy and paste it in file explorer). The next step we would do now is to open the Package Manager Console in Visual Studio and call the nuget.exe with the parameter ‘spec’ to create a .nuspec file. The.xml formatted .nuspec file describes the structure of the NuGet package.
Because we need a multi-architecture package for our Universal class library, I prefer another approach. I created a sample .nuspec file that already describes part of the structure that we need. After pasting the file in, change the file name to match “[projectname].nuspec”. To add the file to your project in Visual Studio, click on the ‘ Show All Files’ button on top of the Solution Explorer Window. Now you will see the previously added NuGet folder and the .nuspec file. Right click on the renamed .nuspec file and select ‘Include in Project’:
Inside the .nuspec File
Let’s have a look into the .nuspec file. The first part is the ‘metadata’ part, which describes the file’s properties:
<metadata> <id>$title$</id> <version>$version$</version> <title>Simple Leet AppService Handler</title> <authors>$author$</authors> <owners>$owner$</owners> <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>$description$</description> <copyright>Copyright © 2016</copyright> <dependencies> </dependencies> </metadata>
Just replace the $-enclosed variables with your data. The more interesting part in this case is the dependencies part. With the Universal app platform, Microsoft introduced the .NETCore package that provides all the APIs. It is very hard to maintain the dependencies manually. Luckily, there is already a Nuget package that helps us to automate this process: NuSpec Dependency Generator.
Just add the package to your project and compile it. That’s it, you have all the dependencies in your .nuspec file:
<dependencies> <group targetFramework="uap10.0"> <dependency id="System.Diagnostics.Debug" version="4.0.10" /> <dependency id="System.Runtime" version="4.0.20" /> <dependency id="System.Runtime.WindowsRuntime" version="4.0.10" /> <dependency id="System.Threading.Tasks" version="4.0.10" /> </group> </dependencies>
Now that we have the dependencies in place, we’re ready for the next step: creating the package file structure. As we want a multi-architecture package, we need to compile the project for every CPU architecture. This is done pretty simple, just select Release mode and build the project for all architectures:
Please note that ‘Any CPU’ will not work for UWP libraries. To check if we have all files in place, just open the corresponding architectures’ folder in the bin folder of your project:
The next part is to add these folders to the .nuspec file within the ‘files’ tag:
<files> <file src="..\bin\ARM\Release\SampleAppServiceConnector.dll" target="runtimes\win10-arm\lib\uap10.0" /> <file src="..\bin\ARM\Release\SampleAppServiceConnector.pdb" target="runtimes\win10-arm\lib\uap10.0" /> <file src="..\bin\x64\Release\SampleAppServiceConnector.dll" target="runtimes\win10-x64\lib\uap10.0" /> <file src="..\bin\x64\Release\SampleAppServiceConnector.pdb" target="runtimes\win10-x64\lib\uap10.0" /> <file src="..\bin\x86\Release\SampleAppServiceConnector.dll" target="runtimes\win10-x86\lib\uap10.0" /> <file src="..\bin\x86\Release\SampleAppServiceConnector.pdb" target="runtimes\win10-x86\lib\uap10.0" /> </files>
Noticed that we use the ‘runtimes’ folder with the corresponding architecture structure folders? This is how we need to set it up for multi architectural packages. Including the .pdb files is always a good practice, even with the missing symbolication in UWP applications (at least for now. I was told from inside Microsoft that they are working on this, but it seems to be a very complicated process for .NET native compiled applications).
Very Important: The Entry Reference
This alone does not work, though. We need a reference that we can use as entry point for our package. To do this, we need to add an additional folder entry to our .nuspec file:
<file src="..\bin\Release\SampleAppServiceConnector.dll" target="ref\uap10.0" /> <file src="..\bin\Release\SampleAppServiceConnector.pri" target="ref\uap10.0" />
Now that we have added this folder structure to the .nuspec file, the only thing we need to do is to manually mark one of the library .dlls as AnyCPU (yes, I tried to compile the class lib as AnyCPU without success). Here is how to do it:
- Copy the x86-.dll file into the Release folder under the bin folder of your project
- Copy the x86-.dll and .pri file into the Release folder
- open the Visual Studio Developer Command Prompt (type ‘dev’ into the start menu, it will appear there)
- type: corflags.exe /32bitreq- [path to Release folder]\[dll-Name].dll
- the result should look like this:
If you have additional files like xaml files, you would need to add a new folder in the uap10.0 folder (with the same name that your project has). I’ll update this post and the sample once I have a matching sample at hand.
Creating and Testing the Package!
Now we are finally able to pack the NuGet package. As we have the Developer Command Prompt already open, lets change the running directory to match the NuGet folder in our project. All we then need to do is to run the pack command of the nuget.exe that we already placed in there:
And that’s it. We have our NuGet Package in place. Now let’s test our package, before we are going to upload it to nuget.org. All you need to do is to have a folder for your NuGet packages on your machine. I made a folder called ‘TestNuget’ on mine, and copied the package into it (which is the same as the Nuget push command we’ll see later).
To add this folder as package source, open the ‘Options’ menu in Visual Studio and select ‘Package Sources’ in the NuGet Package Manager entry. Hit the add symbol on top and add your folder:
Now if you open the Package Manager and select your local folder as source, you will be able to install and test your package:
Publishing the Package to nuget.org (Or Your NuGet Server)
The final step is to publish the newly generated package to nuget.org or your own NuGet server. As we still have the Developer CMD opened, we simply use the following command:
nuget push [path to your package.dll] [nuget.org API Key]
Another alternative would be to use the nuget.org website to upload the package: https://www.nuget.org/packages/upload (the page is self explanatory).
That’s it, your NuGet package is available for all you consider to use it. I also updated the sample of my last blog post on GitHub to include these changes, if you want to play around.
Some of you may go a different route for some steps. I have found this a good way that is also kind of memorable (for me). I would love to hear feedback on this and to discuss this, so feel free to leave me a comment.
Like always, I hope this post is helpful for some of you. Happy coding, everyone!
Published at DZone with permission of Marco Siccardi , DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.