Windows Communication Foundation (WCF)
WCF is a abstraction over multiple protocol. It enable interoperability to C#, but also Java (with SOAP). While services are rarely written, how to invoke a service can be expected. Additionally, contracts will come at the SEP.
How to design Enterprise Software
- Separation of Concern

- Assignment to Tier-"Role"

- Separation of Shared Services

The following diagram shows a more fine-grain view onto the layers. The years are the average lifespan of the layer. This also shows where to focus effort.

CAP Theorem

The CAP theorem says that of the three properties of a DB (consistency, partitioning, availability), two have to be picked.
Finanical services require hard consistency, meaning that consistency is the most important property. On the other hand, companies like google or amazon are fine with eventual consistency.

WCF
WCF's preferred protocol is SOAP, but can also be run over https, TCP, etc.
Hello WCF
First an interface needs to be created, which defines the ServiceContract.
using CoreWCF;
namespace LibraryServiceSolution {
[ServiceContract]
interface ILibraryService {
[OperationContract]
Book? SearchBook(string bookName);
[OperationContract]
IList<Book> AllBooks();
}
}
Similar to DTOs, a DataContract defines the data structure:
using System.ServiceModel;
namespace LibraryServiceSolution {
[DataContract]
pubilc class Book {
[DataMember]
public int ID {get; set; }
[DataMember]
public string? Name {get; set}
}
}
Then a Service class is needed:
namespace LibraryServiceSolution {
public class LibraryService : ILibraryService
{
private List<Book> books;
public LibraryService() {
books = new List<Book>();
for (int i = 0; i < 10; ++i) {
books.Add(new Book { ID = i, Name = "Name " + i });
}
}
public Book? SearchBook(string? bookName) {
return books.Find(w => w.Name == bookName);
}
public IList<Book> AllBooks() {
return books;
}
}
}
To then host this server, we also need a ServiceHost class:
using CoreWCF;
using CoreWCF.Configuration;
using CoreWCF.Description;
using LibraryServiceSolution;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, options) => {
options.AllowSynchronousIO = true;
});
// Add WSDL support
builder.Services.AddServiceModelServices().AddServiceModelMetadata();
builder.Services.AddSingleton<IServiceBehavior, UseRequestHeadersForMetadataAddressBehavior>();
var app = builder.Build();
app.UseServiceModel(builder => {
builder.AddService<LibraryService>((serviceOptions) => { })
.AddServiceEndpoint<LibraryService, ILibraryService>(new BasicHttpBinding(),
"/LibraryService/basichttp")
.AddServiceEndpoint<LibraryService, ILibraryService>(new WSHttpBinding(SecurityMode.Transport),
"/LibraryService/WSHttps");
});
var serviceMetadataBehavior = app.Services.GetRequiredService<ServiceMetadataBehavior>();
serviceMetadataBehavior.HttpGetEnabled = true;
app.Logger.LogInformation("Starting Library Solution ...");
app.Run();
Furthermore, in the appsettings.json, the following needs to be configured:
{
"Urls": "http://localhost:5000;https://localhost:5001",
"Logging": {
"LogLevel": {
"Default": "Information",
"CoreWCF.Channels": "Warning",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
The service can be accessed via the browser. For example, in this case http://localhost:5000/LibraryService/basichttp
Use it in C# (Client Proxy)
This can be used in .NET, a client proxy can be generated by VisualStudio. Those can then be used in code:
using ServiceReference1;
var client = new LibraryServiceClient(
LibraryServiceClient.EndpointConfiguration.WSHttpBinding_ILibraryService);
var book = await client.SearchBookAsync("Name 1");
Console.WriteLine(book.ID+" "+book.Name);
var books = client.AllBooks();
foreach (Book b in books) {
Console.WriteLine(b.Name);
}
SOAP can also be used by Java. For this the wsimport command can be used to generate the client proxy.
Contract First Design
Contracts are written first.
This allows you to concentrate on the format of the messages and the data types. This ensures interoperability and compatibility
As such, for WCF, interfaces should be used, instead of class.
The three Contracts
The data contract contains the data:
using System.Runtime.Serialization;
[DataContract(Name="PersonType")]
public class Person {
[DataMember]
public string name;
[DataMember(Name="AgeProperty")]
private int age;
[DataMember(IsRequired=false)]
float salary;
}
The IsRequired=false allows to make non-breaking changes to the interface.
Breaking changes can be done by using namespaces:
[DataContract NameSpace="http://www.zhaw/Service/1.0"]
public class Car {
[DataMember]
public string Model;
[DataMember]
public int HorsePower;
}
The service contract describes which functions can be invoked:
[ServiceContract]
[DataContractFormat(
Style=OperationFormatStyle.Document)] //Or Rpc
public interface IOrderEntry {...}
[ServiceContract]
[XmlSerializerFormat(
Style=OperationFormatStyle.Document,
Use=OperationFormatUse.Literal)] //Or Encoded
public interface IOrderEntry {...}
Interfaces can be updated in the following way:
[ServiceContract NameSpace="http://www.zhaw/Service/1.0"]
public interface IOrderEntry
{
[OperationContract(IsOneWay = true)]
void PlaceOrder(PurchaseOrder order);
}
[ServiceContract]
public interface IExtendedOrderEntry : IOrderEntry
{
[OperationContract]
PurchaseOrder GetOrder(String orderIdentifier);
}
There is also a FaultContract, which gets used when an error or exception occur.
[DataContract]
class MyFault {
[DataMember]
public string Reason = null;
}
[ServiceContract]
public interface IOrderEntry {
[OperationContract]
[FaultContract(typeof(MyFault))]
PurchaseOrder GetOrder(String orderId);
}
public class OrderEntry: IOrderEntry {
public PurchaseOrder GetOrder(string orderId) {
try{…}
catch(Exception exception) {
MyFault theFault = new MyFault();
theFault.Reason = "Some Reason";
throw new FaultException<MyFault>(theFault);
}
}
}
Container Managed Transaction
[ServiceContract]
public interface IMyContract
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Required)]
bool Transfer1(Account from, Account to, decimal amount);
[OperationContract]
[TransactionFlow(TransactionFlowOption.NotAllowed)]
bool Transfer2(Account from, Account to, decimal amount);
}
If TransactinoFlow is required, then a new transaction is tarted when calling the service. If another service is called from within the first service, the transaction context is passed on.
Bindings
Bindings are a set of protocols that are guaranteed to work. There are multiple bindings. Only the follows are relevant:


