If you are looking to use SOAP or WCF with ASP.NET Core, you are not alone. It is one of the most searched for and requested features for .NET Core. In this article, we will discuss how to consume a WCF SOAP service from your .NET Core application. We also show how to create and host a SOAP service with ASP.NET Core.
To start, let’s give a little background as to what SOAP is.
The Simple Object Access Protocol (SOAP) is a protocol specification for exchanging structured information across distributed and possibly heterogeneous systems. It uses XML as its message format and relies on application layer protocols such as HTTP. Most people know it as the default protocol for web services.
Up until not too long ago, SOAP was the de facto standard for writing web services, and the Service Oriented Architecture (SOA) depended heavily on it. SOAP defines a message format that should be followed but inside of it we are free to add whatever we like – it is even possible to include binary attachments.
The SOAP specification defines a containing envelope (<envelope>), and inside it, we can have a header (<header>) and a body (<body>) and the body can include a fault section (<fault>) together with other subsections. Only <body> is mandatory, and <fault> is only used for responses, not requests, where an error occurred.
Extensions to SOAP include the ability to include chunks of binary content in the middle of a message; it is called Message Transmission Optimization Mechanism (MTOM), an alternative to using Base-64 to encode the binary streams, which typically makes it 30% larger.
When invoking web services, the body must include the action to be called on the web service as well as any possible arguments. SOAP web services always use POST and submit the envelope as the payload to a single well-known URL. The web service framework will direct the request to some class and method on the system.
A web service makes available a Web Services Definition Language (WSDL) file where the details about the service are described: the name of each action method, the parameters and return values of each, and what faults are expectable. From this WSDL, Visual Studio (and other tools, such as the SVCUtil.exe command line utility) can generate code proxies that can interact with the web service.
There are some specifications, known collectively as WS-* (WS-star), which include WS-Policy, WS-Addressing, WS-Trust, WS-SecureConversation, WS-Transaction and a few others. These are key to providing enterprise-level functionality to web services; mind you, these standards are platform-independent, meaning, for example, a web service that implements WS-Transaction can be part of a distributed transaction across heterogeneous systems.
There’s another player, not exactly new, which is the Representational State Transfer (REST). It’s technically not a protocol, but rather a style. With REST, we embrace the HTTP protocol in its entirety, including:
REST is not a specification, and therefore there is no mandatory message format, but JSON is quite often the choice, although XML is not uncommon too. Some implementations allow negotiating the content to expect. But REST is no silver bullet, and, specifically, it leaves out, among others:
Currently, REST is commonly used for simple request-response calls using JSON, including AJAX-style calls. It lacks the specifications and complexity that WCF and SOAP offers, but is great for simple use cases.
You can easily create REST APIs with ASP.NET Core MVC. Learn more about SOAP vs REST.
In the days before.NET Core, starting with .NET/ASP.NET 1.1, we had XML Web Services as of 2001. It was part of the ASP.NET framework, and it provided an easy, although limited, way to create web methods. Many things were missing, such as security features, but it built on top of ASP.NET so it benefited inherently from it.
Realizing this, Microsoft released the Web Services Enhancements (WSE) package in 2002, based on a draft version of the WS-Security protocol. Two versions followed, consolidating the implementation of WS-Security and introducing WS-Policy, WS-Addressing, WS-Trust and WS-SecureConversation support as well as Message Transmission Optimization Mechanism (MTOM), a performance-friendly way to transmit binary contents.
Then came WCF. It was touted as the “one ring” of web services, the one that would rule them all. The ABC acronym, – Address, Binding, and Contract – says it all: give us a contract and a binding and we can call any address!
It was, indeed, highly customizable, with bindings that allowed it to interoperate with other technologies while offering a high-performance binary format for Windows-only communication, the ability to talk directly to Microsoft Message Queue (MSMQ), local-mode inter-process communication (IPC) and even disconnected UDP.
Just think about this: using the same interface and just switching some configuration settings you can communicate with totally different services, not necessarily WCF on both endpoints.
From the start, it included extensibility at various levels through the use of behaviors, instance management and throttling, different layers of security and duplex channels; subsequent releases introduced service discoverability and routing and REST eventually also dropped by.
WCF was Microsoft’s flagship technology for implementing web services, be it SOAP, REST or whatever you would like.
WCF is an enterprise solution that can support a wide array of complex requirements. This complexity is why it hasn’t been ported to .NET Core (yet, anyway).
Then came .NET Core and the story changed: WCF was not here, or, to be precise, there was no server-side WCF, only client-side, meaning, you could write a WCF proxy to access aSOAP or REST web services, but you could not implement one.
WCF is one of the most requested features, and there is an open discussion in WCF’s GitHub repository about this: https://github.com/dotnet/wcf/issues/1200. Microsoft recently made recently available an online survey asking the developer community to express their views about this, and, namely, what do they consider the more important features of WCF; it is available here: https://www.research.net/r/GitWCF, do sound your voice there.
So, if you want to use WCF on the client side with .NET Core, you can certainly do so. First, make sure you add the System.ServiceModel.Primitives and one of System.ServiceModel.Http (for the BasicHttpBinding/BasicHttpsBinding or NetHttpBinding/NetHttpsBinding bindings, which includes SOAP and REST) or System.ServiceModel.NetTcp (for NetTcpBinding, a Windows-only binary protocol). Absent are named pipes, MSMQ and support for the WS-* specs.
A simple example is in order, first, the contract:
[ServiceContract] public interface IPingService { [OperationContract] string Ping(string msg); }
Then, the client code:
var binding = new BasicHttpBinding(); var endpoint = new EndpointAddress(new Uri("http://server/PingService.svc")); var channelFactory = new ChannelFactory(binding, endpoint); var serviceClient = channelFactory.CreateChannel(); var result = serviceClient.Ping("Ping"); channelFactory.Close();
As you can see, nothing different to what you would do in the full .NET framework. Of course, there is no App.config or Web.config files, so you need to configure things manually, like creating the appropriate binding and endpoint address.
You can also use svcutil.exe manually to generate proxy classes for you that will work with .NET Core.
However, if you think about it, SOAP is not that complex, and, also, ASP.NET Core is very easy to extend.
[adinserter block=”33″]
Microsoft wrote a blog post about implementing a middleware component capable of handling SOAP requests.
The example is very clear and informative and is a pleasant read, and Digital Design must have thought the same, because they made available on GitHub a fully functional (and extended) version of the blog’s sample code, which you can find here: https://github.com/DigDes/SoapCore.
Because we live in the age of NuGet, a package is also available; it’s called SoapCore.
By using SoapCore on top of ASP.NET Core, you can benefit from all the ASP.NET Core goodies, such as routing and filters.
As an example, for the client-side, you can use pretty much the same class as I showed before. For the server end, you will need to write a service class that implements the contract:
public class SampleService : IPingService { public string Ping(string msg) { return string.Join(string.Empty, msg.Reverse()); } }
And we just need to register the service implementation under a well-known address:
public void ConfigureServices(IServiceCollection services) { services.AddSingleton(new PingService()); services.AddMvc(); //rest goes here } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseSoapEndpoint(path: "/PingService.svc", binding: new BasicHttpBinding()); app.UseMvc(); //rest goes here }
If you are interested, you can add a custom exception-to-string transformer, if you do, you can extract a meaningful message from any exception that should occur and return it to the client as a fault string:
services.AddSoapExceptionTransformer((ex) => ex.Message);
What the code does is inject a custom middleware to the ASP.NET Core pipeline which listens to HTTP POSTs, checks if the proper headers are present and extracts the action method and its parameters from the payload, which then forwards to the given implementation class.
A couple of notes:
Even though you can surely use this code for backward compatibility, in the case where you need to have a SOAP service written in .NET Core (for example, if you need to deploy it to Docker), be aware of its limitations:
Convenient as this SoapCore package may be, it’s still a long way from the full WCF that we had back in .NET framework. Since part of the work is done, you can consider contributing to it or rolling out your own, in the case that you need to write SOAP services. Be aware of the challenges involved, as things can get complex, especially if you need to support any of the WS-* protocols.
Probably better to wait for Microsoft to implement the remaining parts of WCF for .NET Core, and here you can make yourself heard, either by joining the discussion in the WCF repository or by answering the survey.
Remember to also have a full lifecycle APM in place so that you can catch issues early and often. Stackify Retrace offers a free trial.
If you would like to be a guest contributor to the Stackify blog please reach out to [email protected]