We have talked multiple times on this blog about MSIX and how you can use it to package existing Win32 applications, so that you can improve the deployment and distribution of your Windows applications. If you're starting from a Visual Studio solution (like a WPF or Windows Forms project), the best way to package it with MSIX is the Windows Application Packaging Project, which is a new project's type included in Visual Studio 2017 and 2019. We have talked about this project multiple times, but always using a full .NET Framework project as a reference. However, .NET Core 3.0 is emerging as the new way forward for WPF and Windows Forms application and, even it's still in preview, we can start building Windows desktop .NET Core applications today. So, what if I want to package my WPF or Windows Forms app based on .NET Core with MSIX? Can we still use the Windows Application Packaging Project?
The short answer is... yes! However, there are some specific steps to keep in mind. Let's see them!
The first step, of course, is to start from a WPF or Windows Forms project you have already built using .NET Core 3.0. The most recent .NET Core 3.0 version is Preview 3, which you can get from here https://dotnet.microsoft.com/download/dotnet-core/3.0. To work with .NET Core 3.0 apps you'll also need Visual Studio 2019. You can choose between the RC version, which has a Go Live license and it will be automatically updated to the final bits on 2nd April; or you can get the Preview version, which offers access to preliminary features ahead of the official release.
If you want to know more about .NET Core 3.0 development, here there are some great resources:
- Move your first steps with .NET Core 3.0 for desktop development
- Desktop development features of .NET Core 3.0 Preview 1
- How to convert class library that is targeted WPF to .NET Core 3.0 from .NET Framework
- How to port desktop applications to .NET Core 3.0
If you don't have an existing project but you want to give it a try anyway, you can just create a new project in Visual Studio 2019 and look for WPF (.NET Core) or Windows Forms (.NET Core) in the list of templates:
Or you can use the CLI by opening a command prompt and use one of the following two commands:
dotnet new wpf
dotnet new winforms
Once you have the solution opened in Visual Studio 2019, let's follow the same steps we did in the past to package a full .NET Framework application. Right click on the solution, choose Add -> New project and look for the Windows Application Packaging Project template. Give it a name, then press OK.
Once the new project has been loaded, right click on Applications and choose Add reference. You will see a list of all the projects which belong to your solution. Choose the one which contains your WPF or Windows Forms .NET Core application. At the end, you should see something like this:
So far, nothing special. It's the same exact process you would have done with a full .NET Framework application. However, as soon as you try to build the Windows Application Packaging Project, you will notice something not working as expected:
2>------ Rebuild All started: Project: ContosoExpenses.Package, Configuration: Debug x86 ------
2>C:\Program Files\dotnet\sdk\3.0.100-preview3-010431\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(228,5): error NETSDK1047: Assets file 'C:\Users\mpagani\Source\Samples\ContosoExpenses-Basic\ContosoExpenses\obj\project.assets.json' doesn't have a target for '.NETCoreApp,Version=v3.0/win-x86'. Ensure that restore has run and that you have included 'netcoreapp3.0' in the TargetFrameworks for your project. You may also need to include 'win-x86' in your project's RuntimeIdentifiers.
2>Done building project "ContosoExpenses.csproj" -- FAILED.
The Windows Application Packaging Project, currently, supports .NET Core 3.0 apps only using the Self Contained Deployment approach. This means that the output package won't include just the application, but also the full .NET Core runtime. The downside of this approach is that the package will be bigger, but the great advantage is that you'll be able to deploy it on any machine, regardless if it has or not the .NET Core 3.0 runtime installed. This is very important especially if you're planning to distribute the application through the Microsoft Store. One of the policies, in fact, requires that all the dependencies of the application must be satisfied during the installation (either because they're included in the package or because they're available on the Store). The user shouldn't have to go to a website and download additional libraries / frameworks / tools to run an application downloaded from the Store.
In order to build a self contained application, however, you must specify which are the supported target runtimes. In such a scenario, in fact, you can't build a cross-platform application anymore, because you must embed inside the executable the specific runtime version for the platform where the application is running. Since we're building a Windows desktop application, this isn't a big deal since WPF and Windows Forms application are still bound to Windows. In order to specify the runtime, we need to edit the .csproj file of our project. Right click on it in Solution Explorer and choose Edit xyz.csproj, where xyz is the name of your project.
In the PropertyGroup section add the following line:
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
This is how the first part of your project file should look like:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWPF>true</UseWPF>
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
</Project>
If it's a Windows Forms project, instead of UseWPF you will see the UseWindowsForms entry. With this property we have just added, we are configuring our .NET Core 3.0 project to explictly support the Windows platform, both using the x86 and x64 architecture. Of course, if your project supports only one of these two architectures, feel free to remove the not supported one.
That's it! Now just set as startup project your Windows Application Packaging Project and, in Configuration Manager, choose x86 or x64 as target architecture:
Try to compile again the Windows Application Packaging Project and this time everything will work. Your application will be packaged, along with the specific .NET Core 3.0 version specific for the CPU architecture you have chosen.
Wrapping up
In this post we have seen how we can use the Windows Application Packaging Project to package not only full .NET Framework applications, but also .NET Core 3.0 ones. This feature has been added in Visual Studio 2019 Preview 2 and makes super easy to leverage two of the most interesting technologies to modernize Windows desktop applications: MSIX and .NET Core 3.0. The only limitation is that, currently, Visual Studio supports only Self Contained Deployment, which means that the whole .NET Core runtime is embedded inside the package. This approach has the great advantage of making the application esaier to distribute but it could be redundant in enterprisce scenarios, when you have many applications depenending from the same framework and, as such, it's preinstalled on each machine. However, the team is already working to enable Framework Dependent Deployment as well, which means that the packaged application will be able to leverage the .NET Core 3.0 runtime installed on the machine.
Happy coding!