(All of these examples will be C# specific)
(Most of the types needed for WCF in C# are in System.ServiceModel)

What Is WCF?

WCF stands for Windows Communication Foundation.

It is a framework for building service-oriented applications AND a runtime for deploying these services.

WCF provides a unified programming model for several technologies: COM+ Services, Web Services (in capitals), .Net Remoting, Microsoft Message Queuing, etc. It provides transactions, reliability, state, security, instantiation, scalability, and so on.

It is mostly SOAP based, but can use REST.

WCF abstracts the details of communication, and separates these settings from your business code. You can use HTTP today, and Net.TCP tomorrow by just changing your config file.

WCF web services are interoperable with many types of clients because it (usually) passes messages in XML format using HTTP protocol. Ie, it uses SOAP.

Architecture

WCF uses an "interception" or "pipe line" architecture, loosely based on the Chain of Responsibility design pattern.

You have two end points, the client and the service. The client packages a message and sends it through a proxy client, through a series of client channels, through a series of service channels, to the service.

One channel may handle security (encoding), another may handle queuing. You can add and remove channels to change behavior.

Comparisons

Web Services

"Web Services" is the terribly confusing name Microsoft gave its earlier web services framework. Roughly 2000 to 2002.

"Web Services" only supported HTTP.
They didn't enforce strict communication contracts.
Required use of the WS* stack.

Enterprise Services

"Enterprise Services" included some advanced features, like security and transactions.
But it was hard to setup.

MSMQ

MSMQ is a queuing framework that is still in use today. It provides reliable message transportation.

Sockets

Sockets are good for forming point-to-point connections.
They require a lot of custom code to setup, because they are low-level - highly configurable but a lot of overhead to setup your system.

Web API

"Web API" is another confusing name Microsoft gave a current web services framework.

WCF and Web API are used for different kinds of projects.
- WCF is more feature rich than Web API. It is also more heavy-weight (harder to setup).
- WCF mainly uses the SOAP protocol, while Web API only uses the REST architecture.
- Web API is more interoperable (because it uses just HTTP and REST).
- Communication with Web API only requires an HTTP request, while communicating with WCF requires tooling (meaning the client needs to also use the WCF framework, to most easily talk to the WCF service).
Components

Data Contracts
Service Contracts
Services
Hosts
Client Proxies
Configuration

Contracts

The data contracts and service contracts are the only thing shared between client and service, either through a shared assembly or through contract equivalence.
- It is recommended to put just the contracts into a single assembly, so they are easy to share between service and clients.

Contract Equivalence

Contract names and member/operation names must match. Each of the attributes (DataContract, DataMember, ServiceContract, OperationContract) has an optional Name property so you can specify an outward-facing name.


[OperationContract(Name="matchingName")]

Contract namespaces must also match. Each of the four attributes also has an optional Namespace property.


[ServiceContract(Namespace="matchingNamespace")]

You can also specify the namespace at the assembly level.
In your project's Properties > Assembly.cs:

//add line
[assembly:ContractNamespace("old", ClrNamespace="new")]

Data Contracts

A data contract specifies what data types (besides primitives) can be passed between a client and service. Both your request types and your return types will need to be specified with data contracts.

The client and service do not have to share data types, just the data contracts. One can serialize their data type, send it to the other, and it can than be deserialized to another data type.

Naming Convention

The WCF convention is to add a "Data" suffix to all objects decorated with DataContract. This helps differentiate data contracts from entities.
For example, "CountyData" instead of just "County".

Attributes

Data classes are decorated with the DataContract attribute. Each property in the class that you want to serialize is decorated with the DataMember attribute.


using System.Runtime.Serialization;

[DataContract]
public class MyObjectData
{
    [DataMember]
    public int MyProperty
    {
        get;
        set;
    }
}

Enum attributes:

[DataContract]
public enum ExtensionOption : int
{
    [EnumMember]
    Txt=0,
    [EnumMember]
    Csv=1
}

Opt-In

DataContractSerializer is an opt-in serializer: it will only serialize types decorated with DataContract, and will only serialize properties decorated with DataMember.

As of .Net 4.0, all public properties in a DataContract type are opted-in by default. It is still recommended to be explicit by adding DataMember to each property.

KnownType

Add the KnownType attribute to a base class DataContract to explicitly include its derived types in consideration for deserialization.

For example, when deserializing a PersonData type, check if it is in fact a StudentData or TeacherData type.

using System.Runtime.Serialization;

[DataContract]
[KnownType(typeof(StudentData))]
[KnownType(typeof(TeacherData))]
public class PersonData
{
}

[DataContract]
public class StudentData : PersonData
{
}

[DataContract]
public class TeacherData : PersonData
{
}


Service Contracts

The service contract defines what operations are available from your API.

The service contract specifies what can be communicated between a client and service. A single service contract usually contains multiple operations (methods).

A service contract is an interface (with method members only, no properties).

Naming Convention

As with all C# interfaces, a service contract should start with the "I" prefix.
In addition, service contracts should end with the "Service" suffix.

Attributes

The interface must be decorated with the ServiceContract attribute.
Each method signature must be decorated with the OperationContract attribute.


using System.ServiceModel;

[ServiceContract]
public interface IService
{
    [OperationContract]
    public void AddRecord(Record record);
}

Overloading

To be interoperable with other systems, service contracts do not support method overloading, so each operation must have a unique name. You can still use method overloading locally as long as you specify a unique outward-facing name.


using System.ServiceModel;

[ServiceContract]
public interface IService
{
    [OperationContract(Name="GetZipcodesByState")]
    public List<Zipcode> GetZipcodes(string state);

    [OperationContract]
    public List<Zipcode> GetZipcodes();
}

Arguments

Because service operations are defined with a .Net method signature, they can accept any number of arguments.
Each argument can be a primitive type (int, string, etc) or a DataContract type.

Arguments and return types can also use generic collections as if they were primitive types.
Ex: IEnumerable<string> or List<string> or string[].
All collection types will be serialized as arrays.

Should I use multiple primitive type arguments, or bundle them into one DataContract type that exists just for this operation request?
The main use case I've run into is this:
- Changing the order of arguments, or adding new required arguments, to an existing operation will require all clients to update their code to match.
- Adding a new optional property to a DataContract type does not require the client to update. And the order of properties in the DataContract type does not matter.

Therefore, it is easier to make non-breaking updates to your service if you use DataContract types instead of lists of arguments.
I recommend using either a single primitive type argument, or a single DataContract type argument.


Fault Contracts

Defines errors raised by the service, ie. tells the client what kinds of faults to expect from an operation.

By default, services use Error Masking: all exceptions are passed to the client as generic FaultExceptions.


//in service contract
[OperationContract]
[FaultContract(typeof(MathFault))]
int Divide(int a, int b);

//in service
int Divide(int a, int b)
{
    try
    {
        return a / b;
    }
    catch(DivideByZeroException)
    {
        throw new FaultException<MathFault>(new MathFault());
    }
}


Message Contracts

Defines the elements of the message (header, body, security...). This gives you complete control over the contents of the SOAP message.


Services

Services are classes that implement one or more service contract interfaces. This is where the business logic goes.

Services exist only on the service-side of the wire.


using System.ServiceModel;

public class MyManager : IMyService
{
}

Naming Convention

One convention I've seen is to use a "Manager" suffix instead of a "Service" suffix for service implementations.

Using some distinct suffix is useful:
- It differentiates the service implementation from the service contract.
- It reduces confusion when one class implements more than one service contract.

Instance Context

Manages the association between the channel and the user-defined service object.

Instance Context Mode

A service behavior attribute.

Per Call: a new Instance Context object is created/recycled per web service call.

Per Session: a new Instance Context object is created/recycled per session. Multiple calls can be made in one session.

Single: only one Instance Context object is created for the lifetime of the service, and is used for all calls.

Thread Pool

WCF defaults to allow one thread per CPU.

If the service is slow, but individual calls are fast and CPU usage is low, you may need more threads in your thread pool.

New threads are created when needed, but only as many as 1 per 0.5 seconds, so the pool can be slow to grow.

You can set a minimum pool size with SetMinThreads on the ThreadPool object.

Visual Studio

WCF Project

How get a basic WCF web service running locally,
As of 8/28/2019,
In Visual Studio Community 2015:

(1)

Visual Studio > New Project > WCF (under C#) > WCF Service Application > OK

(2)

Rename project to "Demo.Host".

(3)

Add new library project to solution, called "Demo.Contracts".
Add references System.ServiceModel and System.Runtime.Serialization to "Demo.Contracts".

(4)

Move file "IService1" to project "Demo.Contracts".
Rename "IService1" to "IDemoService".
Move data structures from "IDemoService" to its own file.
Update all namespaces in "Demo.Contracts" project to namespace "Demo.Contracts".

(5)

Add project reference "Demo.Contracts" to project "Demo.Host".
Update all namespaces in "Demo.Host" project to namespace "Demo.Host".

(6)

You can use a real SVC file:
- Rename "Service1.svc" to "DemoService.svc".
- Right-click on "DemoService.svc" > View Markup > update "Service" field to "Demo.Host.DemoService.svc".
- Open "DemoService.svc.cs"
-- Add "using Demo.Contracts;"
-- Rename class to "DemoService" inheriting from "IDemoService"

Or you can use a virtual SVC file:
- Add new class to "Demo.Host" project called "DemoService.cs".
- Copy "Service1.svc.cs" contents to "DemoServices.cs" and delete "Service1.svc".
- Open "DemoService.cs"
-- Add "using Demo.Contracts;"
-- Rename class to "DemoService" inheriting from "IDemoService"
- Open "Demo.Host/Web.config"
-- Add "<serviceHostingEnvironment>" tag inside the "<system.serviceModel>" tag

    <serviceHostingEnvironment>
        <serviceActivations>
            <add service="Demo.Host.DemoService" relativeAddress="DemoService.svc"/>
        </serviceActivations>
    </serviceHostingEnvironment>

(7)

Open "Demo.Host/Web.config"
- Add "<services>" tag inside the "<system.serviceModel>" tag

    <services>
        <service name="Demo.Host.DemoService">
            <endpoint contract="Demo.Contracts.IDemoService" binding="basicHttpBinding" address=""/>
        </service>  
    </services>

(8)

If publishing a WSDL:
Open "Demo.Host/Web.config"
- Add "<behaviors>" tag inside the "<system.serviceModel>" tag

    <behaviors>
        <serviceBehaviors>
            <behavior>
                <serviceMetadata httpGetEnabled="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>

(9)

Right-click on project "Demo.Host" > Properties > Web
- Set "Servers" section to "IIS Express"
- Click "Create Virtual Directory" (might need to open Visual Studio as Admin for this)

(10)

Run "Demo.Host" project in browser.
- Should see a directory listing for the project.
- If you click on DemoService.svc, you should see a well-formated page starting with "DemoService Service". (If you use a virtual SVC, type in the address manually: "localhost:<whatever>/DemoService.svc".)
-- If you click the WSDL link, you should see the XML WSDL file.

(11)

Open WCF Test Client (at a location like C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\WcfTestClient.exe).
- File > Add Service > "localhost:<whatever>/DemoService.svc" > Ok
- Test the service functionality.
-- Double-click a service operation in the list. Details will come up in the right-hand panel.
-- Fill in all fields for the operation.
-- Click "Invoke" and verify the response.

(12)

If you get error "Cannot obtain metadata from <url>", check the address in the endpoint in the "Demo.Host/Web.config".

Hosts

This is the application responsible for listening for web calls to your service and then initializing a service class to handle the call.

Service Configuration

WCF supports declarative configuration (everything in a config file) and procedural configuration (settings in the code).

For declarative configuration, look in the App.config file of the service implementation project (for IIS hosted projects) or the service host project (for self-hosted projects).

Each section is marked for when it is needed:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <connectionStrings>
        <!-- REQUIRED FOR repository (DbContext class) -->
        <!-- Ex: public GeographyDbContext() : base(name="main") {} -->
        <add name="main" connectionString="Data Source=.\sqlexpress;Initial Catalog=GeographyData..." />
    </connectionStrings>
    
    <system.serviceModel>
        <services>
            <!-- REQUIRED FOR hosting a service -->
            <!-- you need 1 service tag for each service you are hosting -->
            <service name="fully qualified Type of the service implementation">
                <!-- each service requires at least 1 endpoint -->
                <!-- each endpoint corresponds to 1 service contract -->
                <endpoint 
                    address="url where clients can find this endpoint" <!-- ex: "net.tcp://localhost:8009/GeographyService" -->
                    binding="netTcpBinding" <!-- defines the transport mechanism; this example is for TCP; this will affect the protocol identifier in the URL address -->
                    contract="fully qualified Type of the service contract (interface)" />
            </service>
        </services>
        
        <serviceHostingEnvironment>
            <!-- REQUIRED FOR virtual SVC files -->
            <serviceActivations>
                <add 
                    service="fully qualified Type of service implementation -->" 
                    relativeAddress="GeographyService.svc" 
                    factory="fully qualified Type of custom service factory" <!-- REQUIRED FOR custom service factory -->
                    />
            </serviceActivations>
        </serviceHostingEnvironment>
    </system.serviceModel>
</configuration>

Web Hosting HTTP

You can host with IIS (Internet Information Services).
It is easy to setup (plug and play), but is mostly limited to HTTP bindings.
This is usually used for externally facing services.

IIS will instantiate ServiceHost automatically.
    
IIS used to require an SVC file per service. This was the browsing point for the site. Ex: "GeographyManager.svc".
With .Net 4.0, the physical SVC file can be replaced with a virtual file.
To do this, reference System.ServiceModel.Activations in the App.config file.


<system.serviceModel>
    <serviceHostingEnvironment>
        <serviceActivations>
            <add service="fully qualified Type of service class"
                relativeAddress="name.svc"
                />
            <!-- the client will still address url/name.svc -->
        </serviceActivations>
    </serviceHostingEnvironment>
</system.serviceModel>

When using IIS, the endpoint address set in the configuration file will not be the complete address. IIS will set an address, and if anything is in the endpoint configuration address, it will be appended to the IIS address.

You can also provide IIS with a custom host factory to regain control of the host, like with self-hosting.

If you are using IIS Express, you can set this in your web host project > properties.

To create a web hosting project:
- Visual Studio > add new project > Web > ASP.Net Web Application > Empty
- This will give you an empty web project with just a config file, which is all you need.
- Add the configurations you need to the Web.config.
- Open the project properties > Web > Server should be set to IIS Express with a default Project URL. This URL plus the address plus the SVC filename plus the configuration endpoint will be where the service host listens for the client. (Or something like that, not sure what order it all gets concatenated in.)

To use a virtual SVC file:
- Make sure the web hosting project references System.ServiceModel.Activation.
- Add the configurations for service activations to the Web.config.

Web Hosting WAS

WAS requires the full version of IIS, not just IIS Express.

1) Open Visual Studio as Admin > Web host project > Properties > Web
- use "Local IIS" instead of "IIS Express"
- and click "Create Virtual Directory"

2) Open command prompt as Admin > C:\Windows\System32\inetsrv
- run: appcmd.exe set site "Default Web Site" -+bindings.[protocol='net.tcp',bindingInformation='808:*']
- The "Default Web Site" part is because this web host is listed under that in IIS Manager.
- This command modifies the applicationHost.config file.

3) IIS Manager > select this web host > Advanced Settings
- update Enabled Protocols from "http" to "http,net.tcp"

4) Update the App.config file to use one of these bindings instead of HTTP.

<system.serviceModel>
    <services>
        <service name="fully qualified Type of the service implementation">
            <endpoint 
                address=""
                binding="netTcpBinding"
                contract="GeorgaphyLibrary.Contracts.IGeographyService" />
        </service>
    </services>
</system.serviceModel>

Result: the service will listen at net.tcp://localhost/GeographyLibrary.WebHost/GeographyService.svc

Self Hosting

You can write your own hosting application, be it a console app, a winforms app, or a windows service. Self hosting requires additional coding, and does not automatically have all the features IIS offers, but it does give you the ability to create your own features.

You create a host by deriving from class ServiceHost. You will need one host per service implementation class.


public class MyHost : ServiceHost
{
}

ServiceHost.CloseHost: waits for in-progress calls to complete, then closes
ServiceHost.AbortHost: closes immediately, sending a fault to clients cut off in the middle

You can host without a configuration file by providing the endpoint procedurally in your host project.
The endpoint tells the host how and where to listen for incoming calls.

Hosting example:

using System.ServiceModel;
using System.Runtime.Serialization;

public class Program
{
    public static void Main(string[] args)
    {
        //GeographyManager is the service implementation class of the IGeographyService interface
        ServiceHost hostGeographyManager = new ServiceHost(typeof(GeographyManager));
        
        //to add endpoints procedurally, add them before opening the host
        //aka "configless binding"
        string address = "net.tcp://localhost:8009/GeographyService";
        Binding binding = new NetTcpBinding();
        Type contract = typeof(IGeographyService);
        hostGeographyManager.AddServiceEndpoint(contract, binding, address);

        //opens the host
        hostGeographyManager.Open();
        
        //a use-case for self-hosting is to put this into a desktop application that will be a dashboard for your service, providing up-to-date information as it runs and handles requests
        
        //closes the host
        hostGeographyManager.Close();
    }
}

Custom Host Factory

IIS automatically instantiates all the ServiceHosts you need, using a service host factory.

You can create you own factory.

1) In the web host project, add new class CustomHostFactory.


using System.ServiceModel.Activation;

public class CustomHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        ServiceHost host = new ServiceHost(serviceType, baseAddresses);
        return host;
    }
}
Operations

Request/Response

The client sends a request and waits until the service returns a response.
This includes operations that return void. They still return a SOAP message.

The standard operation type.

The client is blocked until the service returns a message.

Includes full support for fault handling, because the fault message is in the response SOAP message.

One-Way

One-way operations are also called "fire and forget operations".
These operations do not make a response SOAP message. Therefore, the client is not blocked.

Must return void.
Must have OperationContract attribute with IsOneWay=true property.

Has no support for fault handling, because a fault message cannot be returned to the client.

If using a transport session, note that the client WILL block when it closes its proxy until the last operation on the service completes, even if the operation is one-way.
Therefore, it can make sense to expose one-way operations under a basicHttpBinding, which does not support transport sessions, so that the client cannot accidentally block on those calls.


using System.ServiceModel;

[ServiceContract]
public interface IMyService
{
    [OperationContract(IsOneWay=true)]
    void DoSomething();
}

Callbacks

Callback operations are also called "duplex calls".
Callbacks allow the service to call the client.
This can get useful for reporting progress updates to the client.

This is a feature Web API doesn't have.

Be careful of threading issues.
If the client calls the service from the GUI thread, and the client also handles the callback on the GUI thread, you'll deadlock your GUI.

Requires a transport session, because there needs to be an open pipe between service and client.
Requires a callback service contract linked to the normal service contract by the CallbackContract property of the ServiceContract attribute.

Callbacks are frequently one-way calls, just reporting updates to the client.
An example of a response/request callback is reporting an update to the client, and accepting back whether the client wants to cancel the in-progress operation or not.

Service contract:

using System.ServiceModel;

[ServiceContract(CallbackContract=typeof(IMyCallbackService)]
public interface IMyService
{
    [OperationContract]
    void DoSomething();
}

[ServiceContract] //technically, this attribute is not required, but I recommend it for consistency
public interface IMyCallbackService
{
    [OperationContract]
    //operation arguments will be sent to the client, the return data will come back to the service
    void SendUpdate(string message);
}

Service implementation:

using System.ServiceModel;

public class MyService : IMyService
{
    public void DoSomething()
    {
        //stuff
        
        IMyCallbackService callback = OperationContext.Current.GetCallbackChannel<IMyCallbackService>();
        //callback will be null if the client is down, or did not implement DuplexClientBase
        //if you do this in a loop, get a new channel and check for null each time, because the client state may have changed
        if(callback != null) 
        {
            callback.SendUpdate("done");
        }
    }
}

Client proxy:
Note that "ClientBase" has changed to "DuplexClientBase". This affects all the constructors.

using System.ServiceModel;
using System.ServiceModel.Channels;
using GeographyLibrary.Contracts;

public class GeographyClient : DuplexClientBase<IGeographyService>, IGeographyService
{
    public GeographyClient(InstanceContext instanceContext) : base(instanceContext)
    {
    }
    
    public GeographyClient(InstanceContext instanceContext, string endpointName) : base(instanceContext, endpointName)
    {
    }
    
    public GeographyClient(InstanceContext instanceContext, Binding binding, EndpointAddress address) : base(instanceContext, binding, address)
    {
    }

    public void DoSomething()
    {
        Channel.DoSomething();
    }
}
InstanceContext is a wrapper for the callback service implementation.

Client using proxy:

using System.ServiceModel;
using System.ServiceModel.Channels;
using GeographyLibrary.Contracts;

public class MyClass : IMyCallbackService
{
    public void UseProxy()
    {
        GeographyClient proxy = new GeographyClient(new InstanceContext(this)); //the InstanceContext should wrap whatever actually implemented IMyCallbackService
        proxy.DoSomething();
        proxy.Close();
    }
    
    //implementing the IMyCallbackService operations
    //this does not have to be in the same class/etc as the method that uses the proxy
    public void SendUpdate(string message)
    {
        Console.WriteLine(message);
    }
}
Note how many changes are required in the client to support service callbacks.
You may want to group operations that have callbacks into their own service contract, to minimize the effect on the client.

To avoid deadlock on the client (avoid thread waiting on service response being same thread that handles the callback):

[CallbackBehavior(UseSynchronizationContext=false)] //causes callback to enter on a new background thread
public class MyClass : IMyCallbackService
{
}
Remember to marshal up if the callback handler needs access to the main thread.

If you are using a request/response callback (your service is waiting for a response from the client), make sure your concurrency mode is set such that deadlock will not occur. The problem that can happen is Operation-A is waiting for a client response, the response comes back but it gets queued until Operation-A is complete, causing deadlock.
- Set service implementation concurrency mode to Multiple (opens up concurrency a lot) or Reentrant (just for this use case).

using System.ServiceModel;

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant, ReleaseServiceInstanceOnTransactionComplete=false)]
public class MyService : IMyService
{
}

You can use callbacks with netTcpBinding easily.
You cannot use callbacks with basicHttpBinding because it has no transport session.
To use callbacks with HTTP:

    <system.serviceModel>
        <services>
            <service name="MyServiceImplementation">
                <endpoint 
                    address="http://localhost:8009"
                    binding="wsDualHttpBinding"
                    contract="IMyService"
                    />
            </service>
        </services>
    </system.serviceModel>

A transaction that flows from client to service (or starts in the service) can flow back to the client (for a callback) and then back to the service again (for a callback response).

using System.ServiceModel;

[ServiceContract]
public interface IMyCallbackService
{
    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    void MyCallback(object data);
}
And the client operation that handles the callback can even require a transaction:

[OperationBehavior(TransactionScopeRequired=true)]
public void MyCallback(object data)
{
    //stuff
}

Async

Async calls are a client-side pattern, to execute WCF calls asynchronously. The service knows nothing about it.

This will work even if the service is making callbacks.

The client calls the service asynchronously, which means the client's main thread (probably the GUI thread) immediately regains control and can continue running.

The client will be notified when the async service call finishes.

Make a new client-side service contract for the async operations:

[ServiceContract]
public interface IGeographyService
{
    [OperationContract]
    ZipCodeData GetZipInfo(string zip);
}

[ServiceContract]
public interface IGeographyAsyncService
{
    [OperationContract]
    ZipCodeData GetZipInfo(string zip);
    
    //create an async version of any operations you want to call asynchronously
    //naming convention is to add "Async" suffix to operation name
    [OperationContract]
    Task<ZipCodeData> GetZipInfoAsync(string zip);
}

//now the proxy is based on the async interface
public class GeographyClient : ClientBase<IGeographyAsyncService>, IGeographyAsyncService
{
    public ZipCodeData GetZipInfo(string zip)
    {
        return Channel.GetZipInfo(zip);
    }
    
    public Task<ZipCodeData> GetZipInfo(string zip)
    {
        return Channel.GetZipInfoAsync(zip);
    }
}
Note that any operation attributes (other than OperationContract) on the non-async operation will automatically also apply to the async operation.
Provided you follow Microsoft's naming convention of adding the "Async" suffix to the operation name.
For example, "[TransactionFlow(TransactionFlowOption.Allowed)]" on the non-async operation will also apply to the async operation.

If you are letting Visual Studio automatically generate your client proxy, there is a checkbox on the that dialog to also generate the async operations.

Calling the async operation in the client:

public async void buttonClicked(object sender, EventArgs e)
{
    GeographyClient proxy = new GeographyClient();
    Task<ZipCodeData> task = proxy.GetZipInfoAsync("12345");
    task.ContinueWith(result =>
    {
        //display result.Result of type ZipCodeData
        //display message "Task Complete"
    });
    //display message "Task Initiated"
}
You don't need to manually create a new thread or task when you use this method. It happens behind the scenes.
Note that we don't use "await" here because we want to let the current thread continue while the task runs in the background.

The "ContinueWith" is also known as a "done callback".

Fault handling in async operations:

public async void buttonClicked(object sender, EventArgs e)
{
    GeographyClient proxy = new GeographyClient();
    Task<ZipCodeData> task = proxy.GetZipInfoAsync("12345");
    task.ContinueWith(result =>
    {
        if(result.Exception == null)
        {
            //display result.Result of type ZipCodeData
            //display message "Task Complete"
        }
        else
        {
            //display result.Exception.Message will say "One or more errors occurred."
            //display result.Exception.InnerException.Message to see the actual error message
        }
    });
    //display message "Task Initiated"
}
If you want to use try/catch statements instead (maybe you want to respond to different types of exceptions):

public async void buttonClicked(object sender, EventArgs e)
{
    GeographyClient proxy = new GeographyClient();
    Task<ZipCodeData> task = proxy.GetZipInfoAsync("12345");
    task.ContinueWith(result =>
    {
        if(result.Exception == null)
        {
            //display result.Result of type ZipCodeData
            //display message "Task Complete"
        }
        else
        {
            try
            {
                throw result.Exception.InnerException;
            }
            catch(Exception ex)
            {
                //display ex.Message to see the actual error message
            }
        }
    });
    //display message "Task Initiated"
}

Clients

Consume WCF Services

There are several aspects to establishing communication between client and service:
- Pipe Establishment (if using net.tcp)
- Hand-Shaking
- Security Exchange
- Serialization and Deserialization
- Message Transmission

The client will also need a reference to the Data Contracts and Service Contracts defined by the host.

Naming Convention

Call a proxy for IGeographyService as "GeographyClient".

Client Proxies

All of that low-level complexity can be abstracted into a proxy class. WCF provides the ClientBase<T> wrapper class for this purpose.

You'll have one proxy class per service contract.

public class MyProxy : ClientBase<IServiceContract>, IServiceContract
{
    //implement each service contract operation here
    //generally, these are just pass-through methods like this
    public IEnumerable<Zipcode> GetZipcodes()
    {
        return Channel.GetZipcodes();
    }
}


MyProxy proxy = new MyProxy();
List<Zipcode> zipcodes = proxy.GetZipcodes();
proxy.Close();
Always call proxy.Close(). The pipe established with the service remains open until you do, and it is possible to use up all the service's pipes if you don't clean up.

Configuration

The proxy class will also require an endpoint, either through configuration or code. This will be in the project that uses the proxy classes.

If you are using explicitly named endpoints, you will need to use the non-default constructor in the proxy class. The client code will need to specify which endpoint is used when the proxy is instantiated.


public class MyProxy : ClientBase<IServiceContract>, IServiceContract
{
    public MyProxy(string endpointName) : base(endpointName)
    {
    }
}

You can also use configureless endpoints.


public class MyProxy : ClientBase<IServiceContract>, IServiceContract
{
    public MyProxy(Binding binding, EndpointAddress address) : base(binding, address)
    {
    }
}

The client will need endpoint(s) defined through configuration (App.config file) or through code. The client must have a uniquely named endpoint for each service contract interface. If you do not specify a name explicitly, it will default to the name of the service contract.


<system.serviceModel>
    <client>
        <!-- all endpoint settings exactly match what is in the service config -->
        <endpoint
            address="full url of service"
            binding="communication medium"
            contract="fully specified Type of the service contract interface"
        />
        <endpoint name="explicit name"
            address="full url of service"
            binding="communication medium"
            contract="fully specified Type of the service contract interface"
        />
    </client>
</system.serviceModel>

The client code can then call the web service through a proxy class.

If you do not provide an explicit name for an endpoint, it will be set to one based on the "contract" attribute. All endpoint data is collected into a dictionary, keyed on the name of the endpoints. So if you have more than one endpoint for the same contract, neither with an explicit name, only one will end up being used by the proxy.

Contract Equivalence

The service and client do not have to share a library of Data Contracts and Service Contracts.

It is possible for the service and client to use different contracts, as long as they are equivalent:
- Contract Names are the same
- Namespaces are the same
- Member and Operation names are the same

Note that you can override the actual name of a Member or Operation with an attribute, to make your contracts equivalent.

This works because all data passed between service and client is serialized and then deserialized. As long as the serialization instructions are the same, the data will be passed correctly.

Channel Factory

Instead of using proxy classes, you can use a channel factory to create the proxy classes on the fly.


ChannelFactory<IServiceContract> factory = new ChannelFactory<IServiceContract>("");
/*
    as of the time this lesson was written,
    there was a known bug in ChannelFactory
    where you need to use an empty string instead of no string for the default constructor
*/
IServiceContract proxy = factory.CreateChannel();
List<Zipcode> zipcodes = proxy.GetZipcodes();
factory.Close();

Channel factories can also use configureless endpoints.

Channel factories can be used if you want to write a custom Proxy that does more behind-the-scenes work than the default Proxy.

Bindings

Bindings are the transport mechanism for the messages.

The service and the client must use the exact same bindings, otherwise they cannot communicate.

HTTP

HTTP messages use port 80.
They can pass through a firewall, so are commonly used when the client is a different company than the service.
They are secured and encrypted using certificates. By default, the messages travel as plain-text.

"basicHttpBinding"
- the most simple HTTP option
- use when communicating across the firewall
- use when the client is running legacy code (such as .Net 2.0, VB 6, or SOAP Toolkit)

"wsHttpBinding"
- more feature-rich option
- use when communicating across the firewall
- use when the client is using a modern framework

TCP

Faster than HTTP.
Usually used within a firewall, so for intra-company communication. (You can use it inter-company, but it would require opening another port in the firewall, which is not suggested for security reasons.)
Secure by default.

"netTcpBinding"

IPC

IPC is the fastest communication medium, but it limited to only communicating with the current machine.
This is useful for "in-application services" where the service and the client are running on the same machine, even as a single application.

aka Named Pipe Binding


<system.serviceModel>
    <services>
        <service name="name">
            <endpoint 
                address="net.pipe://localhost/MyService"
                binding="netNamedPipeBinding"
                contract="interface"
                />
        </service>
    </services>
</system.serviceModel>

UDP

Faster than TCP, because it is unreliable. If a message fails to reach the recipient, it will not be resent.
Useful for broadcasting.
Limited to within a subnet.

MSMQ

Used for queuing.
Supports disconnected communication, it still works while not connected to the network.

Binding Configurations

Remember that both service and client must use the exact same settings, to be able to communicate.

For some settings, like timeouts, there can be a mismatch and the shorter setting will win.

Declarative Configuration


<system.serviceModel>
    <services>
        <service name="MyService">
            <endpoint
                address="net.tcp://localhost:8080/MyService"
                binding="netTcpBinding"
                contract="IMyService"
                bindingConfiguration="bindingConfigA"
                />
        </service>
    </services>
    <bindings>
        <netTcpBinding>
            <binding name="bindingConfigA">
                <!-- configuration here -->
            </binding>
        </netTcpBinding>
    </bindings>
</system.serviceModel>

If you don't give the "binding" a name, it will become the default settings to all "netTcpBinding" (or whatever the parent tag is) that do not specify a "bindingConfiguration".

Procedural Configuration


NetTcpBinding binding = new NetTcpBinding();
binding.{property} = {value};

Reliability

Reliability: ensuring that the message reached the recipient.
- netTcpBinding is reliable by default, other bindings have to configure this

Ordered Messaging

Ordered messaging: ensuring that messages are serviced in the same order they were dispatched.
- requires Reliability
- useful for one-way communication


<netTcpBinding>
    <binding name="bindingConfigA">
        <reliableSession ordered="true" />
    </binding>
</netTcpBinding>

Inactivity Timeout

Inactivity timeout: keeps the pipe open for X amount of time between messages, to see if another message arrives.
- requires Reliability
- enables transport sessions

This is called a sliding timeout because it restarts each time activity occurs.


<netTcpBinding>
    <binding name="bindingConfigA" receiveTimeout="00:00:05"> <!-- must also be set when using inactivityTimeout -->
        <reliableSession inactivityTimeout="00:00:05" /> <!-- 5 seconds -->
    </binding>
    <binding name="bindingConfigB" receiveTimeout="infinite">
        <reliableSession inactivityTimeout="infinite" /> <!-- no timeout -->
    </binding>
</netTcpBinding>

Receive Timeout

Receive timeout: keeps the pipe open for X amount of time between messages, to see if another message arrives.
- when not using Reliability
- although this setting is still used when using Reliability?

This is called a sliding timeout because it restarts each time a message is received.

Send Timeout

Send timeout: the amount of time the client will wait to receive a response to their request.
- default is 45sec


<binding name="bindingConfigA" sendTimeout="00:00:05"> <!-- 5 seconds -->
</binding>

Message Size

Message size: maximum size of a single message
- default is 64kB


<binding name="bindingConfigA" maxReceivedMessageSize="2000000"> <!-- 2MB -->
</binding>

Transaction Flow

Transport-Level Sessions

A transport session is an open pipe maintained between a service and client.
- allows the service to identify a client (with the handshake) and maintain a connection to them

These bindings support transport sessions:
- netTcpBinding
- netNamedPipeBinding
- wsHttpBinding (with reliability or security turned on)

Threads

How to put the service on a different thread than the rest of the application.
For instance, if the application includes a GUI, you want the GUI and the service on different threads.

It is best practice to be careful with what runs on which threads. You never know what changes to the application will occur in the future, and race conditions and deadlocks are difficult to debug.

Marshalling / Marshaling

Marshalling is the process of transforming an object to a data format suitable for transmission or storage.
Often used to move data between different parts of a computer or between programs or between threads.

Marshalling is similar to serialization.

The opposite process is unmarshalling or demarshalling.

UseSynchronizationContext

UseSynchronizationContext is a service behavior attribute.

To make the service run on a background thread:

using System.ServiceModel;

[ServiceBehavior(UseSynchronizationContext=false)] //execute service on a worker thread, instead of the service host's main thread
public class GeographyManager : IGeographyService
{
    public void UpdateGUI(string message)
    {
        //update GUI element with message
        mainWindow.ShowMessage(message);
    }
}

Synchronization Context

SynchronizationContext represents the executing context for a particular thread.

In the main thread, like the GUI:

public class MainWindow : Form
{
    private SynchronizationContext synchronizationContext = null;
    
    public MainWindow()
    {
        //initialize window
        
        synchronizationContext = SynchronizationContext.Current;
    }
    
    public void ShowMessage(string message)
    {
        //this will marshall from the service thread to the GUI thread
        SendOrPostCallback callback = new SendOrPostCallback(arg => 
        {
            messageLabel.Content = "Message: " + message;
        });
        synchronizationContext.Send(callback, null); //the "null" is a state variable that will be passed into the callback "arg"
    }
    
    private void buttonClick(object sender, RoutedEventArgs e)
    {
        //do this on a non-GUI thread so the GUI is not locked while the service runs
        Thread thread = new Thread(() =>
        {
            Channel<IGeographyService> factory = new ChannelFactory<IGeographyService>("");
            IGeographyService proxy = factory.CreateChannel();
            proxy.ShowMessage("very important message");
            factory.Close();
        });
        thread.IsBackground = true; //low priority thread, so it does not get in the way of the application closing
        thread.Start();
    }
}
Every thread in the application can now use this SynchronizationContext to talk to the GUI thread.

If you need to make multiple calls from the proxy on different threads each, then instantiate the proxy (and close it) outside the worker thread(s). This gives the proxy thread affinity for the main thread.

Tasks

Using threads directly is out of date. Use tasks instead.
Benefits: uses thread pools.


public class MainWindow : Form
{
    private SynchronizationContext synchronizationContext = null;
    
    public MainWindow()
    {
        //initialize window
        
        synchronizationContext = SynchronizationContext.Current;
    }
    
    public void ShowMessage(string message)
    {
        //this will marshall from the service thread to the GUI thread
        SendOrPostCallback callback = new SendOrPostCallback(arg => 
        {
            messageLabel.Content = "Message: " + message;
        });
        synchronizationContext.Send(callback, null); //the "null" is a state variable that will be passed into the callback "arg"
    }
    
    private async void buttonClick(object sender, RoutedEventArgs e)
    {
        //do this is a non-GUI thread so the GUI is not locked while the service runs
        await Task.Run(() =>
        {
            Channel<IGeographyService> factory = new ChannelFactory<IGeographyService>("");
            IGeographyService proxy = factory.CreateChannel();
            proxy.ShowMessage("very important message");
            factory.Close();
        });
    }
}
Behavior Configuration

Behaviors of a service.

Declarative Configuration


<system.serviceModel>
    <services>
        <service name="MyService" behaviorConfiguration="serviceBehaviorA">
            <endpoint address="a" binding="b" contract="c"/>
        </service>
        <behaviors>
            <serviceBehaviors>
                <behavior name="serviceBehaviorA">
                    <!-- settings here -->
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </services>
</system.serviceModel>

If you don't give the "behavior" a name, it will become the default settings to each "service" that does not specify a "behaviorConfiguration".

Inline Configuration


[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class MyManager : IMyService
{
}

Some behaviors can only be set inline, because they make such a difference to how the service operates that they cannot be left in an easily edited place like a config file.

Procedural Configuration


Behavior behavior = host.Description.Behaviors.Find<{type}>();
if(behavior == null)
{
    behavior = nwe {behavior type};
    behavior.{property} = {value};
    host.Description.Behaviors.Add(behavior);
}

Exceptions

You can receive more detailed information about unhandled SOAP faults. This is recommended during development, but not during production, for security and usability reasons.
(Ideally, you handle all faults anyway.)

Inline:

[ServiceBehavior(IncludeExceptionDetailInFaults=True)]
public class GeographyManager : IGeographyService
{
}

Declarative:

<system.serviceModel>
    <services>
        <service name="MyService" behaviorConfiguration="serviceBehaviorA">
            <endpoint address="a" binding="b" contract="c"/>
        </service>
        <behaviors>
            <serviceBehaviors>
                <behavior name="serviceBehaviorA">
                    <serviceDebug includeExceptionDetailInFaults="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </services>
</system.serviceModel>

Procedural:

ServiceHost hostGeographyManager = new ServiceHost(typeof(GeographyManager));

ServiceDebugBehavior debugBehavior = hostGeographyManager.Description.Behaviors.Find<ServiceDebugBehavior>();
if(debugBehavior == null)
{
    behavior = new ServiceDebugBehavior();
    behavior.IncludeExceptionDetailInFaults = true;
    hostGeographyManager.Description.Behaviors.Add(debugBehavior);
}
else
{
    behavior.IncludeExceptionDetailInFaults = true;
}

hostGeographyManager.Open();

hostGeographyManager.Close();

To test this, you can set your Client project to Start Without Debugging.

Metadata Exposure

Instancing

Concurrency

Throttling

Throttling can prevent memory overload. If the service is being overwhelmed by requests, it will queue up requests and feed them to the service more slowly.

The default settings are usually sufficient.

Declarative:

<system.serviceModel>
    <services>
        <service name="MyService" behaviorConfiguration="serviceBehaviorA">
            <endpoint address="a" binding="b" contract="c"/>
        </service>
        <behaviors>
            <serviceBehaviors>
                <behavior name="serviceBehaviorA">
                    <serviceThrottling 
                        maxConcurrentSessions="100" <!-- open transport sessions; defaults to NumberOfProcessors X 100 -->
                        maxConcurrentCalls="16" <!-- defaults to NumberOfProcessors X 16 -->
                        maxConcurrentInstances="26" <!-- minimum of 116 (sum of other minimums) -->
                        />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </services>
</system.serviceModel>

Serialization

The old XmlSerializer has been replaced with the DataContractSerializer (System.Runtime.Serialization).

The DataContractSerializer is an opt-in serializer, where the XmlSerializer was opt-out.
It looks for the DataContract and DataMember attributes on classes and their properties.

Although, as of .Net 4.0, classes with an explicit DataContract attribute are assumed to be DataContracts with all public properties as DataMembers.

Serialization calls "get" on each property.
Deserialization calls "set" on each property.

Version Tolerance

If the client sends extra data (parameters) to the service, the serializer will discard them instead of throwing an error.

If the service returns an object with fewer properties than the client expects, those properties will be set to null.

Now, if you DO want to catch those extra parameters, use the System.Runtime.Serialization interface IExtensibleDataObject. The extra parameters will be placed in the ExtensionData property during deserialization.


[DataContract]
public class MyObject : IExtensibleDataObject
{
    [DataMember]
    public int PropertyA
    {
        get;
        set;
    }
    
    public ExtensionDataObject ExtensionData
    {
        get;
        set;
    }
}

VarSpecified Parameters

When a .Net 1.1 client or ASMX client connects to a WCF service, it is using the old serializer. The result is that the client proxies add a "varSpecified" boolean parameter to each parameter in the operation signatures.


//WCF operation
void MyMethod(int a, string b, string c);

//becomes client proxy
void MyMethod(int a, bool aSpecified, string b, bool bSpecified, string c, bool cSpecified);

This is because the client cannot handle nullable parameters, so it requires you to specify which parameters are set and which are not.

You can avoid this by specifying the XmlSerializerFormat attribute on the service contract.

Security

Authentication: identify clients that call the service.

Authorization: determine what operations authenticated clients can access.

Clients can identify themselves with:
    - Windows account
    - username and password
    - certificate
    - other?
    
Services can identify themselves to clients with a certificate.

Security Token Service

A service providing tokens for token-based security. This is the service component that builds, signs, and issues security tokens according to the WS-Trust and WS-Federation protocols.

Ex: Active Directory Federation Services (ADFS)

Most STSs today issue tokens formatted with Security Assertion Markup Language (SAML), which is an XML vocabulary.

WCF STS is deprecated as of .Net 4.5, when Windows Identification Foundation was integrated into the .Net Framework.

Claims Aware Application

In a claims aware application, user identity is represented in code as a set of claims. An external identity system is configured to give your application that data it needs about the user.

Aka Relying-Party Application (RP) which relies on claims.

Security Token

A security token is a serialized set of claims, digitally signed by the issuing authority.


Version Tolerance

DataContractSerializer provides version tolerance (which the previous serializer did not).

Example: the Client sends an extra property in a data structure that the Service was not expecting.
The Service will ignore the extra property instead of throwing an exception.

Example: the Service sends two properties in a data structure to the Client, but the Client expects three properties.
The Client will fill in the missing property with the default value (0 or null, usually).

IExtensibleDataObject

This is intended for pass-through scenarios, such as Service A passing on the request to Service B.

If you implement interface IExtensibleDataObject on your Data Contracts, then the Service will remember extra data that has been sent in, that it didn't know how to use, and it return that data back to the Client.

So when the Client sends in three properties, and the Service only expects two, that third property will be saved while the request is fulfilled, and will (if appropriate) be returned back the Client in the response.

It's really simple to implement:

using System.Runtime.Serialization;

abstract class ExtensibleData : IExtensibleDataObject
{
    //this bucket will store unrecognized properties until they are needed
    public ExtensionDataObject ExtensionData { get; set; }
}

[DataContract]
public class ZipCodeData : ExtensibleData
{
    [DataMember]
    public string ZipCode { get; set; }
    [DataMember]
    public string City { get; set; }
    [DataMember]
    public string State { get; set; }
}


Instancing

Instancing decides which instance (running process) of a service will answer a particular request/call.

This enables a big differences between WCF (can maintain state) and Web API (stateless).

Per Call

Per call instance context mode: every request/call from a client is handled by a new service instance.
Even if the client's proxy stays open.

This is most scalable option.
There is no chance of memory leaks.

Does not support maintaining state.

Per Session

Per sessions instance context mode: the first request/call from a proxy is handled by a new service instance.
All calls from the proxy are handled by this service instance until the proxy is closed.
When the proxy is closed, it makes one final call to the service to say it is closing.

This is the default option.

This option requires a transport session:
- TCP binding
- IPC binding
- WS-HTTP binding with reliability or security turned on
If none of these are used, the service auto-downgrades to Per Call mode.

Supports maintaining state across multiple requests/calls with class-scoped variables. (For example, a field/property in the service implementation class.)
May need to consider locking errors.

Single

Single instance context mode: when the host opens it starts a new service instance.
All requests/calls to the service are handled by this one instance until the host closes.
(singleton pattern)

You can still have multiple transport sessions going on from clients, they just all hit the same service instance.

Supports maintaining state, but that state is shared by every proxy.
MUST consider locking errors, given how many clients could be using it at the same time.

?Supports something like starting the service instance before starting the host?
?See pre-hosting initialization?

Inline


[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class MyService : IMyService
{
}

Enum values: PerCall, PerSession, Single

This behavior can only be set inline, so that a system administrator cannot change it in the config.
This setting makes a big difference to how the business logic will work.

Demarcation

A service contract setting saying you can control when a transport sessions starts/ends.
These settings are properties on the OperationContract attribute.

Demarcation requires that you have a transport session.


using System.ServiceModel;

[ServiceContract]
public class IMyService
{
    [OperationContract(IsInitiating=true,IsTerminating=false)]
    void MyOperation();
}

Default values:
- IsInitiating=true meaning this operation can initiate a session
- IsTerminating=false meaning this operation will not automatically end the session

Usage example:
You can using Per Session instancing (with state across calls).
There is an initialization operation that must be called before any other operation.
So you set IsInitiating to true only on the initialization operation, and false on all others.
Therefore, the only way to start a session with the service is to call that initialization operation.

If the client calls an IsInitializing=false operation first, they'll get an InvalidOperationException with the detail "The operation cannot be the first operation to be called because IsInitializing is false".

Session Mode

Session mode is a property on the service contract attribute.

You can require that a transport session is used to communicate with the service.
That means the binding one of the following:
- TCP
- IPC
- WS-Http with reliability or security turned on

Session mode defaults to "Allowed", meaning allowed by not required. If a transport session is not used, a Per Session service will downgrade to a Per Call service.

Session mode "Required" means the client MUST use a transport session.

Session mode "NotAllowed" means the client MAY NOT use a transport session.


using System.ServiceModel;

[ServiceContract(SessionMode=SessionMode.Required)]
public class MyService : IMyService
{
}

If you try to use TCP to connect to a SessionMode="NotAllowed" service, you'll get an InvalidOperationException with a detail like "Contract does not allow Session, but Binding NetTcpBinding does not support Datagram or is not configured properly to support it".
Concurrency

Concurrency is how the service (across instances) handles locking during multiple, concurrent requests/calls from one proxy.

This is a service behavior.


using System.ServiceModel;

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single)]
public class MyService : IMyService
{
}

Single Mode

Single concurrency mode means the service (across instance) will only handle one call at a time from each proxy.
This is a very safe mode.
This is the default mode.

Ex:
The service uses Per Call instancing.
Proxy A makes three calls, causing the host to start three service instances on three different threads.
The service will still only handle one call at a time from Proxy A.
At the same time, Proxy B is making a call.
The service can handle a call from Proxy A concurrently with a call from Proxy B.

Ex:
The service uses Per Session instancing.
So all calls from Proxy A will be handled by one service instance (one thread service-side).
Proxy A uses multiple threads (client-side) to make three concurrent requests/calls to the service.
The service will still only handle one call at a time from Proxy A.

Multiple Mode

Multiple concurrency mode means the service provides no locking.
This is a dangerous mode, you'll need to provide your own locking.

Ex:
The service uses Per Session instancing.
So all calls from Proxy A will be handled by one service instance (one thread service-side).
Proxy A uses multiple threads (client-side) to make three concurrent requests/calls to the service.
If those requests access the same objects, they can step on each other and cause errors.

Reentrant Mode

Reentrant concurrency mode means the service will act like Single concurrency mode, unless the call is coming from the same proxy that caused the lock.

This is required for callbacks between service and client.

Also required for circular service calls (Service A calls B, B calls C, C calls A).

Locking

This is a brief summary.

You can only lock reference-types, not value-types.

Example usage:

lock(this)
{
    valueField++;
}
Now this code block can only be run by one thread at a time.

To lock a static resource:

public static class MyStaticResource
{
    private static object _Lock = new object();

    public static void DoOperation()
    {
        lock(_Lock)
        {
            //stuff
        }
    }
}
Transactions

About

A transaction is about ensuring that an operation ends (on success or failure) with the system in a consistent state.
On a success, every step in the operation completed.
On a failure, every step in the operation was rolled back.

The namespace System.Transactions supports .Net transactions.

WCF is a fully qualified transaction resource manager.

DTC stands for Distributed Transaction Coordinator. This can coordinate transactions that span multiple machines, from the client through to the database.
All resources in the chain vote on the transaction. Only if they all agree, will the transaction be committed. Any of them can have the whole transaction rolled back.

If WCF, or another transaction resource manager, starts a transaction that ends up including the database, then you do not need to manually handle the database transaction. It will be handled as part of the overall transaction. (This is called "carry in".)

Example of a service operation that needs a transaction:
You send in a shopping cart (list) of items to purchase. If one cannot be purchased, you want the whole purchase rolled back.

There is no need to make a read/get/lookup operation part of a transaction, because the system state is not changing.
It is recommended to make all insert/update/delete operations transaction-friendly. Especially when you allow flow through, you cannot know what larger operation this single operations is going to become a part of.

Terminology

I've heard these all use interchangeably:
- transaction flows in
- transaction propagates in
- transaction is carried in

Transaction Voting

Transaction voting is when each transaction resource manager is asked "should this transaction be committed"?
If anything votes "no", then the transaction is rolled back.

WCF handles transaction voting automatically.
This is based on OperationBehavior attribute TransactionAutoComplete=true property (defaults to true).
The operation will vote against a commit if an exception occurs.

using System.ServiceModel;

public MyService : IMyService
{
    [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=false)]
    public void DoSomething()
    {
        //stuff
    }
}

You can also tell an operation to vote "no" on the commit by calling:

Transaction.Current.Rollback();

If you set TransactionAutoComplete=false, then run this to vote "yes" on committing the transaction:

OperationContext.Current.SetTransactionComplete();

Example of manually voting:
You want to report back to the client which item(s) failed to process.
So you keep a record of success/failures, then vote to commit/rollback, then return the report to the client. No exceptions occur in this case.

Configuration

The endpoint binding must have TransactionFlow allowed. This must match on both the service and client bindings.

The operation contract must have the TransactionFlow attribute enabled.
"NotAllowed" is the default. Other settings are "Allowed" and "Mandatory".
- This allows (or not) a transaction started on the client side to flow/carry into this operation.
- A transaction from the client may be halted at this operation, but I think the operation is still completed?

Set the TransactionScopeRequired property on the OperationBehavior attribute.
If TransactionScopeRequired=true, this operation will vote on the transaction commit.
-- When a transaction is allowed to flow/carry in, and it does so, then that transaction continues through this operation.
-- When a transaction is not allowed to flow/carry in, this operation will start a new transaction at this point (this operation is the root of the transaction).
-- When no transaction exists yet, this operation will start a new transaction at this point.
If TransactionScoptRequired=false, this operation will not join any ongoing transaction, nor will it vote on any commit.
-- If a transaction flowed in, this operation will still complete but will not be part of the success or failure of that transaction.

Service config:

<system.serviceModel>
    <bindings>
        <netTcpBinding> <!-- or whichever type of binding it is -->
            <binding transactionFlow="true" />
        </netTcpBinding>
    </bindings>
</system.serviceModel>

Client config:

<system.serviceModel>
    <bindings>
        <netTcpBinding> <!-- or whichever type of binding it is -->
            <binding transactionFlow="true" />
        </netTcpBinding>
    </bindings>
</system.serviceModel>

Service contract:

using System.ServiceModel;

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    void DoOperation();
}

Service implementation:

using System.ServiceModel;

public class MyService : IMyService
{
    [OperationBehavior(TransactionScopeRequired=true)]
    public void DoSomethiing()
    {
        //stuff
    }
}

Sessions

When you have a sessionful service, and at least one operation with TransactionScopeRequired=true, then the service automatically becomes a Per Call service. The entire service becomes Per Call.
This is because the session boundaries are equated to the transaction boundaries.
Each session is dropped after the transaction is committed.

To be both sessionful and transactionful, set attribute ReleaseServiceInstanceOnTransactionComplete=false on the service behavior.
The default setting is "true".

This is also required when using transactions with multiple concurrency.

Service implementation:

using System.ServiceModel;

[ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete=false)]
public class MyService : IMyService
{
}

Manual Transactions

Sometimes you need to handle transactions manually.
Example: you want to save an audit report whether or not the transaction succeeds, so you can't just mark the whole operation is one transaction.
- This is called "suppressing a transaction".
Example: you want to separate an operation into multiple transactions.

If you are using Web API, this is how you'd manually implement transactions.

You'll use the System.Transactions.TransactionScope object.
This lets you start transactions, suppress transactions, and join transactions.

Manual transactions do not have auto-voting, so you must manually vote to commit or rollback.

Example:

using System.ServiceModel;
using System.Transactions;

public class MyService : IMyService
{
    [OperationBehavior(TransactionScopeRequired=false)] //this is the default setting, but by being explicit we tell other programmers not to change this
    public void DoSomething()
    {
        using(TransactionScope transactionScope = new TransactionScope())
        {
            //stuff
            
            transactionScope.Complete(); //vote to commit transaction
        }
    }
}

Other constructors:
new TransactionScope(TransactionScopeOption.Required) will use/join the current transaction or create a new one if none exists. This is the default.
new TransactionScope(TransactionScopeOption.RequiresNew) will create a new transaction just for this code block.
new TransactionScope(TransactionScopeOption.Suppress) will execute this code block outside any current transactions.

Client Transactions

A client could be a proxy, it could be another service, it could be anything.
And the client may try to propagate their transactions to your service.

If the client is also a WCF web service with automatic transactions, then no problem. The settings described above will handle transactions automatically.

If the client is using manual transactions, and your service uses Per Call instancing:
- each client call starts a new service instance
- the client may make multiple calls within one of their transactions
- the client can close the transaction before or after closing the proxy
- if the client fails the transaction (and the transaction was flowing into the service operation(s)), then it will cause the service to rollback that(those) operation(s)

If the client is using manual transactions, and your service uses Per Session instancing:
- the client must close their session (by closing the proxy) within their transaction
- so the client can make some calls on the proxy, then close the proxy, then close (and vote) on the transaction
- (the transaction and proxy can be opened in any order)
- if the client fails the transaction (and the transaction was flowing into the service operation), then it will cause the service to rollback that operation
Service Metadata

Service Metadata

Service metadata communicates the service contracts to the client. They can be published several ways:
- a WSDL file (Web Service Description Language)
- an XSD file
- a WS-policy

Metadata gives info about:
- service contracts
- data contracts
- endpoint bindings
- etc

The client will need the URL of this information.

This metadata can be used by the client to automatically generate and configure proxies for connecting to the web service.

In Visual Studio, use "Add Service Reference" to auto-generate all the proxies, contracts, and configurations you need.
This requires the SvcUtil utility, which also works through the command line.

Add Service Reference

In Visual Studio:

1) Make sure the service project is running.
2) In the client project, right-click on References > Add Service Reference > enter the url for the SVC file or base address > Go
3) Enter the namespace you want all the generated code under.
4) Ok

This will auto-generate all the contracts, proxies, and configuration you need to connect to that service.
The auto-generated code can be verbose.
This is all optional, you can write everything manually if you want, to slim it down.

Note that you should not manually edit this code and configuration - refreshing the reference will overwrite any manual changes you have made.

Exposing Metadata

For a self-hosted service (not through IIS).
I think this is only needed if you have no SVC file defined.
I think this is also only needed to allow clients to use "Add Service Reference" instead of manual setup.

Why do this?
This way, only internal computers can find the metadata. Computers outside your firewall will not be able to see it.

Option 1: you can expose the metadata through HTTP only.
- Requires the <serviceMetadata httpGetEnabled="true"> service behavior
- Requires at least one HTTP base address

Declarative:

    <system.serviceModel>
        <services>
            <service name="DemoService">
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:8080" />
                    </baseAddresses>
                </host>
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior>
                    <serviceMetadata httpGetEnabled="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>

Procedural:

using System.ServiceModel;

public class Program
{
    public static void Main(string[] args)
    {
        ServiceHost hostGeographyManager = new ServiceHost(typeof(GeographyManager), new Uri("http://localhost:8080"));
        hostGeographyManager.Open();
        hostGeographyManager.Close();
    }
}

Option 2: you can expose the metadata through a MEX endpoint on HTTP, TCP, or ICP.
- Requires the <serviceMetadata> service behavior.
- MEX stands for Metadata Exchange.

Declarative:

    <system.serviceModel>
        <services>
            <service name="DemoService">
                <host>
                    <baseAddresses>
                        <add baseAddress="net.tcp://localhost:8080/" /> <!-- so the metadata will be exposed at "net.tcp://localhost:8080/MEX" -->
                    </baseAddresses>
                </host>
                <endpoint
                    address="MEX" <!-- since this is not a protocol, WCF will look for a matching base address (tcp in this case) -->
                    binding="mexTcpBinding" <!-- for tco -->
                    contract="IMetadataExchange"
                    />
                <endpoint
                    address="GeographyService" <!-- because a net.tcp base address exists, this will located at "net.tcp://localhost:8080/GeographyService" -->
                    binding="netTcpBinding"
                    contract="GeographyLibrary.Contracts.IGeographyService"
                    />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior>
                    <serviceMetadata />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>

Procedural:

using System.ServiceModel;

public class Program
{
    public static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(GeographyManager), new Uri("net.tcp://localhost:8080"));
        
        //if you forget this part, you'll get an InvalidOperationException when adding the MEX endpoint
        ServiceMetadataBehavior metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
        if(metadataBehavior == null)
        {
            metadataBehavior = new ServiceMetadataBehavior();
            metadataBehavior.HttpGetEnabled = true;
            host.Description.Behaviors.Add(metadataBehavior);
        }
        
        host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExhangeBindings.CreateMexTcpBinding(), "MEX");
        
        host.Open();
        host.Close();
    }
}

Note that Option 1 and 2 can be used at the same time.

Example of using the auto-generated proxies:

SelectedNamespace.GeographyServiceClient proxy = new SelectedNamespace.GeographyServiceClient();
SelectedNamespace.ZipCodeData data = proxy.GetZipInfo(zipcode);
proxy.Close();
Message Exchange Patterns (MEPs)

These are the patterns of communication available between client and service.

Request/Reply

A channel is established between client and service. The client sends one request, the service sends one reply, and the channel is closed.

One Way

A channel is established between client and service. The client sends one request, and the channel is closed. The client does not expect any reply or faults to be returned.

Duplex

A channel is established between the client and service. This channel is used for multiple request/reply cycles before it is closed.

Security Scenarios

Intranet

Both the services and the clients are inside the same firewall.

The services use TCP bindings.
- The default security mode is Transport.
- The default protection level is Encrypted & Signed.

The services use Windows-based authentication and authorization.
- This is called Client Credential Type: Windows.

These are all binding settings, so both the service and the client must use the same settings.
Also, bindings are set per service contract, so you may divide your services into multiple contracts (interfaces) so that they can use different binding settings.

Web.config or App.config on service:

    <system.serviceModel>
        <services>
            <service name="GeographyManager"> <!-- this service implements both service contracts -->
                <endpoint 
                    address="net.tcp://localhost:8009/GeographyService"
                    binding="netTcpBinding"
                    contract="IGeographyService"
                    />
                <endpoint
                    address="net.tcp://localhost:8009/GeographyAdminService"
                    binding="netTcpBinding"
                    contract="IGeographyAdminService"
                    bindingConfiguration="admin"
                    />
            </service>
        </services>
        <bindings>
            <netTcpBinding>
                <binding transactionFlow="true" sendTimeout="00:20:00">
                    <security mode="None" />
                </binding>
                <binding name="admin" transactionFlow="true" sendTimeout="00:20:00">
                    <security mode="Transport"> <!-- Transport is the default in TCP, but we're setting it explicitly to be clear -->
                        <transport 
                            clientCredentialType="Windows" <!-- use a Windows token passed in from the client -->
                            protectionLevel="EncryptAndSign" <!-- EncryptAndSign is the TCP default -->
                            />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
    </system.serviceModel>
This is an intranet application, so it is assumed that anyone with access to a computer that can access this application is allowed to use the normal read operations. So there's no security (beyond the defaults) set on that service contract.
Only the administrative operations have security.

Internet

The services are inside the firewall, the clients are outside the firewall.

The services use HTTP bindings.

The services use custom certificate-based authentication and authorization.

Protection Level

In TCP, the protection levels are None, Signed, and Encrypted & Signed.
- Encrypted means the data is not legible as it passes through the pipe. It is encrypted at one end and decrypted at the other.
- When you don't use Encryption, it can be called using a "clear pipe", because the data is visible.
- Signed means that each message comes with a checksum. If the checksum does not match the message, then the message has been tampered with and it is discarded.
- The TCP default protected level is Encrypted & Signed.

You can enforce the protection level a service contract will accept:
(You can also enforce this at the operation level)

[ServiceContract(ProtectionLevel=ProtectionLevel.EncryptAndSign)]
public interface IMySecureService
{
}
This defines the minimum acceptable protection level. It escalates through None, Sign, EncryptAndSign.

If the binding protection level is less than the service contract protection level, you'll get an error like "The request message must be protected. This is required by an operation of the contract."
Identities


using System.Security.Principal;

//type IIdentity
//string IIdentity.Name, Windows example "DOMAIN\\username"

The "host identity" or "token identity" is the identity of the host process. It is used to access resources on the file system, in the registry, or in a database.

IIdentity hostIdentity = WindowsIdentity.GetCurrent();
string name = hostIdentity.Name;

The "primary identity" or "client identity" is the identity that the client passes to the service. This identity is accessible after the service constructor starts.

//available in the WCF application
IIdentity primaryIdentity = ServiceSecurityContext.Current.PrimaryIdentity;
If security is turned off on the binding, then primary identity will be null.

The "Windows identity" will be the same as the "primary identity" when Windows authentication is being used. Otherwise it will be null.

IIdentity windowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;

The "thread identity" (after the service constructor has completed) will be the same as the "primary identity".

//available in anything running downstream (on the same thread) of the WCF application
IIdentity threadIdentity = Thread.CurrentPrincipal.Identity;

Authentication

Authentication is the act of determining what user is using the system.

Windows

The client will create a Windows token and pass it to the service.
The Windows token will be based on the how the current user is logged into Windows.
- If the client is a desktop application, then the Windows identity will be the user logged into that machine.
- If the client is an internet web application, then the Windows identity will be whatever IIS is running as on that machine.

You can also send a non-default Windows identity through the proxy.

Alternate Credentials

You can send non-default credentials/identity to the client proxy.

public void ClientOperation()
{
    GeographyClient proxy = new GeographyClient();
    
    //this must still be a valid Windows user on the current machine
    proxy.ClientCredentials.Windows.ClientCredentials.UserName = "otherUser";
    proxy.ClientCredentials.Windows.ClientCredentials.Domain = "otherDomain"; //optional
    proxy.ClientCredentials.Windows.ClientCredentials.Password = "password";
    
    var result = proxy.MyOperation();

    proxy.Close();
}
Authorization

Authorization is the act of deciding if the current user is allowed to run a particular operation.

Windows

Authorization is against the Primary Identity.

A Windows Principal is created, wrapping the Primary Identity and its associated Roles (Windows Groups, in this case). That principal is placed on the current thread.

using System.Security.Principal;

IPrincipal principal = Thread.CurrentPrincipal;

Authorize Operation

Require the principal has a particular role to be able to run this operation:

public class MyService : IMyService
{
    [PrincipalPermission(SecurityAction.Demand, Role="Administrators")]
    public void MyOperation()
    {
    }
}
This attribute is not specific to WCF, so you can use it downstream on other business objects.

The PrincipalPermission attribute just makes a call to:

bool isAuthorized = Thread.CurrentPrincipal.IsInRole(stringRole);
You can authorize based on a specific username, but don't do that. Always authorize based on roles the user has.

Make sure the user is authenticated, but it doesn't matter what roles they have:

public class MyService : IMyService
{
    [PrincipalPermission(SecurityAction.Demand)]
    public void MyOperation()
    {
    }
}
So no anonymous users allowed. This can be useful if you want to enable logging of who does what.
Unit Testing

Testable Code

To make it possible to automate testing of your code:
- Do not instantiate dependencies.

Example of instantiating a dependency:

using System.ServiceModel;

public class GeographyManager : IGeographyService
{
    public CountryData GetCountryInfo(string country)
    {
        CountryData countryData = null;
        ICountryRepository countryRepository = new CountryRepository();
        Country countryEntity = countryRepository.GetByName(country);
        if(countryEntity != null)
        {
            countryData = new CountryData() {
                Name = countryEntity.Name,
                Capital = countryEntity.Capital,
                Flag = countryEntity.Flag
            };
        }
        return countryData;
    }
}

Example of injecting the dependency instead:
When the service implementation is instantiated by the application, the repositories will be null, so they will be instantiated by the service implementation.
When the service implementation is instantiated by the unit test, the repositories will be injected.

using System.ServiceModel;

public class GeographyManager : IGeographyService
{
    private ICountryRepository _CountryRepository = null;

    public GeographyManager() {} //default constructor used by the application
    
    public GeographyManager(ICountryRepository countryRepository) //dependency injection constructor used by unit tests
    {
        _CountryRepository = countryRepository;
    }
    
    public CountryData GetCountryInfo(string country)
    {
        CountryData countryData = null;
        ICountryRepository countryRepository = _CountryRepository ?? new CountryRepository();
        Country countryEntity = countryRepository.GetByName(country);
        if(countryEntity != null)
        {
            countryData = new CountryData() {
                Name = countryEntity.Name,
                Capital = countryEntity.Capital,
                Flag = countryEntity.Flag
            };
        }
        return countryData;
    }
}

Alternate dependency injection logic:

using System.ServiceModel;

public class GeographyManager : IGeographyService
{
    private ICountryRepository _countryRepository = null;
    private ICountryRepository CountryRepository {
        get {
            if(_countryRepository == null)
                _countryRepository = new CountryRepository();
            return _countryRepository;
        }
    }

    public GeographyManager() {} //default constructor used by the application
    
    public GeographyManager(ICountryRepository countryRepository) //dependency injection constructor used by unit tests
    {
        _countryRepository = countryRepository;
    }
    
    public CountryData GetCountryInfo(string country)
    {
        CountryData countryData = null;
        Country countryEntity = CountryRepository.GetByName(country);
        if(countryEntity != null)
        {
            countryData = new CountryData() {
                Name = countryEntity.Name,
                Capital = countryEntity.Capital,
                Flag = countryEntity.Flag
            };
        }
        return countryData;
    }
}

Exception Handling

SOAP Faults

CLR exceptions will not pass directly from service to client.
Passing the exception is simulated with SOAP faults.

The service converts an uncaught exception into a SOAP fault and sends it to the client.
The client converts the SOAP fault into a CLR exception and throws it.

Unhandled Exceptions

If IncludeExceptionDetailInFaults=False, then the client will receive only the most generic information about an unhandled exception.
The client will only receive a FaultException (with a detail like "The server was unable to process the request due to an internal error").
This leaves the proxy in a faulted state. You cannot use this proxy again.

If IncludeExceptionDetailInFaults=True, then the client will receive details about an unhandled exception.
The client will receive a FaultException<ExceptionDetail>.
But the proxy will still be in a faulted state, and cannot be used again.

Note that IncludeExceptionDetailInFaults might be set through config, so it might be easy for someone to change it without warning.

Solid rule: handle ALL exceptions on the service.

Handled Exceptions

This is the minimum recommendation for handling exceptions on the service.

Catch all exceptions on the service.
Re-throw them as FaultExceptions.
In this case, the exception details will be included and the proxy will no be left in a faulted state.

?How do the service and client see this different from an automatic FaultException?

This is the better recommendation:
Catch all exceptions on the service.
Re-throw then as FaultException<T>.
In this case, the exception details will be included and the proxy will no be left in a faulted state.
In addition, the client can be specific about what type of exceptions to catch.
- T can be an Exception class or a custom fault contract.
- T must be known ahead of time, and the operation contract must have the FaultContract attribute.


public class MyService : IMyService
{
    public void DoOperation()
    {
        throw new FaultException<ApplicationException>(new ApplicationException(message), reason);
    }
}

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    [FaultContract(typeof(ApplicationException))]
    void DoOperation();
}

Custom Fault Contract

A custom fault contract is just a data contract that is used within a FaultException<T>.


public class MyService : IMyService
{
    public void DoOperation()
    {
        throw new FaultException<MyCustomFault>(new MyCustomFault(message), reason);
    }
}

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    [FaultContract(typeof(MyCustomFault))]
    void DoOperation();
}

[DataContract]
public class MyCustomFault
{
    [DataMember]
    public string Message { get; set; }
    
    public MyCustomFault(string message)
    {
        Message = message;
    }
}