gRPC + ASP.NET Core as a Migration Path for WCFs in .NET Core

Developer Support

App Dev Manager Keith Anderson and Field Engineer Patricio Belardo explore gRPC + ASP.NET Core as a migration path for WCF.

Overview

A recent statement from Microsoft’s Director of Program Management for .NET, Scott Hunter, regarding roadmap for .NET Core clarified the direction of Windows Communication Foundation (WCF) Services.

In his blog, Scott says, “After .NET Core 3.0 we will not port any more features from .NET Framework.” He also says, “If you are a remoting or WCF Server developer and want to build a new application on .NET Core, we would recommend either ASP.NET Core Web APIs or gRPC,…”

WCF had its faults, but it was clearly a wildly successful technology, as evidenced by the large library of services still in use.

The intended audience for this blog post is one who wants to migrate from the full .NET Framework to .NET Core and has a large library of WCFs, now considered technical debt, blocking the path to adoption.

This post will attempt to at least partially answer the question: How difficult will it be to migrate my current code base of WCFs to gRPC in .NET Core?

Comparison of WCF and GRPC

Whether or not gRPC is a viable migration path for your WCF services depends on how you are using WCF. GRPC is not a direct analog to WCF.

I haven’t seen a feature comparison matrix yet, so I thought I would take a stab at one.

Feature WCF ASP.Net Core + gRPC
Platforms Windows Windows, Linux, MacOS
Protocols LRPC/Named Pipes/HTTP/TCP/MSMQ Binary (GRPC) + HTTP2

(TCP/Named Pipes/LRPC)

.AddProtocol(“ncacn_ip_tcp”, “8080”)

.AddProtocol(“ncacn_np”, @”\pipe\MyService”)

.AddProtocol(“ncalrpc”, “MyService”)

By removing the ASP.NET Core stack and just using .NET Core

Injected Aspects Behaviors ASP.NET Core DI Middleware/ gRPC interceptors
Distributed Transactions *Yes – [TransactionFlow], transactionscopes, and supported bindings *No
Transport Security SSL/TLS SSL/TLS
Message Security Certificates/credentials Certificates/credentials

https://docs.microsoft.com/en-us/aspnet/core/grpc/authn-and-authz?view=aspnetcore-3.0

Windows Authentication Kerberos/NTLM AAD Sync/ASFS + ASP.NET Core middleware
Proxies/Contracts Service Contracts/Data Contracts Protocol Buffers
Proxy-less Communication WCF Channel Factory † Protobuf-Net.GRPC

*See Transactions below †This is a 3rd party library and is not the solution formally supported by Microsoft.

Transactions

Just because you can do something, doesn’t mean you should, and in general, distributing database transactions across service calls is an anti-pattern to avoid. This was allowed in WCF, in situations where you had a client orchestrating calls to different services that each participated in part of a single atomic unit of work. All you needed was an ambient transaction scope and a binding that supported distributed transactions (NetNamedPipeBinding, NetTCPBinding, WSHttpBinding, etc.).

GRPC on the other hand, is just a communication channel and protocol. It does not concern itself with transactions at all.

If you cannot collect all of your database commits that constitute a unit of work in a single transaction, you may be forced to implement the compensating transaction pattern:

https://docs.microsoft.com/en-us/azure/architecture/patterns/compensating-transaction

This is anyway required for non-homogenous data repositories or data repositories that do not implement transaction coordination.

WCF distributed transactions will also not currently work with elastic transactions in the cloud, as .NET Core does not support them at the time of this writing. The full .NET Framework is required to implement elastic transactions and are limited to SQL Server as a Service in Azure. On premises or SQL Server in IaaS still requires the DTC.

Proxies/Contracts

WCF developers familiar with contract definitions should find gRPC protocol buffers to be the analogous construct serving the same purpose. The following shows an example of a WCF contract and a possible analogous protocol buffer:

namespace Weather {

    [ServiceContract]
    public interface IWeatherService {
        [OperationContract]
        WeatherResponse SendTheWeather(WeatherRequest p1);
    }

    // The request message containing the date for the request.
    [DataContract]
    public class WeatherRequest {
        [DataMember]
        DateTime Date { get; set; }
    }

    public class WeatherData {
        DateTime Date { get; set; }
        int TemperatureC { get; set; }
        int TemperatureF { get; set; }
        string Summary { get; set; }
    }

    // The response message containing the weather collection.
    [DataContract]
    public class WeatherResponse {
        [DataMember]
        Collection<WeatherData> WeatherForcast { get; set; }
    }

} 
syntax = "proto3";
 
package Weather;
 
// The request message containing the date for the request.
message WeatherRequest {
 string Date = 1;
}
 
// The response message containing the weather.
message WeatherData {
 string Date = 1;
 int32 TemperatureC = 2;
 int32 TemperatureF = 3; 
 string Summary = 4; 
}
 
message WeatherResponse {
 repeated WeatherData WeatherForcast = 1;
}
 
service WeatherService {
  // Sends the weather
  rpc SendTheWeather (WeatherRequest) returns (WeatherResponse) {}
}
 
message ErrorResult {
  string error_text = 536870911; //max field-id
}

For more information about protocol buffers, see the Protocol Buffer Language Guide: https://developers.google.com/protocol-buffers/docs/proto3

As you can see, this takes some re-writing and refactoring. The auto-generated classes need to be shared between server and client. They can be centralized and isolated for sharing to minimize the impact, but it is still impactful on developer time if you have a large library of WCFs to migrate.

Another option is to use the protobuf-net.grpc libraries which allow you to use the same declarative attributes as WCF contracts. This currently is not the formally supported method of creating GRPC services in .NET Core, though the protobuf-net.grpc library is a well-maintained 3rd party open-source project with close ties to the .NET Core team.

namespace Contracts {

    [ServiceContract]
    public interface ISampleService {
        [OperationContract]
        Task<DoResponse> DoAsync(DoRequest request);
    }

    [DataContract]
    public class DoRequest {
        [DataMember(Order = 1)]
        public List<Shape> Shapes { get; set; }
    }

    [DataContract]
    public class DoResponse {
        [DataMember(Order = 1)]
        public bool IsSuccess { get; set; }
    }

    //Protoinclude is part of protobuf-net implementation and will allow to include derived classes
    [DataContract, ProtoInclude(4, typeof(Circle))]
    public abstract class Shape {
        public int S1 { get; set; }
        public int S2 { get; set; }
    }

    [DataContract]
    public class Circle : Shape {
        public int C1 { get; set; }
        public int C2 { get; set; }
    }
}

As you can see, if you had a WCF contract that looked like this, you could adopt a gRPC implementation through the protobuf-net.grpc library with no change to your code base.

Also, with WCF services, it was not necessary to generate a proxy class. Your client could use a ChannelFactory and the service definition itself to invoke the service. Using protobuf-net.grpc, this becomes the natural way to invoke the service, since you are sharing only the service contract definition.

Conclusion

By no means was this intended to be a comprehensive guide or step-by-step tutorial on migrating from WCF to gRPC+ASP.NET Core, but rather for the architect with large WCF technical debt, trying to decide what impact a migration might have to appropriately prioritize the work with upcoming projects, the hints that have been given should help provide a path forward.

There are analogs in an ASP.NET Core + gRPC solution to many, if not most of what WCF provides. For instance, gRPC interceptors or ASP.NET Core dependency injection can add the same functionality as custom WCF Service Behaviors.

If the codebase in question leverages the most common features of WCF and doesn’t stray too far into platform specific territory, and you are ok with introducing 3rd party open-source projects into your solution, it may be possible to migrate the entire codebase with minimal coding and just a few reference changes and recompilation.

References/Additional Reading

0 comments

Discussion is closed.

Feedback usabilla icon