WCF Behavior
Common Tweaks
The maximum message size quota for incoming messages (65536) has been exceeded.
- increase maxReceivedMessageSize!
Throttling: maxConcurrentCalls.
InstanceContextMode
PerCall is default (NB: goes on implementation, not interface)
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1 : IService
Sessions
If you use sessions, the contract must state for the client
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IService
And then implement it
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service1 : IService
If the client tries to use an open session after it expired, it gets a CommunicationObjectFaultedException. The default is 10 minutes - see ReliableSession.InactivityTimeout and Binding.ReceiveTimeout (you can set "infinite" but IIS will recycle you anyway). basicHttpBinding does not support sessions.
[OperationContract(IsInitiating = false, IsTerminating = true)]
Response Final(int number);
- IsInitiating
- (Default true)- create a session or use existing.
If set to false, cannot open a session. - IsTerminating
- (Default false)- close a session (still need the proxy to Close)
Singleton
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService
It supports clients who uses sessions, but obviously everything must be thread-safe. You can create a self-hosted service passing in the singleton into the constructor.
Instance Behaviors
[OperationBehavior(ReleaseInstanceMode =
ReleaseInstanceMode.BeforeAndAfterCall)]
public void UpdateResource()
- BeforeCall
- creates new instance (disposes any existing instance)
- AfterCall
- disposed when finished
- BerforeAndAfterCall
- InstanceContextMode.PerCall (for one method while the others have sessions)
Concurrency
You can queue requests with Single concurrency (or Multiple to handle simultaneous calls)
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single)]
public class Service1 : IService
Reentrant is locked like Single, but can release locks which processing (inner WCF calls)
Duplex messaging
Because it does a callback, these must be ConcurrencyMode = ConcurrencyMode.Multiple or Reentrant (not single).
Transactions
See also contracts where you can specify [TransactionFlow(TransactionFlowOption.Mandatory)]
//requires transaction and will commit when finished
[OperationBehavior(TransactionScopeRequired = true)]
public void DoWork()
MSMQ transactions can't span both ends of the queue, but you can do batch transactions by adding an endpointBehavior with <transactedBatching maxBatchSize="100"/>.
On the service implementation add [ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete = false)] so the instance keeps alive through the batch
Anonymous Behavior
In .Net 4.0+, you don't need a <service> configuration with endpoints at all- it can autogenerate for your contracts and schema (default for http is basicHttpBinding). Change the mappings (http default with <protocolMapping><add scheme="http" binding="wsHttpBinding" bindingConfiguration="MyBindingConfiguration"/>
Unnamed behavior elements (or name="") refer to the current service.
WCF Runtime Extensibility
You add an IEndpointBehavior which implements ApplyClient/ApplyDispatchBahvior or ApplyBindingParameters:
endpoint.Behaviors.Add(myIEndpointBehavior)
public class LoggingEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
{ }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
//implements IClientMessageInspector
var inspector = new MessageLogInspector();
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
//implements IDispatchMessageInspector
var inspector = new MessageLogInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}
public void Validate(ServiceEndpoint endpoint)
{ }
}
- IParameterInspector (BeforeCall/ AfterCall):
- Server: add in IEndpointBehavior.ApplyDispatchBehavior
- Client: add in IEndpointBehavior.ApplyClientBehavior
- MessageInspectors-
on client, IClientMessageInspector (BeforeSendRequest, AfterReceiveReply),
on service, IDispatchClientInspector (AfterReceiveRequest, BeforeSendReply).
A serialized message body is a stream, so can be read only once (by ToString() or GetBody<T>())- so use a buffered copy
var buffer = request.CreateBufferedCopy(Int32.MaxValue)
var x = buffer.CreateMessage().GetBody<T>()
To modify it through a configuration file (in extensions/behaviorExtensions- the name can then be an element under endpointBehaviors/behavior/), derive from BehaviorExtensionElement (CreateBehavior())