WCF services on .NET 8 or 10: CoreWCF, gRPC or Web API
If your .NET Framework application hosts WCF services, the port to .NET 8 or 10 has one problem the rest of the code does not: Microsoft ships the WCF client for .NET and no server. The server side comes from CoreWCF, a community project, or from a rewrite to gRPC or a Web API. This guide says what each option covers, using Microsoft’s and CoreWCF’s own pages.
What Microsoft ships for .NET
The dotnet/wcf repository holds, in its own words, “the .NET Core version of the Windows Communication Foundation client libraries”, and describes them as a subset of the .NET Framework version. The packages are System.ServiceModel.Primitives, System.ServiceModel.Http (BasicHttpBinding), System.ServiceModel.NetTcp, System.ServiceModel.NetNamedPipe, System.ServiceModel.UnixDomainSocket and System.ServiceModel.Federation (WS-Federation). For hosting a service, the same readme sends you to CoreWCF.
Microsoft’s list of .NET Framework technologies that are not in .NET says the same in a tip: a WCF server can be used in .NET 6 and later through the CoreWCF NuGet packages. The page also says that Windows Workflow Foundation is not supported in .NET, which takes Workflow Services with it.
Microsoft’s gRPC documentation names two recommended paths for a WCF application. gRPC is the first. The second is CoreWCF, described as “a community effort to bring support for hosting WCF services to .NET”, with the caveat that it “only supports a subset of WCF’s features, and .NET Framework apps that migrate to use it will need code changes and testing to be successful”. The page calls CoreWCF “a good choice if an app has to maintain compatibility with existing clients that call WCF services”. If you cannot change the clients, the service keeps speaking SOAP, and CoreWCF is the only way to host it on .NET.
CoreWCF
What it is
CoreWCF is “a port of the service side of Windows Communication Foundation (WCF) to .NET Core”, published under the MIT license and supported by the .NET Foundation. The service host runs inside ASP.NET Core. When 1.0 came out, Microsoft wrote on the .NET blog that support for 1.x follows the support of the .NET platform it runs on, and the project’s support document says Microsoft Product Support is available for CoreWCF customers. The current 1.9 releases list .NET Framework 4.6.2 and above, .NET 8, .NET 9 and .NET 10 as supported targets.
The 1.0 announcement describes the scope as “a subset of the functionality from WCF, but represents what we believe are the most used features”. It recommends considering alternatives to SOAP such as gRPC, and says that “The sweet spot for CoreWCF is to make it easier to modernize server and clients”: an existing service with existing clients.
What it has
From the 1.0 announcement, the package list and the release notes:
- Bindings: BasicHttpBinding, NetHttpBinding, WSHttpBinding, WS2007HttpBinding, NetTcpBinding and WebHttpBinding (WCF REST).
- Transports beyond HTTP and TCP, each in its own package: named pipes (
CoreWCF.NetNamedPipe), Unix domain sockets (CoreWCF.UnixDomainSocket, on Linux and Windows, with a matching client indotnet/wcf), MSMQ (CoreWCF.MSMQ), RabbitMQ and Kafka. - Security: transport security and transport with message credential; user name, certificate and Windows authentication; WS-Federation. The 1.0 announcement lists “Message security beyond Transport and Transport with Message Credentials” as not implemented, and we found no later release note that adds it.
- WSDL generation.
AddServiceModelMetadata()registers the behavior,ServiceMetadataBehavior.HttpGetEnabled = trueserves the WSDL over HTTP, andUseRequestHeadersForMetadataAddressBehaviorwrites the host name the client used into it instead oflocalhost. - Extensibility:
IServiceBehavior,IEndpointBehaviorand, per the road map, message inspectors and similar extensions with a namespace change. - Configuration from a file: the
CoreWCF.ConfigurationManagerpackage addsAddServiceModelConfigurationManagerFile(path), which reads services, endpoints and bindings from asystem.serviceModelsection.
What it leaves out
The 1.0 announcement lists distributed transactions and message queueing as not implemented, and says that NetTcpBinding and WSHttpBinding have “some WS-* features not supported”. An MSMQ package has appeared since. Transactions have not: the release notes from 1.6 to 1.9.1 do not mention them. The project’s feature request thread lists WS-AtomicTransaction, WS-Discovery and the Routing Service without a status, and WS-ReliableMessaging as in progress. We found no CoreWCF package for routing. Tracing was missing in 1.0; basic OpenTelemetry support arrived in 1.8.
How a service moves
The walkthrough puts it in one sentence: “The definition and implementation of data and service contracts is the same as WCF. The major difference is in the definition of the host which is now based on ASP.NET Core, and the ceremony of how a service is exposed.” In practice:
- Contracts and the service class stay. The attributes come from the
CoreWCFnamespace; if the project also referencesSystem.ServiceModel.Primitives, the road map says the contract attributes can stay in theSystem.ServiceModelnamespace. ServiceHostand the.svcfile go. An ASP.NET Core project (dotnet new web) withCoreWCF.PrimitivesandCoreWCF.Httpbecomes the host, ordotnet new corewcffrom theCoreWCF.Templatespackage creates one with the pieces below in place.- Bindings and endpoints are declared in
Program.cs.web.configcan be kept throughCoreWCF.ConfigurationManager, or its contents moved into code. - Authentication is configured in ASP.NET Core, not on the binding. The 1.0 release post says so directly. WSHttpBinding defaults to Windows credentials, which the walkthrough turns off for its example because of that.
The host from the walkthrough, with a BasicHttp endpoint, a WSHttp endpoint over TLS and WSDL enabled:
using CoreWCF;
using CoreWCF.Configuration;
using CoreWCF.Description;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddServiceModelServices().AddServiceModelMetadata();
builder.Services.AddSingleton<IServiceBehavior, UseRequestHeadersForMetadataAddressBehavior>();
var app = builder.Build();
var wsHttp = new WSHttpBinding(SecurityMode.Transport);
wsHttp.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
app.UseServiceModel(serviceBuilder =>
{
serviceBuilder.AddService<EchoService>(options => { })
.AddServiceEndpoint<EchoService, IEchoService>(new BasicHttpBinding(), "/EchoService/basichttp")
.AddServiceEndpoint<EchoService, IEchoService>(wsHttp, "/EchoService/WSHttps");
});
var metadata = app.Services.GetRequiredService<ServiceMetadataBehavior>();
metadata.HttpGetEnabled = true;
app.Run();Authorization moved to ASP.NET Core as well. An operation can carry the ASP.NET Core [Authorize] attribute with a policy, and the service calls HttpContext.AuthenticateAsync() with the default scheme when the binding’s client credential type is InheritedFromHost. In that mode a ServiceAuthorizationManager no longer runs, Roles and AuthenticationSchemes on the attribute are not supported, and [AllowAnonymous] has no effect; the build warns about each.
Because CoreWCF runs on .NET Framework 4.6.2 and above, the host can change first and the runtime later. The road map describes this as the intended path: move the service to CoreWCF while it still runs on .NET Framework, then port the rest.
gRPC
Microsoft’s e-book for WCF developers walks through the conversion. A [ServiceContract] becomes a service in a .proto file and a [DataContract] a message. The properties of OperationContract mostly fall away: Name and ReplyAction are SOAP concepts with no meaning in gRPC, ProtectionLevel has no counterpart because there is no message encryption, and IsInitiating and IsTerminating give way to streams that one method opens and closes. A callback contract becomes a server stream and a full-duplex service a bidirectional stream. The book compares the bindings one by one: NetTCP gives persistent connections and small messages between .NET endpoints, gRPC does the same over HTTP/2 for any language; BasicHttpBinding carries SOAP text, gRPC carries Protobuf; an MSMQ binding has no gRPC counterpart, and the book points to a message broker instead; a WebHttpBinding service is better moved to an ASP.NET Core Web API than to gRPC.
The book also lists what gRPC does not have: WS-Security, WS-Federation and XML Encryption; WS-ReliableMessaging, where retries move into code; and distributed transactions, which it covers in an appendix on why two-phase commit does not fit services on mixed platforms. Security is TLS on the connection, with X.509 client certificates for mutual authentication. WSDL is replaced by the shared .proto file; a server reflection extension exists for dynamic discovery.
The ASP.NET Core documentation adds that a browser cannot call a gRPC service directly; gRPC-Web or JSON transcoding fills that gap. For processes on one machine, gRPC on ASP.NET Core works over Unix domain sockets and named pipes, which covers what NetNamedPipeBinding did.
Every gRPC client is generated from the .proto file. A SOAP client that you do not control cannot call the new service, so this path assumes you can change, or replace, every client.
Web API
An ASP.NET Core Web API answers JSON over HTTP, and that is what Microsoft recommends for a WebHttpBinding service. For a service that is called from browsers or from code in other languages it is the plainest target. It is also the one with the least in common with a SOAP contract: the operations, the faults and the client proxies are all redesigned, and an existing SOAP client cannot use it.
Leave the service where it is
The fourth option is to port the rest of the application and leave the service on .NET Framework for now. The WCF client packages exist for this case: the readme names “mid-tier servers that talk to existing WCF services” as a target. Microsoft’s feature list for the client marks BasicHttpBinding, NetHttpBinding, NetTcpBinding and CustomBinding as working on Windows, Linux and macOS, with request/reply, duplex, buffered and streamed transfers, and transport security. It marks message security and WebHttpBinding as not supported, and NTLM as Windows only. A client on .NET 8 or 10 reaches a basicHttp or netTcp endpoint on .NET Framework without the service changing. This works as a first step when the service is the only thing holding back the port, and settles nothing when the service itself is the reason for the port.
Clients
dotnet-svcutil is the .NET version of svcutil. It is installed with dotnet tool install --global dotnet-svcutil, reads the metadata from a running service or a WSDL file, writes ServiceReference/Reference.cs with a class derived from ClientBase, and adds the WCF packages the proxy needs to the project. dotnet-svcutil -u regenerates the proxy after the service changes. Visual Studio offers the same through “Add Service Reference” with the “WCF Web Service” type.
There is no app.config for the client on .NET. The 8.0 release of the client packages lists the removal of the configuration API, and the generated proxy takes the endpoint in code: the walkthrough creates it with new EchoServiceClient(EchoServiceClient.EndpointConfiguration.WSHttpBinding_IEchoService, "https://..."). Bindings and credentials that lived in system.serviceModel are set on the binding and the client object.
What usually hurts on the server side
web.configwith a longsystem.serviceModelsection. Either keep the file and load it throughCoreWCF.ConfigurationManager, or translate it into binding objects inProgram.cs. Custom behaviors declared there need the code path.- IIS hosting through a
.svcfile. The service becomes an ASP.NET Core application, and the deployment changes with it. - Windows authentication and other credentials. They move to ASP.NET Core authentication; the binding’s credential type becomes
InheritedFromHostand policies replaceServiceAuthorizationManager. - Message security beyond transport with message credential. Not in CoreWCF and not in gRPC. A client that signs or encrypts SOAP at message level needs the service to stay on .NET Framework until that client changes.
OperationContext, behaviors and message inspectors. The road map says most of them need only a namespace change; the ones that reach into the HTTP layer are the ones to test first.- Transactions flowing over WS-AtomicTransaction. Not in CoreWCF, and the gRPC e-book explains why nothing replaces them.
- MSMQ. CoreWCF has a package for it; gRPC has no queue at all.
- Workflow Services and the Routing Service. Workflow Foundation is not in .NET; for routing we found no CoreWCF implementation.
How to assess your own services
Make a list before you pick a target. For each service: its bindings and security mode as configured in web.config, who calls it (your own .NET code, other teams, Java or other SOAP clients, browsers), and whether those callers can be changed on your schedule. Then check every row against the table: a service whose callers you cannot touch has to keep its contract, which means CoreWCF, or staying on .NET Framework for now. A service whose only callers are your own code can take any of the three. If you would rather have us go through the list with you, the migration service starts with a free check.
Not sure which option fits your services?
Send us the list of projects, or a description of the application, and we answer by email with what blocks the port and what we would propose for each service. The check is free and does not commit you to anything.
If you then want us to do the work, we agree a fixed price for an agreed scope, by email.
- What does the application do and who uses it?
- Which .NET Framework version and project types (ASP.NET MVC, Web Forms, WCF, Windows service, WinForms/WPF)?
- Which third-party packages or components does it depend on?
- What is the goal: .NET 8/10 on Windows, Linux, containers, cloud?
| In WCF | CoreWCF | gRPC or Web API |
|---|---|---|
| BasicHttpBinding | Yes (CoreWCF.Http) | gRPC over HTTP/2, or a Web API; clients are regenerated |
| WSHttpBinding, WS2007HttpBinding | Yes; transport security and transport with message credential | No WS-* protocols; TLS on the connection |
| NetTcpBinding | Yes (CoreWCF.NetTcp) | gRPC over HTTP/2 |
| NetNamedPipeBinding | Yes (CoreWCF.NetNamedPipe) | gRPC over named pipes or Unix domain sockets |
| WebHttpBinding (WCF REST) | Yes (CoreWCF.WebHttp) | ASP.NET Core Web API |
| NetMsmqBinding | CoreWCF.MSMQ package | None; a message broker instead |
| Message security (WS-Security) | Not implemented beyond transport with message credential | Not in gRPC |
| Windows authentication | Through ASP.NET Core authentication | Through ASP.NET Core authentication |
| WSDL and metadata | Yes, HttpGetEnabled | Shared .proto file; server reflection |
| Callback contracts, duplex | Listed as done in the feature thread | Server and bidirectional streaming |
| WS-AtomicTransaction | Not implemented | None |
| WS-ReliableMessaging | In progress in the feature thread | None; retries in code |
| Workflow Services | No; Workflow Foundation is not in .NET | No |
| Routing Service | None found | None |
Sources
- Microsoft Learn: why migrate WCF to ASP.NET Core gRPC ↗
- Microsoft Learn: .NET Framework technologies unavailable on .NET 6+ ↗
- Microsoft Learn: compare gRPC services with HTTP APIs ↗
- Microsoft, e-book “ASP.NET Core gRPC for WCF developers” (PDF) ↗
- Microsoft, “CoreWCF 1.0 has been Released”, .NET blog ↗
- CoreWCF repository and package list ↗
- CoreWCF, getting started walkthrough ↗
- CoreWCF, release road map ↗
- CoreWCF, Microsoft support policy ↗
- CoreWCF releases ↗
- CoreWCF blog: 1.0.0 release ↗
- CoreWCF blog: WSDL support ↗
- CoreWCF blog: ASP.NET Core authorization support ↗
- CoreWCF blog: Unix domain socket binding ↗
- CoreWCF source: ConfigurationManagerExtensions.cs ↗
- CoreWCF, feature request thread (issue 234) ↗
- dotnet/wcf: the WCF client libraries for .NET ↗
- dotnet/wcf: supported features of the client ↗
- dotnet/wcf: release 8.0.0 ↗
- Microsoft Learn: dotnet-svcutil ↗