Wcf Core Playbook - Work In Progress
Purpose
The goal of this document is to provide clear direction and guidance for developers migrating applications that use WCF APIs from the full .NET Framework to .NET Core.
.NET Framework versus .NET Core
Before addressing WCF specifically it is useful to understand the relationship and the differences between .NET Core and .NET Framework. This was addressed well by Immo Landwerth in his Porting to .NET Core blog post.
Relationship of .NET Core and .NET Framework
Before we go into porting itself, it’s useful to understand how .NET Core and .NET Framework relate, especially with respect to available APIs. This helps you in gaining a picture of how APIs are likely going to evolve and in turn enables you to plan the evolution of your applications and libraries.
Many people think of .NET Core as a subset of .NET Framework. It’s important to understand that this isn’t true. While it’s true that .NET Core today is smaller in terms of available APIs, we also have — and plan to continue to have — certain APIs and technologies that are .NET Core only. This includes tooling, for instance .NET Native, but also includes libraries.
However, it’s equally important to understand that the overwhelming majority of .NET Core APIs are shared with the .NET Framework. That makes it fairly easy to write class libraries that can simultaneously work on .NET Core as well as the .NET Framework. In fact, unless you target .NET Framework 4 or Silverlight, all portable class libraries are .NET Core class libraries. If you want to understand how this is modeled and how .NET Core is essentially simply portable class libraries done right, take a look at this blog post.
Of course, the vast majority of existing code is targeting the .NET Framework. Converting an existing .NET Framework class library to .NET Core can be challenging, so let’s take a look at the key differences and API gaps that exist between the two.
Differences between .NET Core and .NET Framework
The differences between the two can be summarized in these three points:
1.NuGet-based. .NET Core is distributed as a set of NuGet packages that allow app-local deployments. In contrast, the .NET Framework is always installed in a system-wide location. This difference doesn’t matter so much for class libraries; but it matters for applications as those are expected to deploy the closure of their dependencies. But we expect this model to change how quickly class library authors can take advantage of new functionality. Since the applications can simply deploy a new version (as opposed to having to wait until a given .NET Framework version is widely adopted), there is less of a penalty for component authors to take advantage of the latest features.
2.Well layered .NET Core was specifically designed to be layered. The goal was to create a .NET stack that can accommodate a wide variety of capabilities and system constraints without forcing customers to recompile their binaries and/or produce new assets. This means that we had to remove certain APIs because they tied lower level components to higher level components. In those cases, we provide alternatives, often in the form of extension methods.
3.Free of problematic tech. .NET Core doesn’t include certain technologies we decided to discontinue because we found them to be problematic, for instance AppDomain and sandboxing. If the scenario still makes sense for .NET Core, our plan is to have replacements. For example, AssemblyLoadContext replaces AppDomains for loading and isolating assemblies.
The first point means that we now fully embrace NuGet as a first-class concept for the core development experience. We believe this to be a natural progression as many of you already use NuGet to acquire third party dependencies.
The second and third point mean that there are certain APIs that aren’t available when targeting .NET Core. Let’s look at some areas you should be aware of.
What is the WCF Story in .NET Core
.NET Core WCF Client
This project is intended for .NET Core WCF client-side projects to call into existing WCF Services that run on .NET Framework.
GitHub repository: dotnet/wcf
Core WCF
This project is for the purpose of porting .NET Framework Services to .NET Core, but with limitations. Scott Hunter in his .NET Blog described it like this.
GitHub repository: CoreWCF/CoreWCF
*This playbook is focused on porting projects using the .NET Core WCF Client packages.
.NET Core WCF Client
In order to best support porting of WCF client side features from .NET Framework to .NET Core we will...
- Continue to support the .NET Standard 2.0 target framework even in our most recent packages and plan to continue doing so in future releases.
- Keep the names and namespaces identical when adding support for .NET Framework APIs in Core WCF Client.
This is important because .NET Framework 4.6.1 and higher supports targeting .NET Standard 2.0, meaning that .NET Standard 2.0 contains the base class libraries needed to support WCF client-side features that already exist in .NET Framework. Therefore these features on the full .NET Framework could eventually be supported on .NET Core via our .NET Core WCF Client packages, that being said, there are some features that are highly unlikely to be supported in .NET Core due to missing dependencies or other significant blocking issues.
Here is a doc with more info about this: Doc needed
*To learn more about .Net Standard: .NET Standard
.NET Core WCF Client packages
There are 5 .NET Core WCF Client public packages and 1 private implementation package. The public packages support a number of target frameworks which are listed by their Target Framework Moniker.
- System.ServiceModel.Duplex
- System.ServiceModel.Http
- System.ServiceModel.NetTcp
- System.ServiceModel.Primitives
- System.ServiceModel.Security
- System.Private.ServiceModel
The public packages are the packages that can be referenced and contain the APIs that represent the supported surface area. The assemblies under the lib directory are empty and simply type forward to the private implementation package.
note: An API may not be supported just because it can be found in the private implementation package even if the access modifier on the type is public. It must be explicitly listed in one of the 5 public packages.*
The Duplex, Http, NetTcp and Security packages have a reference dependency on Primitives and all of them depend on the private package for the implementation.
System.ServiceModel Shim
Beginning with .NET Standard 2.0 we introduced a shim assembly designed to allow libraries that have been built targeting the .NET Framework to run using the .NET Core WCF Client packages. This ‘System.ServiceModel.dll’ shim is in the ‘netstandard2.0’ TFM directory of the Primitives package and at runtime type-forwards to the private implementation package.
Beginning the Porting Process
Begin with the Microsoft .NET Core guide “Port from .NET Framework”. It is expected that you will follow that guide, in this doc we will provide additional information primarily focused on WCF.
Identify WCF APIs
In the simple scenario where your own code uses WCF or you depend on a third party assembly that uses WCF, the first step to determine the portability of your project is to run the .NET Portability Analyzer.
*It is also recommended that you use the .NET API Analyzer to help identify compatibility risks.
Having gotten a report from the .NET Portability Analyzer, filter the data for WCF specific APIs by the assemblies they were found in. In the full .NET Framework the WCF assemblies are…
- System.ServiceModel.dll
- System.ServiceModel.Channels.dll
- System.ServiceModel.Activation.dll
- System.ServiceModel.Discovery.dll
- System.ServiceModel.Web.dll
- System.ServiceModel.Routing.dll
- System.ServiceModel.WasHosting.dll
- System.ServiceModel.dll
- System.IdentityModel.dll
- System.Runtime.Serialization.dll
- System.Xml.dll
Resolving Compilation Errors
Several approaches are discussed on the Port .NET Framework libraries to .NET Core page. One additional approach is to use the <TargetFrameworks>
element in the project so that as you fix compiler issues you verify it works in both your current target framework and the one you are porting to, such as…
<TargetFrameworks>netstandard2.0;net48;</TargetFrameworks>
Analyze WCF APIs
Dead or Unnecessary Code
WCF is a complex technology and there have been numerous cases where more WCF code was used than was necessary for the desired scenario. There is no convenient tool for discovering these situations. The recommended approach is to focus on the ‘unsupported APIs’ and do a targeted analysis.
Unsupported APIs
Known status
Many currently unsupported feature areas are in some planning state while others have significant blocking issues preventing them from being added. Check Unsupported Features Status - link needed for information on various WCF features that are not yet currently supported in .NET Core.
Unknown status
For any feature areas or APIs that are not in the Unsupported Features Status page please open a GitHub Issue with a feature or API status request so we can address it.
Case Study Example
Scenario
A legacy service, business critical, that hasn’t been touched in a long time. The original developers were no longer around, what the service does is understood, how it does it not so much. This service and its libraries did not need any WCF Server side capabilities. Running the ‘.NET Portability Analyzer’ tool identified many WCF APIs that were not available in .NET Core. Deeper analysis categorized these unsupported APIs as follows…
*API counts include methods, properties, enumerators, etc.…
- Server side APIs not be supported by client packages in the .NET Core WCF Client. – 367 APIs
APIs such as methods in abstract classes that contained both client side and server-side methods. These abstract classes in WCF Core will have the server-side components removed.
- APIs that were not actually used. – 343 APIs
A lot of WCF Samples have been published to demonstrate various features. It is not unusual for developers to use code in these Samples in their projects, this is generally fine but often results in unnecessary code being pulled in. This also tends to pull in server-side APIs that are not needed, contributing to the first category. Properties were being explicitly set to default values. If these properties had been needed they would have been identified via the feature that used them, by explicitly setting them to their default value every one of them that was not supported got flagged.
- Modification and simplification of the service code. – 319 APIs
The service needed to communicate with a Security Token Service (STS) using the WS-Trust protocol, and a custom WS-Trust client was written to do this. WCF on the full .NET Framework supports the WS-Trust protocol through a dependency on System.IdentityModel APIs that include a WS-Trust client. This WS-Trust client implementation introduced many additional unsupported APIs due to their calls directly into System.IdentityModel. By removing this WS-Trust client implementation and used a WCF binding instead, the WCF Team then worked with the team that owns System.IdentityModel to get their WS-Trust client working on Core. This solution simplified the service and avoided unsupported APIs that would have blocked their migration to Core.
- APIs that the WCF Team needed to add support for in Core. – 364 APIs
The issues that tracked adding support for these APIs can be found on the WCF GitHub repo using the WSFederation label.
Additional resources…
https://devblogs.microsoft.com/dotnet/porting-to-net-core/ https://www.stevejgordon.co.uk/migrating-full-net-framework-net-core https://mitchelsellers.com/blog/article/should-when-and-how-can-i-migrate-to-net-core https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/porting.md#unsupported-technologies https://docs.microsoft.com/en-us/dotnet/core/porting/ https://devblogs.microsoft.com/dotnet/supporting-the-community-with-wf-and-wcf-oss-projects/