.NET Core 3.0 will be RTM soon and it supports WPF and Winforms APIs.
In my last post I’ve been exploring .NET Core 3.0 new APIs by comparing compiled bits with NDepend, of .NET Core 3.0 against .NET Core 2.2.
In this post I will compare .NET Core 3.0 Windows Forms (Winforms) and WPF APIs with .NET Framework 4.x.
I won’t make the suspense last: .NET Core 3.0 support for Winforms and WPF APIs is almost complete, I found very few breaking changes.
I will now explain what I’ve done with NDepend to explore this API diff, and then dig into the results. If you are wondering How to port desktop applications to .NET Core 3.0 see Microsoft explanations here.
Comparing .NET Core 3.0 Winforms and WPF APIs vs. NET Framework 4.x with NDepend
From the NDepend Start Page select Compare 2 versions of a code base menu. Then use Add assemblies in Folder buttons to add .NET Framework assemblies from folder C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319 and Microsoft.WindowsDesktop.app nuget package assemblies (from folder C:\Users\psmac\.nuget\packages\microsoft.windowsdesktop.app\3.0.0-preview-27325-3\ref\netcoreapp3.0 on my machine).

A minor difficulty was to isolate the exact set of assemblies to focus on. Here is the list of concerned assemblies I came up with:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
Accessibility PresentationCore PresentationCore-CommonResources PresentationFramework PresentationFramework.Aero PresentationFramework.Aero2 PresentationFramework.AeroLite PresentationFramework.Classic PresentationFramework.Luna PresentationFramework.Royale PresentationUI ReachFramework System.Drawing System.Drawing.Design System.Drawing.Primitives System.Printing System.Security.AccessControl System.Security.Cryptography.Cng System.Security.Cryptography.Pkcs System.Security.Cryptography.Xml System.Security.Permissions System.Security.Principal.Windows System.Windows.Controls.Ribbon System.Windows.Forms System.Windows.Input.Manipulations System.Windows.Presentation System.Xaml UIAutomationClient UIAutomationClientSideProviders UIAutomationProvider UIAutomationTypes WindowsBase WindowsFormsIntegration |
Notice that to preserve the correspondance between APIs and assemblies packaging, the attribute TypeForwardedToAttribute is massively used to delegate implementations.

The few breaking changes
With the default NDepend rules about API breaking changes, I’ve only found 16 public types and 52 public methods missing. Here are the types:

16 types missing on a total of 4.095 public types, well done!

The 52 public methods missing are: (on a total of 42.645 public methods)
Parent Assembly Name | Parent Type Name | Method name |
System.Security.Principal.Windows | System.Security.Principal.WindowsIdentity | .ctor(String,String) |
System.Security.Principal.Windows | System.Security.Principal.WindowsIdentity | Impersonate() |
System.Security.Principal.Windows | System.Security.Principal.WindowsIdentity | Impersonate(IntPtr) |
System.Security.Principal.Windows | System.Security.Principal.IdentityReferenceCollection | get_IsReadOnly() |
System.Security.Permissions | System.Net.EndpointPermission | ToString() |
System.Security.Permissions | System.Security.HostProtectionException | GetObjectData(SerializationInfo,StreamingContext) |
System.Security.Permissions | System.Security.Policy.ApplicationDirectory | Clone() |
System.Security.Permissions | System.Security.Policy.ApplicationTrust | Clone() |
System.Security.Permissions | System.Security.Policy.PermissionRequestEvidence | Clone() |
System.Security.Permissions | System.Security.Policy.Site | Clone() |
System.Security.Permissions | System.Security.Policy.StrongName | Clone() |
System.Security.Permissions | System.Security.Policy.Url | Clone() |
System.Security.Permissions | System.Security.Policy.Zone | Clone() |
System.Security.Permissions | System.Security.Policy.GacInstalled | Clone() |
System.Security.Permissions | System.Security.Policy.Hash | Clone() |
System.Security.Permissions | System.Security.Policy.Publisher | Clone() |
System.Security.Cryptography.Pkcs | System.Security.Cryptography.Pkcs.EnvelopedCms | .ctor(SubjectIdentifierType,ContentInfo) |
System.Security.Cryptography.Pkcs | System.Security.Cryptography.Pkcs.EnvelopedCms | .ctor(SubjectIdentifierType,ContentInfo,AlgorithmIdentifier) |
System.Security.Cryptography.Pkcs | System.Security.Cryptography.Pkcs.EnvelopedCms | Encrypt() |
System.Security.Cryptography.Pkcs | System.Security.Cryptography.Pkcs.ContentInfo | Finalize() |
System.Security.Cryptography.Cng | System.Security.Cryptography.ECDiffieHellmanCng | FromXmlString(String) |
System.Security.Cryptography.Cng | System.Security.Cryptography.ECDiffieHellmanCng | ToXmlString(Boolean) |
System.Security.Cryptography.Cng | System.Security.Cryptography.ECDsaCng | FromXmlString(String) |
System.Security.Cryptography.Cng | System.Security.Cryptography.ECDsaCng | ToXmlString(Boolean) |
System.Security.Cryptography.Cng | System.Security.Cryptography.RSACng | DecryptValue(Byte[]) |
System.Security.Cryptography.Cng | System.Security.Cryptography.RSACng | EncryptValue(Byte[]) |
System.Security.Cryptography.Cng | System.Security.Cryptography.RSACng | get_KeyExchangeAlgorithm() |
System.Security.Cryptography.Cng | System.Security.Cryptography.RSACng | get_SignatureAlgorithm() |
System.Printing | System.Printing.PrintQueue | set_Name(String) |
System.Printing | System.Printing.IndexedProperties.PrintInt32Property | op_Implicit(PrintInt32Property) |
System.Printing | System.Printing.IndexedProperties.PrintStringProperty | op_Implicit(PrintStringProperty) |
System.Printing | System.Printing.IndexedProperties.PrintStreamProperty | op_Implicit(PrintStreamProperty) |
System.Printing | System.Printing.IndexedProperties.PrintQueueAttributeProperty | op_Implicit(PrintQueueAttributeProperty) |
System.Printing | System.Printing.IndexedProperties.PrintQueueStatusProperty | op_Implicit(PrintQueueStatusProperty) |
System.Printing | System.Printing.IndexedProperties.PrintBooleanProperty | op_Implicit(PrintBooleanProperty) |
System.Printing | System.Printing.IndexedProperties.PrintThreadPriorityProperty | op_Implicit(PrintThreadPriorityProperty) |
System.Printing | System.Printing.IndexedProperties.PrintServerLoggingProperty | op_Implicit(PrintServerLoggingProperty) |
System.Printing | System.Printing.IndexedProperties.PrintDriverProperty | op_Implicit(PrintDriverProperty) |
System.Printing | System.Printing.IndexedProperties.PrintPortProperty | op_Implicit(PrintPortProperty) |
System.Printing | System.Printing.IndexedProperties.PrintServerProperty | op_Implicit(PrintServerProperty) |
System.Printing | System.Printing.IndexedProperties.PrintTicketProperty | op_Implicit(PrintTicketProperty) |
System.Printing | System.Printing.IndexedProperties.PrintByteArrayProperty | op_Implicit(PrintByteArrayProperty) |
System.Printing | System.Printing.IndexedProperties.PrintProcessorProperty | op_Implicit(PrintProcessorProperty) |
System.Printing | System.Printing.IndexedProperties.PrintQueueProperty | op_Implicit(PrintQueueProperty) |
System.Printing | System.Printing.IndexedProperties.PrintJobPriorityProperty | op_Implicit(PrintJobPriorityProperty) |
System.Printing | System.Printing.IndexedProperties.PrintJobStatusProperty | op_Implicit(PrintJobStatusProperty) |
System.Printing | System.Printing.IndexedProperties.PrintDateTimeProperty | op_Implicit(PrintDateTimeProperty) |
System.Printing | System.Printing.IndexedProperties.PrintSystemTypeProperty | op_Implicit(PrintSystemTypeProperty) |
System.Printing | System.Windows.Xps.XpsDocumentWriter | raise__WritingProgressChanged(Object,WritingProgressChangedEventArgs) |
System.Printing | System.Windows.Xps.XpsDocumentWriter | raise__WritingCompleted(Object,WritingCompletedEventArgs) |
System.Printing | System.Windows.Xps.XpsDocumentWriter | raise__WritingCancelled(Object,WritingCancelledEventArgs) |
System.Drawing | System.Drawing.FontConverter | Finalize() |
Portability to .NET Core 3.0 analysis
Microsoft offers a Portability Analyzer tool to analyze changes in desktop API that will break your desktop app. I’ve tested it on NDepend but I just got very coarse results. Did I miss something? At least it is mostly green 🙂

I wrote last year a post named Quickly assess your .NET code compliance with .NET Standard let me know in comment if it is worth revisiting this post for desktop APIs. Btw, my guess is that desktop APIs won’t be part of .NET Standard vNext (since there is no plan to support it on all platforms) but I haven’t found any related info on the web.
Why migrate your desktop app to .NET Core 3.0?
This is a great news that Microsoft embeds good-old desktop APIs in .NET Core 3.0 with such an outstanding compatibility. It is worth noting that so far (February 2019) there is no plan to port Windows Forms and WPF on other platforms than Windows. So, what are the benefits of porting an existing application to .NET Core 3.0?
I found answers in this recent How to Port Desktop Applications to .NET Core 3.0 Channel9 30 minutes video at 5:12. Basically you’ll get more deployment flexibility, Core Runtime and API improvements and also more performances.
Microsoft promises to not urge anyone to port existing Winforms and WPF application to .NET Core 3.0. However for a Visual Studio extension shop like us if it is decided that VS will run on .NET Core 3.0 in the future, we hope to be notified many months ahead. We discussed that on twitter with Amanda Silver in January 2019. It looks like this spring 2019 they will take a decision. As a consequence to support both Visual Studio past versions running on .NET fx and new versions running on .NET Core 3, an extension will need to support both .NET Fx and .NET Core 3 desktop APIs.
Hi,
“An in-depth” ? What are replacements for missing funcionality? Why there are not there? Deprecated XML?
Cheers
I hope that with all API details it is in-depth enough.
> What are replacements for missing funcionality? Why there are not there? Deprecated XML?
Those are questions for Microsoft
Patrick, this is a great post! Since February we added support for many assemblies from your list to .NET Core 3, so the compatibility should be even better now! 🙂
In the Portability Report you can see all APIs that are not supported in the Details tab.
You are absolutely right that desktop APIs will not be included in .NET Standard.
Here are a few suggestions on what to use instead of the parts that are not coming to Core:
* use ASP.NET Blazor for ASP.NET Web Forms
* use gRPC for WCF Server and Remoting
* use Open Source Core Workflow for Workflow (https://github.com/UiPath/corewf)
Thank you,
Olia Gavrysh
.NET team, Microsoft
I guess we are all just a bunch of dummies who don’t understand the value of more deployment flexibility, Core Runtime and API improvements and also more performances
it would be just as easier to port our WPF/FF code to another stack other that core , maybe that explains whhy almost no one is adopting core, just have a look a the pathetic Nuget downloads and the Wc3tech marketshare numbers, it’s not a “no” it’s a “hell Fing NO” , but shill on my friend maybe you can get a MVP award patty !