Skip to main content

.NET SOAP Services

Introduction

SOAP (Simple Object Access Protocol) is a protocol specification for exchanging structured information in web services using XML. In the .NET ecosystem, SOAP services have been a cornerstone for building distributed applications that need to communicate across platforms and programming languages.

Although REST has become more popular in recent years, SOAP services remain relevant in enterprise environments, especially where formal contracts, security, and reliability are critical concerns. .NET provides robust tools for both creating and consuming SOAP services.

In this guide, we'll explore:

  • What SOAP services are and how they work
  • Creating SOAP services using .NET
  • Consuming SOAP services from .NET applications
  • Best practices and common patterns

What are SOAP Services?

SOAP is a messaging protocol that allows programs running on different operating systems to communicate using HTTP and XML. A SOAP message is an XML document containing:

  1. Envelope: The root element that identifies the XML document as a SOAP message
  2. Header (optional): Contains metadata about the message
  3. Body: Contains the actual message data
  4. Fault (optional): Contains error and status information

Here's a simple example of a SOAP message:

xml
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<m:TransactionID xmlns:m="http://example.org/transaction">
12345
</m:TransactionID>
</soap:Header>
<soap:Body>
<m:GetStockPrice xmlns:m="http://example.org/stock">
<m:StockName>Microsoft</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>

Key Characteristics of SOAP Services

  • Platform Independence: Works across different operating systems
  • Language Independence: Can be consumed by applications written in any programming language
  • Standardized: Based on established W3C standards
  • Built-in Error Handling: Through the Fault mechanism
  • Extensibility: Through the Header element
  • Transport Protocol Independence: Though typically used over HTTP, can work with SMTP, TCP, etc.

SOAP Service Technologies in .NET

Over the years, .NET has offered different ways to implement SOAP services:

  1. ASMX Web Services: The original technology in .NET for building SOAP services (legacy)
  2. Windows Communication Foundation (WCF): A unified framework for building service-oriented applications
  3. CoreWCF: An open-source implementation of WCF for .NET Core and .NET 5+ applications

Let's explore each approach:

Creating a SOAP Service with ASMX (Legacy)

While ASMX is considered legacy technology, understanding it helps grasp the fundamental concepts of SOAP services.

Step 1: Create an ASMX Web Service

csharp
// CalculatorService.asmx.cs
using System;
using System.Web.Services;

namespace MyWebServices
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CalculatorService : WebService
{
[WebMethod]
public int Add(int a, int b)
{
return a + b;
}

[WebMethod]
public int Subtract(int a, int b)
{
return a - b;
}
}
}

The [WebMethod] attribute marks methods that should be exposed as SOAP operations.

Step 2: Deploy and Access the Service

After deploying to IIS, you can access the service at http://yourserver/CalculatorService.asmx. This provides a web page that lists all operations and allows testing them directly from the browser.

Creating a SOAP Service with WCF

Windows Communication Foundation (WCF) provides a more flexible and feature-rich way to create SOAP services.

Step 1: Define a Service Contract

csharp
using System.ServiceModel;

namespace MyWcfService
{
// Define the service contract
[ServiceContract(Namespace = "http://example.org/calculator")]
public interface ICalculatorService
{
[OperationContract]
int Add(int a, int b);

[OperationContract]
int Subtract(int a, int b);
}
}

Step 2: Implement the Service

csharp
namespace MyWcfService
{
// Implement the service contract
public class CalculatorService : ICalculatorService
{
public int Add(int a, int b)
{
return a + b;
}

public int Subtract(int a, int b)
{
return a - b;
}
}
}

Step 3: Configure the Service

In your web.config or app.config file:

xml
<configuration>
<system.serviceModel>
<services>
<service name="MyWcfService.CalculatorService">
<endpoint
address=""
binding="basicHttpBinding"
contract="MyWcfService.ICalculatorService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

Step 4: Host the Service

In a console application:

csharp
using System;
using System.ServiceModel;

namespace MyWcfHost
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(MyWcfService.CalculatorService)))
{
host.Open();
Console.WriteLine("Service is running...");
Console.WriteLine("Press any key to stop the service.");
Console.ReadKey();
host.Close();
}
}
}
}

Or in IIS through a .svc file.

Creating a SOAP Service with CoreWCF (.NET Core and .NET 5+)

CoreWCF is an open-source project that brings WCF programming model to .NET Core and newer versions.

Step 1: Install the Required Packages

bash
dotnet add package CoreWCF.Primitives
dotnet add package CoreWCF.Http

Step 2: Define and Implement the Service (similar to WCF)

csharp
using CoreWCF;

namespace MyService
{
[ServiceContract]
public interface ICalculatorService
{
[OperationContract]
int Add(int a, int b);

[OperationContract]
int Subtract(int a, int b);
}

public class CalculatorService : ICalculatorService
{
public int Add(int a, int b)
{
return a + b;
}

public int Subtract(int a, int b)
{
return a - b;
}
}
}

Step 3: Configure and Host the Service in ASP.NET Core

csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using CoreWCF.Configuration;
using CoreWCF.Description;

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddServiceModelServices();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseServiceModel(builder =>
{
builder.AddService<CalculatorService>();
builder.AddServiceEndpoint<CalculatorService, ICalculatorService>(
new CoreWCF.BasicHttpBinding(), "/CalculatorService");

var serviceMetadataBehavior = app.ApplicationServices.GetRequiredService<ServiceMetadataBehavior>();
serviceMetadataBehavior.HttpGetEnabled = true;
});
}
}

Consuming SOAP Services in .NET

There are multiple ways to consume SOAP services in .NET applications.

Method 1: Using Service Reference

In Visual Studio:

  1. Right-click on the project and select "Add > Service Reference"
  2. Enter the URL of the WSDL (Web Service Description Language) document
  3. Click "Go" and then "OK" to generate the client code

Method 2: Using svcutil.exe (WCF) or dotnet-svcutil (.NET Core)

Generate client code from a WSDL:

bash
# For .NET Framework
svcutil.exe http://example.org/calculator?wsdl

# For .NET Core
dotnet tool install --global dotnet-svcutil
dotnet-svcutil http://example.org/calculator?wsdl

Method 3: Using the Client Code

After generating the client proxy:

csharp
// For ASMX
using (var calculatorClient = new CalculatorServiceSoapClient())
{
int result = calculatorClient.Add(5, 10);
Console.WriteLine($"5 + 10 = {result}"); // Output: 5 + 10 = 15
}

// For WCF
using (var calculatorClient = new CalculatorServiceClient())
{
int result = calculatorClient.Add(5, 10);
Console.WriteLine($"5 + 10 = {result}"); // Output: 5 + 10 = 15
}

Real-World Example: Weather Service

Let's build a more practical example – a weather service that provides weather forecasts for cities.

Step 1: Define the Service Contract

csharp
using System.ServiceModel;

namespace WeatherService
{
[ServiceContract]
public interface IWeatherService
{
[OperationContract]
WeatherInfo GetCurrentWeather(string cityName);

[OperationContract]
WeatherForecast[] GetFiveDayForecast(string cityName);
}

// Data contracts define the data structures that will be serialized
[DataContract]
public class WeatherInfo
{
[DataMember]
public string City { get; set; }

[DataMember]
public double Temperature { get; set; }

[DataMember]
public string Condition { get; set; }

[DataMember]
public int Humidity { get; set; }
}

[DataContract]
public class WeatherForecast
{
[DataMember]
public DateTime Date { get; set; }

[DataMember]
public double MaxTemperature { get; set; }

[DataMember]
public double MinTemperature { get; set; }

[DataMember]
public string Condition { get; set; }
}
}

Step 2: Implement the Service

csharp
namespace WeatherService
{
public class WeatherService : IWeatherService
{
public WeatherInfo GetCurrentWeather(string cityName)
{
// In a real application, this would call a weather API or database
// This is a simplified mock implementation

return new WeatherInfo
{
City = cityName,
Temperature = 22.5, // Celsius
Condition = "Partly Cloudy",
Humidity = 65
};
}

public WeatherForecast[] GetFiveDayForecast(string cityName)
{
// Mock implementation
var forecasts = new WeatherForecast[5];
var random = new Random();

for (int i = 0; i < 5; i++)
{
forecasts[i] = new WeatherForecast
{
Date = DateTime.Today.AddDays(i + 1),
MaxTemperature = 20 + random.Next(10),
MinTemperature = 10 + random.Next(5),
Condition = i % 2 == 0 ? "Sunny" : "Partly Cloudy"
};
}

return forecasts;
}
}
}

Step 3: Consume the Weather Service

csharp
using (var weatherClient = new WeatherServiceClient())
{
// Get current weather
WeatherInfo currentWeather = weatherClient.GetCurrentWeather("New York");

Console.WriteLine($"Current weather in {currentWeather.City}:");
Console.WriteLine($"Temperature: {currentWeather.Temperature}°C");
Console.WriteLine($"Condition: {currentWeather.Condition}");
Console.WriteLine($"Humidity: {currentWeather.Humidity}%");

// Get 5-day forecast
WeatherForecast[] forecast = weatherClient.GetFiveDayForecast("New York");

Console.WriteLine("\n5-day forecast:");
foreach (var day in forecast)
{
Console.WriteLine($"{day.Date.ToShortDateString()}: {day.Condition}, " +
$"{day.MinTemperature}°C - {day.MaxTemperature}°C");
}
}

Output:

Current weather in New York:
Temperature: 22.5°C
Condition: Partly Cloudy
Humidity: 65%

5-day forecast:
6/15/2023: Sunny, 12.5°C - 25.7°C
6/16/2023: Partly Cloudy, 11.2°C - 22.8°C
6/17/2023: Sunny, 13.8°C - 27.3°C
6/18/2023: Partly Cloudy, 10.5°C - 23.9°C
6/19/2023: Sunny, 14.2°C - 26.1°C

Best Practices for SOAP Services in .NET

  1. Use Data Contracts: Always define proper data contracts with the [DataContract] and [DataMember] attributes.

  2. Error Handling: Implement proper error handling using FaultContract:

    csharp
    [ServiceContract]
    public interface ICalculatorService
    {
    [OperationContract]
    [FaultContract(typeof(CalculationFault))]
    int Divide(int a, int b);
    }

    [DataContract]
    public class CalculationFault
    {
    [DataMember]
    public string Message { get; set; }
    }
  3. Version Your Services: Use proper namespaces and consider versioning strategies.

  4. Security: Use appropriate security measures like transport security (HTTPS) or message security (WS-Security).

  5. Performance: Be mindful of the size of SOAP messages and consider compression for large payloads.

  6. Testing: Use tools like SoapUI or Postman to test your SOAP services.

  7. Documentation: Generate and maintain WSDL documentation for your services.

SOAP vs REST: When to Choose SOAP

While REST is often preferred for its simplicity, SOAP might be a better choice in scenarios like:

  1. Enterprise Integration: Where formal contracts are required
  2. Stateful Operations: For services that need to maintain state
  3. Security Requirements: When advanced security features are needed
  4. Reliability: When guaranteed message delivery is critical
  5. Transaction Support: For operations that need ACID transactions

Summary

SOAP services in .NET provide a robust way to build interoperable web services with features like strong typing, security, and reliability. While the technologies have evolved from ASMX to WCF and now CoreWCF for modern .NET applications, the fundamental principles remain consistent.

By understanding how to create, deploy, and consume SOAP services, you can build distributed applications that communicate across platforms and programming languages, especially in enterprise environments where SOAP's features align with business requirements.

Exercises

  1. Create a simple calculator SOAP service with addition, subtraction, multiplication, and division operations.
  2. Extend the weather service example to include additional data like wind speed and pressure.
  3. Implement error handling in the division operation to return a fault when dividing by zero.
  4. Create a client application that consumes a public SOAP web service (many financial and weather services still offer SOAP APIs).
  5. Compare the same service implemented in both SOAP and REST, analyzing the differences in message size, complexity, and ease of use.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)