Instance Management
Basically there are three instance modes in WCF:
Configuration:
Instance mode can be configured using ServiceBehavior attribute. This can be specified at implementing the service contract as shown below. [ServiceContract()]
public interface IMyService
{
[OperationContract]
int MyMethod();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyService:IMyService
{
public int MyMethod()
{
//Do something
}
}
Per-Call Service
When WCF service is configured for Per-Call instance mode,
Service instance will be created for each client request. This Service
instance will be disposed after response is sent back to client.
Following diagram represent the process of handling the request from client using Per-Call instance mode.
Let as understand the per-call instance mode using example.Following diagram represent the process of handling the request from client using Per-Call instance mode.
Step 1:
Create the service contract called IMyService and implement the
interface. Add service behavior attribute to the service class and set
the InstanceContextMode property to PerCall as show below.
[ServiceContract()] public interface IMyService { [OperationContract] int MyMethod(); }
Step 2:
In this implementation of MyMethod operation, increment the static
variable(m_Counter). Each time while making call to the service,
m_Counter variable is incremented and return the value to the client.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)] public class MyService:IMyService { static int m_Counter = 0; public int MyMethod() { m_Counter++; return m_Counter; } }
Step 3:
Client side, create the proxy for the service and call "myMethod" operation multiple time.
Surprisingly, all requests to service return '1', because we
configured the Instance mode to Per-Call. Service instance will created
for each request and value of static variable will be set to one. While
return back, service instance will be disposed. Output is shown below.
Fig: PercallOutput.static void Main(string[] args) { Console.WriteLine("Service Instance mode: Per-Call"); Console.WriteLine("Client making call to service..."); //Creating the proxy on client side MyCalculatorServiceProxy.MyServiceProxy proxy = new MyCalculatorServiceProxy.MyServiceProxy(); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.ReadLine(); }
Per-Session Service
When WCF service is configured for Per-Session instance mode,
logical session between client and service will be maintained. When the
client creates new proxy to particular service instance, a dedicated
service instance will be provided to the client. It is independent of
all other instance.
Following diagram represent the process of handling the request from client using Per-Session instance mode.
Let as understand the Per-Session instance mode using example.
Following diagram represent the process of handling the request from client using Per-Session instance mode.
Let as understand the Per-Session instance mode using example.
Step 1:
Create the service contract called IMyService and implement the
interface. Add service behavior attribute to the service class and set
the InstanceContextMode property to PerSession as show below.
[ServiceContract()] public interface IMyService { [OperationContract] int MyMethod(); }
Step 2:
In this implementation of MyMethod operation, increment the static
variable (m_Counter). Each time while making call to the service,
m_Counter variable will be incremented and return the value to the
client.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] public class MyService:IMyService { static int m_Counter = 0; public int MyMethod() { m_Counter++; return m_Counter; } }
Step 3:
Client side, create the proxy for the service and call "myMethod" operation multiple time.
All request to service return incremented value (1, 2, 3, 4), because
we configured the instance mode to Per-Session. Service instance will
be created once the proxy is created at client side. So each time
request is made to the service, static variable is incremented. So each
call to MyMethod return incremented value. Output is shown below.
Fig: PersessionOutput.static void Main(string[] args) { Console.WriteLine("Service Instance mode: Per-Session"); Console.WriteLine("Client making call to service..."); //Creating the proxy on client side MyCalculatorServiceProxy.MyServiceProxy proxy = new MyCalculatorServiceProxy.MyServiceProxy(); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.ReadLine(); }
Singleton Service
When WCF service is configured for Singleton instance mode, all
clients are independently connected to the same single instance. This
singleton instance will be created when service is hosted and, it is
disposed when host shuts down.
Following diagram represent the process of handling the request from client using Singleton instance mode.
Let as understand the Singleton Instance mode using example.
Following diagram represent the process of handling the request from client using Singleton instance mode.
Let as understand the Singleton Instance mode using example.
Step 1:
Create the service contract called IMyService and implement the
interface. Add service behavior attribute to the service class and set
the InstanceContextMode property to Single as show below.
[ServiceContract()] public interface IMyService { [OperationContract] int MyMethod(); }
Step 2:
In this implementation of MyMethod operation, increment the static
variable(m_Counter). Each time while making call to the service,
m_Counter variable is incremented and return the value to the client
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class MyService:IMyService { static int m_Counter = 0; public int MyMethod() { m_Counter++; return m_Counter; } }
Step 3:
Client side, create the two proxies for the service and made a multiple call to MyMethod.
When two proxy class made a request to service, single instance at
service will handle it and it return incremented value (1, 2, 3, 4),
because instance mode is configured to 'Single'. Service instance is
created when it is hosted. So this instance will remain till host is
shutdown. Output is shown below.
Fig: SingletonOutput.static void Main(string[] args) { Console.WriteLine("Service Instance mode: Singleton"); Console.WriteLine("Client 1 making call to service..."); //Creating the proxy on client side MyCalculatorServiceProxy.MyServiceProxy proxy = new MyCalculatorServiceProxy.MyServiceProxy(); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Counter: " + proxy.MyMethod()); Console.WriteLine("Client 2 making call to service..."); //Creating new proxy to act as new client MyCalculatorServiceProxy.MyServiceProxy proxy2 = new MyCalculatorServiceProxy.MyServiceProxy(); Console.WriteLine("Counter: " + proxy2.MyMethod()); Console.WriteLine("Counter: " + proxy2.MyMethod()); Console.ReadLine(); }
Instance Deactivation
In Instance Management System tutorial, you learn how to create
sessionful service instance. Basically service instance is hosted in a
context. Session actually correlated the client message not to the
instance, but to the context that host it. When session starts, context
is created and when it closes, context is terminated. WCF provides the
option of separating the two lifetimes and deactivating the instance
separately from its context.
ReleaseInstanceMode property of the OberationalBehavior attribute used to control the instance in relation to the method call.
Followings are the list Release mode available in the ReleaseInstanceMode
ReleaseInstanceMode property of the OberationalBehavior attribute used to control the instance in relation to the method call.
Followings are the list Release mode available in the ReleaseInstanceMode
- RealeaseInstanceMode.None
- RealeaseInstanceMode.BeforeCall
- RealeaseInstanceMode.AfterCall
- RealeaseInstanceMode.BeforeAndAfterCall
Below code show, how to add the 'ReleaseInstanceMode' property to the operational behavior.
[ServiceContract()]
public interface ISimpleCalculator
{
[OperationContract()]
int Add(int num1, int num2);
}
[OperationBehavior(ReleaseInstanceMode=ReleaseInstanceMode.BeforeCall]
public int Add(int num1, int num2)
{
return num1 + num2;
}
ReleaseInstanceMode.None
This property means that it will not affect the instance lifetime. By default ReleaseInstanceMode property is set to 'None'.ReleaseInstanceMode.BeforeCall
This property means that it will create new instance before a call is made to the operation.If the instance is already exist,WCF deactivates the instance and calls Dispose() before the call is done. This is designed to optimize a method such as Create()
ReleaseInstanceMode.AfterCall
This property means that it will deactivate the instance after call is made to the method.This is designed to optimize a method such a Cleanup()
ReleaseInstanceMode.BeforeAndAfterCall
This is means that it will create new instance of object before a call and deactivates the instance after call. This has combined effect of using ReleaseInstanceMode.BeforeCall and ReleaseInstanceMode.AfterCallExplicit Deactivate
You can also explicitly deactivate instance using InstanceContext object as shown below. [ServiceContract()]
public interface IMyService
{
[OperationContract]
void MyMethod();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyService:IMyService
{
public void MyMethod()
{
//Do something
OperationContext.Current.InstanceContext.ReleaseServiceInstance();
}
}
Durable Service
Durable services are WCF services that persist service state
information even after service host is restarted or Client. It means
that durable services have the capability to restore their own state
when they are recycled. It can use data store like SQL database for
maintain instance state. It is new feature in .Net 3.5
You might think that we can also maintain session using WCF sessions, but content in the session environment is not persisted by default. If the service is shut down or client closes the proxy, data will be lost. But in case of Durable service it is still maintained.
You might think that we can also maintain session using WCF sessions, but content in the session environment is not persisted by default. If the service is shut down or client closes the proxy, data will be lost. But in case of Durable service it is still maintained.
Working:
When Durable service is created with database as data store, it will maintain all its state information in the table.When a client make a request to the service, instance of the service is serialized, a new GUID is generated. This serialized instance xml and key will be saved in the database. We will call this GUID as instanceID. Service will send the instanceID to the client, so later it can use this id to get the instance state back. Even when client is shut down, instanceId will be saved at the client side. So when ever client opening the proxy, it can get back the previous state.
Defining the Durable Service
Durable service can be implemented using [DurableService()] attribute. It takes 'CanCreateInstance' and 'CompletesInstance' property to mention on which operation instance state has to be saved and destroyed.- CanCreateInstance = true: Calling this operation results in creating the serialization and inserting it into the datastore.
- CompletesInstance = true: Calling this operation results in deleting the persisted instance from the datastore.
[Serializable] [DurableService()] public class MyService :IMyservice { [DurableOperation(CanCreateInstance = true)] public int StartPersistance() { //Do Something } [DurableOperation(CompletesInstance = true)] public void EndPersistence() { //Do Something } }
How to Create Durable Service
Step 1:
Start the Visual Studio 2008 and click File->New->Web Site. Select the 'WCF Service' as shown below.
Step 2:
Create interface and decorate with Service and Operation contract.
[ServiceContract()] public interface ISimpleCalculator { [OperationContract] int Add(int num); [OperationContract] int Subtract(int num); [OperationContract] int Multiply(int num); [OperationContract] void EndPersistence(); }
Step 3:
You need to add [Serializable] And [DurableService()] attribute to the
service implementation. Set CanCreateInstance = true property to the
operation in which instance state has to be persisted and set
CompletesInstance = true when state has to be destroyed. In this
implementation, we are going to persist the 'currentValue' variable
value to the database.
using System.Runtime.Serialization; using System.ServiceModel; using System.Text; using System.ServiceModel.Description; [Serializable] [DurableService()] public class SimpleCalculator :ISimpleCalculator { int currentValue = default(int); [DurableOperation(CanCreateInstance = true)] public int Add(int num) { return (currentValue += num); } [DurableOperation()] public int Subtract(int num) { return (currentValue -= num); } [DurableOperation()] public int Multiply(int num) { return (currentValue *= num); } [DurableOperation(CompletesInstance = true)] public void EndPersistence() { }
Step 4:
Before configuring the database information in the durable service, you
need to set up DataStore environment. Microsoft provides inbuilt
sqlPersistance provider. To set up the database environment, run the
these sql query located at following location
'C:\Windows\Microsoft.NET\Framework\v3.5\SQL\EN'
- SqlPersistenceProviderSchema.sql
- SqlPersistenceProviderLogic.sql
Step 5:
In order to support durable service, you need to use Context binding type. <persistenceProvider> tag is used to configure the persistence provider.
<system.serviceModel> <services> <service name="SimpleCalculator" behaviorConfiguration="ServiceBehavior"> <!-- Service Endpoints --> <endpoint address="" binding="wsHttpContextBinding" bindingConfiguration="browConfig" contract="ISimpleCalculator"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> <persistenceProvider type="System.ServiceModel.Persistence.SqlPersistenceProviderFactory, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DurableServiceStore" persistenceOperationTimeout="00:00:10" lockTimeout="00:01:00" serializeAsText="true"/> </behavior> </serviceBehaviors> </behaviors> <bindings> <wsHttpContextBinding > <binding name="browConfig" > <security mode="None"></security> </binding> </wsHttpContextBinding> </bindings> </system.serviceModel> <connectionStrings> <add name="DurableServiceStore" connectionString="Data Source=saravanakumar;Initial Catalog =DurableServiceStore;Integrated Security=True"/> </connectionStrings>
Step 6:
Create the console client application and name it as DurableServiceClient
Step 7:
Add following reference to client application
- System.ServiceModel
- System.WorkflowService
Step 8:
Add WCF service as Service Reference to the project and name it as SimpleCalculatorService
Step 9:
Create the Helper class called it as Helper.cs. This helper class is
used to Store, Retrieve and set the context at the client side. Context
information will be saved in 'token_context.bin' file. Copy and paste
the below code to your helper file.
Helper.cs
Helper.cs
using System.ServiceModel.Channels; using System.ServiceModel; using System.Net; using System.IO; using System.Runtime.Serialization.Formatters.Binary; public class Helper { static readonly String TokenContextFileName = "token_context.bin"; public static IDictionary<String, String> LoadContext() { IDictionary<String, String> ctx = null; try { using (FileStream fs = new FileStream(TokenContextFileName, FileMode.Open, FileAccess.Read)) { BinaryFormatter bf = new BinaryFormatter(); ctx = bf.Deserialize(fs) as IDictionary<String, String>; fs.Close(); } } catch (Exception ex) { } return ctx; } public static void SaveContext(IClientChannel channel) { IDictionary<String, String> ctx = null; IContextManager cm = channel.GetProperty<IContextManager>(); if (cm != null) { ctx = cm.GetContext() as IDictionary<String, String>; try { using (FileStream fs = new FileStream(TokenContextFileName, FileMode.CreateNew)) { BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(fs, ctx); fs.Close(); } } catch (Exception ex) { } } } public static void DeleteContext() { try { File.Delete(TokenContextFileName); } catch (Exception ex) { } } public static void SetContext(IClientChannel channel, IDictionary<String, String> ctx) { IContextManager cm = channel.GetProperty<IContextManager>(); if (cm != null) { cm.SetContext(ctx); } } }
Step 10:
In the main method, I was creating the proxy for the service and calling
the Add operation. Call to this method will add instance state to the
database. Now I have closed the proxy and creating new proxy instance.
When I call the Subtract and Multiply operation, it will operate on the
previously saved value (instance state).
End of the proxy 1, service instance saved in the database as shown below.
Serialized XML instance state save in the database is shown below.
Output of the client application.
static void Main(string[] args) { //Create the proxy for the service SimpleCalculatorService.SimpleCalculatorClient client = new SimpleCalculatorService.SimpleCalculatorClient "WSHttpContextBinding_ISimpleCalculator"); int currentValue = 0; //Call the Add method from the service currentValue = client.Add(10000); Console.WriteLine("The current value is {0}", currentValue); //Save the Context from the service to the client Helper.SaveContext(client.InnerChannel); //Close the proxy client.Close(); //Create new Instance of the proxy for the service client = new SimpleCalculatorService.SimpleCalculatorClient ("WSHttpContextBinding_ISimpleCalculator"); //Load the context from the client to start from saved state IDictionary<string,string> cntx=Helper.LoadContext(); //Set Context to context manager Helper.SetContext(client.InnerChannel, cntx); //Call the Subtract and Multiply method from service currentValue = client.Subtract(2); Console.WriteLine("The current value is {0}", currentValue); currentValue = client.Multiply(5); Console.WriteLine("The current value is {0}", currentValue); //Delete the context from the client Helper.DeleteContext(); //Remove persistance state from the server client.EndPersistence(); Console.WriteLine("Press <ENTER> to shut down the client."); Console.ReadLine(); client.Close(); }
Serialized XML instance state save in the database is shown below.
Output of the client application.
Throttling
Attribute | Description |
---|---|
maxConcurrentCalls | Limits the total number of calls that can currently be in progress across all service instances. The default is 16. |
maxConcurrentInstances | The number of InstanceContext objects that execute at one time across a ServiceHost. The default is Int32.MaxValue. |
maxConcurrentSessions | A positive integer that limits the number of sessions a ServiceHost object can accept. The default is 10. |
Administrative(configuration file)
Using <serviceThrottling> tag of the Service Behavior, you can configure the maxConcurrentCalls, maxConcurrentInstances , maxConcurrentSessions property as shown below.
<system.serviceModel> <services > <service behaviorConfiguration="ServiceBehavior" name="MyService"> <endpoint address="" binding="wsHttpBinding" contract="IMyService"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true "/> <serviceThrottling maxConcurrentCalls="500" maxConcurrentInstances ="100" maxConcurrentSessions ="200"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
Programming Model
Use ServiceThrottlingBehavior object to set concurrent calls, session and instance property.ServiceHost host = new ServiceHost(typeof(MyService)); ServiceThrottlingBehavior throttle = host.Description.Behaviors.Find(); if (throttle == null) { throttle = new ServiceThrottlingBehavior(); throttle.MaxConcurrentCalls = 500; throttle.MaxConcurrentSessions = 200; throttle.MaxConcurrentInstances = 100; host.Description.Behaviors.Add(throttle); } host.Open();
Operations
In classic object or component- oriented programming model
offered only single way for client to call a method. Client will issue a
call, block while the call was in progress, and continue executing once
the method returned.
WCF will support classical Request-Replay model, along with that it also supports One-Way call(call and forget operation) and callback(service to call back the client)
Three modes of communication between client and service are
WCF will support classical Request-Replay model, along with that it also supports One-Way call(call and forget operation) and callback(service to call back the client)
Three modes of communication between client and service are
Request-Reply
By default all WCF will operated in the Request-Replay mode. It
means that, when client make a request to the WCF service and client
will wait to get response from service (till receiveTimeout).
After getting the response it will start executing the rest of the
statement. If service doesn't respond to the service within
receiveTimeout, client will receive TimeOutException.
Apart from NetPeerTcpBinding and the NetMsmqBinding all other bindings will support request-reply operations.
Apart from NetPeerTcpBinding and the NetMsmqBinding all other bindings will support request-reply operations.
One-Way
In One-Way operation mode, client will send a request to the
server and does not care whether it is success or failure of service
execution. There is no return from the server side, it is one-way
communication.
Client will be blocked only for a moment till it dispatches its call to service. If any exception thrown by service will not reach the server.
Client can continue to execute its statement, after making one-way call to server. There is no need to wait, till server execute. Sometime when one-way calls reach the service, they may not be dispatched all at once but may instead be queued up on the service side to be dispatched one at a time, according to the service's configured concurrency mode behavior. If the number of queued messages has exceeded the queue's capacity, the client will be blocked even if it's issued a one-way call. However, once the call is queued, the client will be unblocked and can continue executing, while the service processes the operation in the background.
Client will be blocked only for a moment till it dispatches its call to service. If any exception thrown by service will not reach the server.
Client can continue to execute its statement, after making one-way call to server. There is no need to wait, till server execute. Sometime when one-way calls reach the service, they may not be dispatched all at once but may instead be queued up on the service side to be dispatched one at a time, according to the service's configured concurrency mode behavior. If the number of queued messages has exceeded the queue's capacity, the client will be blocked even if it's issued a one-way call. However, once the call is queued, the client will be unblocked and can continue executing, while the service processes the operation in the background.
Definition :
One-way operation can be enabled by setting IsOneWay property to true in Operation contract attribute.[ServiceContract] public interface IMyService { [OperationContract(IsOneWay=true)] void MyMethod(EmployeeDetails emp); }
One-Way Operations and Sessionful Services
Let us see the example, what will happen when you use the one-way communication with Sessionful service.[ServiceContract(SessionMode = SessionMode.Required)] interface IMyContract { [OperationContract(IsOneWay = true)] void MyMethod(); }
Suppose If you want to make use of One-way operation in Sessionful service, use in the last operation of the service which will terminate the session. This operation should not return any value.
[ServiceContract(SessionMode = SessionMode.Required)] interface IMyContract { [OperationContract] void MyMethod1(); [OperationContract] string MyMethod2(); [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)] string CloseSessionService(int id); }
One-Way Operations and Exceptions
Suppose when we are using BasicHttpBinding or WSHttpBinding, i.e. no transport session is used, if any exception throw by service will not affect the client. Client can make a call to the service using same proxy[ServiceContract] interface IMyContract { [OperationContract(IsOneWay = true)] void MethodWithError( ); [OperationContract] void MethodWithoutError( ); } //Client side without transport session MyContractClient proxy = new MyContractClient( ); proxy.MethodWithError( ); //No exception is thrown from serivce proxy.MethodWithoutError( ); //Operation will execute properly proxy.Close( );
In the presence of transport session, any exception thrown by
service will fault the client channel. Client will not be able to make
new call using same proxy instance.
//Client side transport session MyContractClient proxy = new MyContractClient( ); proxy.MethodWithError( ); proxy.MethodWithoutError( ); //Can not executre because channel is faulted proxy.Close( );
Callback Service
Till now we have seen that the all clients will call the service
to get the things done. But WCF also provides the service to call the
client. In which, service will act as client and client will act as
service.
- HTTP protocols are connectionless nature, so it is not supported for callback operation. So BasicHttpBinding and WSHttpBinding cannot be used for this operation.
- WCF support WSDualHttpBinding for call back operation.
- All TCP and IPC protocols support Duplex communication. So all these binding will be used for callback operation.
Defining and configuring a callback contract
Callback service can be enabled by using CallbackContract property in the ServiceContract attribute. In the below example you can find the decalration of the callback contract and it is configured in the ServiceContract attribute.public interface IMyContractCallback { [OperationContract] void OnCallback(); } [ServiceContract(CallbackContract = typeof(IMyContractCallback))] public interface IMyContract { [OperationContract()] void MyMethod(); }
Client Callback Setup
As I said earlier, in callback operation client will act as service and service will act as client. So client has to expose a callback endpoint to the service to call. In the earlier part of the tutorial I have mention that InstanceContext is the execution scope of inner most service instance. It provides a constructor that takes the service instance to the host.IMyContractCallback callback=new MyCallback(); InstanceContext cntx=new InstanceContext(callback); MyServiceClient proxy = new MyServiceClient(cntx); proxy.MyMethod();
class MyServiceClient:DuplexClientBase,IMyContract { public MyServiceClient(InstanceContext callbackCntx) : base(callbackCntx) { } public void MyMethod() { base.Channel.MyMethod(); } }
Service-Side Callback Invocation
The client-side callback endpoint reference is passed along with
every call the client makes to the service, and it is part of the
incoming message. The OperationContext class provides the service with
easy access to the callback reference via the generic method GetCallbackChannel<T>(
).
Service can call the client side callback method using reference e to
the client side callback instance. The following code shows the callback
method invocation.
IMyContractCallback callbackInstance=OperationContext.Current.GetCallbackChannel(); callbackInstance.OnCallback();
How to Create Callback Service in WCF
Step 1:
Create the sample Classlibrary project using Visual Studio 2008 and name it as CallbackService
Step 2 :
Add System.ServiceModel reference to the project
Step 3:
Create the Callback and Service contract as shown below. You need to mention CallbackContract property in the ServiceContract attribute. Implementation of the Callback contract will be done on the client side.
IMyContract.cs
IMyContract.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace CallbackService { public interface IMyContractCallback { [OperationContract] void OnCallback(); } [ServiceContract(CallbackContract = typeof(IMyContractCallback))] public interface IMyContract { [OperationContract()] void MyMethod(); } }
Step 4:
Implement the Service contract as shown below. In the below code you will find using OperationContext is used to receive the reference to Callback instance. Using that instance we are calling the OnCallback() method from client side.
MyService.cs
MyService.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace CallbackService { [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple )] public class MyService:IMyContract { public void MyMethod() { //Do something IMyContractCallback callbackInstance =OperationContext.Current.GetCallbackChannel(); callbackInstance.OnCallback(); } } }
You can also note that We have set the ConcurrencyMode to
Multile. If you are not using ConcurrencyMode to Multiple or Reentent,
you will be end up with deadlock exception as shown below. This is
because when a client made a call to the service, channel is created and
lock by WCF service. If you are calling the Callback method inside the
service method. Service will try to access the lock channel, this may
leads to deadlock. So you can set ConcurrencyMode to Multiple or Reentent so it will release the lock silently.
Step 5:
Create a Console application using Visual Studio 2008 and name it a
CallbackServiceHost. This application is used to self-host the WCF
service
Step 6:
Main method
static void Main(string[] args) { Uri httpUrl = new Uri("http://localhost:8090/MyService/"); ServiceHost host = new ServiceHost(typeof(CallbackService.MyService), httpUrl); host.Open(); Console.WriteLine("Service is Hosted at {0}", DateTime.Now.ToString()); Console.WriteLine("Host is running...Press key to stop the service."); Console.ReadLine(); host.Close(); }
Step 7:
Use Duplex binding to support Callback operation.
Web.Config
Web.Config
<system.serviceModel> <services > <service behaviorConfiguration="ServiceBehavior" name="CallbackService.MyService"> <endpoint address="http://localhost:8090/MyService" binding="wsDualHttpBinding" contract="CallbackService.IMyContract"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true "/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
Step 8:
Run the host application
Step 9:
Create Console Application using Visual Studio 2008 and name it as
CallbackClient. This is the client application which contain Callback
implementation.
Step10:
Add System.ServiceModel and CallbackService as reference to the project
Step 11:
Create the proxy class as shown below. Use DuplexClientBase to create the proxy, because it will support bidirectional communication. Create the contractor which will accept InstanceContext as parameter.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using CallbackService; namespace CallbackClient { class MyServiceClient:DuplexClientBase<IMyContract>,IMyContract { public MyServiceClient(InstanceContext callbackCntx) : base(callbackCntx) { } public void MyMethod() { base.Channel.MyMethod(); } } }
Step12:
Create the implementation for Callback Contract
class MyCallback : IMyContractCallback { public void OnCallback() { Console.WriteLine("Callback method is called from client side."); } }
Step 13:
Implementation of main method
static void Main(string[] args) { IMyContractCallback callback=new MyCallback(); InstanceContext cntx=new InstanceContext(callback); MyServiceClient proxy = new MyServiceClient(cntx); Console.WriteLine("Client call the MyMethod Operation from Service."); proxy.MyMethod(); Console.ReadLine(); }
Step14:
Run the client application. In the output, you can see the OnCallback method called by the service
Events
Events allow the client or clients to be notified about
something that has occurred on the service side. An event may result
from a direct client call, or it may be the result of something the
service monitors. The service firing the event is called the publisher,
and the client receiving the event is called the subscriber.
- Publisher will not care about order of invocation of subscriber. Subscriber can be executed in any manner.
- Implementation of subscriber side should be short duration. Let us consider the scenario in which you what to publish large volume of event. Publisher will be blocked, when subscriber is queued on previous subscription of the event. These make publishers to put in wait state. It may lead Publisher event not to reach other subscriber.
- Large number of subscribers to the event makes the accumulated processing time of each subscriber could exceed the publisher's timeout
- Managing the list of subscribers and their preferences is a completely service-side implementation. It will not affect the client; publisher can even use .Net delegates to manage the list of subscribers.
- Event should always one-Way operation and it should not return any value
Definition
public interface IMyEvents { [OperationContract(IsOneWay = true)] void Event1(); }
Step 1 :
Create ClassLibrary project in the Visual Studio 2008 and name it as WCFEventService as shown below.
Step 2:
Add reference System.ServiceModel to the project
Create the Event operation at the service and set IsOnwWay property to true. This operation should not return any value. Since service has to communicate to the client, we need to use CallbackContract for duplex communication. Here we are using one operation to subscribe the event and another for firing the event.
Create the Event operation at the service and set IsOnwWay property to true. This operation should not return any value. Since service has to communicate to the client, we need to use CallbackContract for duplex communication. Here we are using one operation to subscribe the event and another for firing the event.
public interface IMyEvents { [OperationContract(IsOneWay = true)] void Event1(); } [ServiceContract(CallbackContract = typeof(IMyEvents))] public interface IMyContract { [OperationContract] void DoSomethingAndFireEvent(); [OperationContract] void SubscribeEvent(); }
Step 3:
Implementation of the Service Contract is shown below.
In the Subscription operation, I am using Operationcontext to get the reference to the client instance and Subscription method is added as event handler to the service event. DoSomethingAndFireEvent operation will fire the event as shown.
MyPublisher.cs
In the Subscription operation, I am using Operationcontext to get the reference to the client instance and Subscription method is added as event handler to the service event. DoSomethingAndFireEvent operation will fire the event as shown.
MyPublisher.cs
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] public class MyPublisher : IMyContract { static Action m_Event1 = delegate { }; public void SubscribeEvent() { IMyEvents subscriber = OperationContext.Current.GetCallbackChannel(); m_Event1 += subscriber.Event1; } public static void FireEvent() { m_Event1(); } public void DoSomethingAndFireEvent() { MyPublisher.FireEvent(); } }
Step 4:
Create the Console application using Visual Studio 2008 and name it as
WcfEventServiceHost. This application will be used to self-host the
service.
Step 5:
Add System.ServiceModel and WcfEventService as reference to the project.
static void Main(string[] args) { Uri httpUrl = new Uri("http://localhost:8090/MyPublisher/"); ServiceHost host = new ServiceHost(typeof(WcfEventService.MyPublisher), httpUrl); host.Open(); Console.WriteLine("Service is Hosted at {0}", DateTime.Now.ToString()); Console.WriteLine("Host is running...Press key to stop the service."); Console.ReadLine(); host.Close(); }
Step 6:
Use Duplex binding to support Callback operation.
Web.Config
Web.Config
<system.serviceModel> <services > <service behaviorConfiguration="ServiceBehavior" name="WcfEventService.MyPublisher"> <endpoint address="http://localhost:8090/MyPublisher" binding="wsDualHttpBinding" contract="WcfEventService.IMyContract"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true "/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
Step7:
Run the host application as shown below.
Step 8:
Create the console application using visual studio and name it as WcfEventServiceClient as shown below. This application will act a client which is used to subscribe the event from service.
Step 9:
Create the proxy class as shown below. Use DuplexClientBase to
create the proxy, because it will support bidirectional communication.
Create the contractor which will accept InstanceContext as parameter.
EventServiceClient.cs
EventServiceClient.cs
class EventServiceClient:DuplexClientBase<IMyContract>,IMyContract { public EventServiceClient(InstanceContext eventCntx) : base(eventCntx) { } public void DoSomethingAndFireEvent() { base.Channel.DoSomethingAndFireEvent(); } public void SubscribeEvent() { base.Channel.SubscribeEvent(); } }
Step 10:
Implementation of IMyEvents at client side is shown below. This method will be called when service publish the event.
class MySubscriber : IMyEvents { public void Event1() { Console.WriteLine("Event is subscribed from the service at {0}",DateTime.Now.ToString() ); } }
Step 11:
Main method of the client side you can find the creating Subscription instance and it passed to service using InstanceContext
static void Main(string[] args) { IMyEvents evnt = new MySubscriber(); InstanceContext evntCntx = new InstanceContext(evnt); EventServiceClient proxy = new EventServiceClient(evntCntx); Console.WriteLine("Client subscribe the event from the service at {0}",DateTime.Now.ToString()); proxy.SubscribeEvent(); Console.WriteLine("Client call operation which will fire the event"); proxy.DoSomethingAndFireEvent(); Console.ReadLine(); }
Step 12:
Run the client application and you see the when event is fired from the service. Subscriber got notification.
Transfer mode
Buffer transfer
When the client and the service exchange messages, these messages are buffered on the receiving end and delivered only once the entire message has been received. This is true whether it is the client sending a message to the service or the service returning a message to the client. As a result, when the client calls the service, the service is invoked only after the client's message has been received in its entirety; likewise, the client is unblocked only once the returned message with the results of the invocation has been received in its entirety.Stream transfer
When client and Service exchange message using Streaming transfer mode, receiver can start processing the message before it is completely delivered. Streamed transfers can improve the scalability of a service by eliminating the requirement for large memory buffers. If you want to transfer large message, streaming is the best method.StreamRequest
In this mode of configuration, message send from client to service will be streamedStreamRespone
In this mode of configuration, message send from service to client will be streamed.Configuration
<system.serviceModel> <services > <service behaviorConfiguration="ServiceBehavior" name="MyService"> <endpoint address="" binding="netTcpBinding" bindingConfiguration="MyService.netTcpBinding" contract="IMyService"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true "/> </behavior> </serviceBehaviors> </behaviors> <bindings > <netTcpBinding> <binding name="MyService.netTcpBinding" transferMode="Buffered" closeTimeout ="0:01:00" openTimeout="0:01:00"></binding> </netTcpBinding> </bindings> </system.serviceModel>
Differences between Buffered and Streamed Transfers
Buffered | Streamed |
---|---|
Target can process the message once it is completely received. | Target can start processing the data when it is partially received |
Performance will be good when message size is small | Performance will be good when message size is larger(more than 64K) |
Native channel shape is IDuplexSessionChannel | Native channels are IRequestChannel and IReplyChannel |
Streaming
Client and Service exchange message using Streaming transfer
mode, receiver can start processing the message before it is completely
delivered. Streamed transfers can improve the scalability of a service
by eliminating the requirement for large memory buffers. If you want to
transfer large message, streaming is the best method.
Supported Bindings
- BasicHttpBinding
- NetTcpBinding
- NetNamedPipeBinding
Restrictions
There are some restriction, when streaming is enabled in WCF- Digital signatures for the message body cannot be performed
- Encryption depends on digital signatures to verify that the data has been reconstructed correctly.
- Reliable sessions must buffer sent messages on the client for redelivery if a message gets lost in transfer and must hold messages on the service before handing them to the service implementation to preserve message order in case messages are received out-of-sequence.
- Streaming is not available with the Message Queuing (MSMQ) transport
- Streaming is also not available when using the Peer Channel transport
I/O Streams
WCF uses .Net stream class for Streaming the message. Stream in base class for streaming, all subclasses like FileStream,MemoryStream, NetworkStream are derived from it. Stream the data, you need to do is, to return or receive a Stream as an operation parameter.[ServiceContract] public interface IMyService { [OperationContract] void SaveStreamData(Stream emp); [OperationContract] Stream GetStreamData(); }
- Stream and it's subclass can be used for streaming, but it should be serializable
- Stream and MemoryStream are serializable and it will support streaming
- FileStream is non serializable, and it will not support streaming
Streaming and Binding
Only the TCP, IPC, and basic HTTP bindings support streaming. With all of these bindings streaming is disabled by default. TransferMode property should be set according to the desired streaming mode in the bindings.public enum TransferMode { Buffered, //Default Streamed, StreamedRequest, StreamedResponse } public class BasicHttpBinding : Binding,... { public TransferMode TransferMode {get;set;} //More members }
- StreamedRequest - Send and accept requests in streaming mode, and accept and return responses in buffered mode
- StreamResponse - Send and accept requests in buffered mode, and accept and return responses in streamed mode
- Streamed - Send and receive requests and responses in streamed mode in both directions
- Buffered -Send and receive requests and responses in Buffered mode in both directions
Streaming and Transport
The main aim of the Streaming transfer mode is to transfer large size data, but default message size is 64K. So you can increase the message size using maxReceivedMessageSize attribute in the binding element as shown below.<system.serviceModel> <bindings > <netTcpBinding> <binding name="MyService.netTcpBinding" transferMode="Buffered" maxReceivedMessageSize="1024000"> </binding> </netTcpBinding> </bindings> </system.serviceModel>
Transaction
Recovery Challenge
Let us discuss more on challenge we will phased and how to recover from it.- Consider a system maintained in consistent state, when application fail to perform particular operation, you should recover from it and place the system in the consistent state.
- While doing singe operation, there will be multiple atomic sub operation will happen. These operations might success or fail. We are not considering about sub operation which are failed. We mainly consider about the success operation. Because we have to recover all these state to its previous consistence state.
- Productivity penalty has to be payee for all effort required for handcrafting the recovery logic
- Performance will be decreased because you need to execute huge amount of code.
Solution
Best way to maintain system consistence and handling error-recovery challenge is to use transactions. Below figure gives idea about transaction.- Committed transaction: Transaction that execute successfully and transfer the system from consistence state A to B.
- Aborted transaction: Transaction encounters an error and rollback to Consistence State A from intermediate state.
- In-doubt transaction: Transactions fail to either in commit or abort.
Transaction Resources
Transactional programming requires working with a resource that is capable of participating in a transaction, and being able to commit or roll back the changes made during the transaction. Such resources have been around in one form or another for decades. Traditionally, you had to inform a resource that you would like to perform transactional work against it. This act is called enlisting. Some resources support auto-enlisting.Transaction Properties
Transaction can be said as pure and successful only if meets four characteristics.- Atomic - When transaction completes, all the individual changes made to the resource while process must be made as to they were all one atomic, indivisible operation.
- Consistent - transaction must leave the system in consistent state.
- Isolated - Resources participating in the transaction should be locked and it should not be access by other third party.
- Durable - Durable transactions must survive failures.
Two-phase committed protocol
Consider the scenario where I am having single client which use
single service for communication and interacting with single database.
In which service starts and manage the transaction, now it will be easy
for the service to manage the transaction.
Consider for example client calling multiple service or service itself calling another service, this type of system are called as Distributed Service-oriented application. Now the questions arise that which service will begin the transaction? Which service will take responsibility of committing the transaction? How would one service know what the rest of the service feels about the transaction? Service could also be deployed in different machine and site. Any network failure or machine crash also increases the complexity for managing the transaction.
Consider for example client calling multiple service or service itself calling another service, this type of system are called as Distributed Service-oriented application. Now the questions arise that which service will begin the transaction? Which service will take responsibility of committing the transaction? How would one service know what the rest of the service feels about the transaction? Service could also be deployed in different machine and site. Any network failure or machine crash also increases the complexity for managing the transaction.
Transaction Manager is the third party for the service that will manage the transaction using two phase committed protocol.
Let us see how Transaction manager will manage the transaction using two-phase committed protocols.
Transaction Propagation
In WCF, transaction can be propagated across service boundary. This enables
service to participate in a client transaction and it includes multiple services
in same transaction, Client itself will act as service or client.
We can specify whether or not client transaction is propagated to service by changing Binding and operational contract configuration
We can specify whether or not client transaction is propagated to service by changing Binding and operational contract configuration
<bindings> <netTcpBinding> <binding transactionFlow="true"></binding> </netTcpBinding> </bindings>
Even after enabling transaction flow does not mean that the service wants to use
the client’s transaction in every operation. We need to specify the
“TransactionFlowAttribute” in operational contract to enable transaction flow.
[ServiceContract]
public interface IService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
int Add(int a, int b);
[OperationContract]
int Subtract(int a, int b);
}
Note: TransactionFlow can be enabled only at the operation level not
at the service level.
TransactionFlowOption | Binding configuration | |
---|---|---|
NotAllowed | transactionFlow="true" or transactionFlow="false" |
Client cannot propagate its transaction to service even client has transaction |
Allowed | transactionFlow="true" | Service will allow to flow client transaction. It is not necessary that service to use client transaction. |
Allowed | transactionFlow="false" | If service disallows at binding level, client also should disable at binding level else error will be occurred. |
Mandatory | transactionFlow="true" | Both Service and client must use transaction aware binding |
Mandatory | transactionFlow="false" | InvalidOperationException will be throw when serice binding disables at binding
level. FaultException will be thrown when client disable at its binding level. |
Transaction Protocols
As a developer we no need to concern about transaction protocols
and transaction manager used by WCF. WCF itself will take care of what
kind of transaction protocols should be used for different situation.
Basically there are three different kinds of transaction protocols used
by WCF.
Did you know that that you can make money by locking premium areas of your blog or site?
ReplyDeleteSimply open an account on Mgcash and add their content locking tool.
Are you trying to make cash from your websites by running popup advertisments?
ReplyDeleteIn case you do, have you considered using Pop Ads?