Core blimey! Windows Forms on .NET Core 3.0

Let’s get this out of the way first. Yes, yes, I still write code for Windows Forms! For cheap and cheerful applications running on the desktop, you just can’t beat it for rapid application development.

And, yes, I have a legitimate need to build a desktop app instead of a web app. I need to alter MP3 files stored locally so that they play as expected in my car, which has very odd notions about the default order to play album tracks.

So…

Last week was .NET Conf 2019 and Microsoft announced the release of .NET Core 3.0, containing support for WPF and Windows Forms. Of course, projects using these technologies can only target Windows machines, not Linux or Mac, so you may wonder what the point is. Well, in May this year Microsoft also announced that the future of .NET will be Core, not Framework. Version 4.8 is the last significant release of the .NET Framework. Thus, if Microsoft developers want to keep up they need to embrace Core.

I started off by watching Olia Gavrysh’s session: Modernizing .NET Desktop Applications with .NET Core – and then dived in. I created myself an empty Windows Forms project and started copying code from my existing project. Here’s what I learned:

  1. The Windows Form designer for .NET Core projects is not yet ready. At the time of writing you can download a preview version which is basic but worked fine for me – I didn’t need to change UI elements for this migration.
  2. Forms no longer seem to have Resource files – so I had to manually load the icon I wanted to use for the form, like so:
    this.Icon = new System.Drawing.Icon(Directory.GetCurrentDirectory()
    + @"\MyIcon.ico");

  3. By default there is no Properties folder in projects (with no apparent AssemblyInfo class or Settings file). However the Properties folder will be created as needed, for instance when you choose to Publish your application
  4. Without the Settings file you need to load user settings yourself. .NET Core now has an extensive Configurations API, built with Dependency Injection in mind. If you want to use a traditional app.config file there is an XML provider, however, I choose to go with the Core-style applicationsettings.json file.
  5. References to Microsoft’s .NET assemblies are now created by adding NuGet packages NB – a lot of examples use extension methods and you need to ensure that you have installed the appropriate libraries via NuGet:
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Configuration.Json;

  6. NuGet is now tracked in the csproj file – so no need for the packages.config file anymore
  7. When it comes to unit testing it’s common to add the InternalsExposedTo attribute to your AssemblyInfo class – but in Core that class is generated by default (with an editor for it added to the project’s Properties pages). You can choose to manually create the file, or alternatively you can add the following to any class in your project:
    [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyTests")]
    

    (fully qualifying the namespace seems to be necessary)
After addressing these steps I then had a Windows Forms app built in .NET 3.0. I can now choose whether to deploy as a self contained EXE – containing all the necessary .NET Core files – or as a application that expects the Core to exist on the target machine (framework dependent).

The following Microsoft documents were useful:
How to: Port a Windows Forms desktop app to .NET Core
Configuration in ASP.NET Core
.NET Core application deployment

And the following blogs came in handy too:
How to use Configuration API in .NET core console application
How to unit test Internal classes in .NET Core applications

Happy coding!

Comments