WCF - Managing Instances
The instance management is a technique that is used by WCF or any other technology of distributed computing that determines how and by whom the client requests will be met. The choice of the management mode of instances directly affects the scalability, performance and transactions of a service / component, besides having some changes to the level of implementation of the contract, we need to pay attention to ensure that it operates under the management model chosen . The purpose of the article is basically to show each of the three techniques available for WCF but also addressing their respective benefits and some techniques that surround this process and that somehow are connected and influence the choice and / or implementation. The article will also address the care we should have the choice and implementation of each of the techniques provided. Firstly, it is important to say that the choice of the management mode instance does not directly compromise the design of the service contract. The choice of mode applies to the implementation class service that, in turn, makes the use (implementation) of that interface . The choice of management mode should be performed from a behavior * pre-defined service within the NET Framework as an attribute, called ServiceBehaviorAttribute . * In a short response, a behavior customizes the assignment. To be more specific, a behavior consists of a piece of code that implements a particular interface (depending on where it will be applied) that enables the WCF runtime add it in the implementation process and, consequently, run custom code for you . They can be "plugged in" via attributes or configuration file. Creating custom behaviors is beyond the scope of this article. This attribute has a property called InstanceContextMode that receives one of the options provided by the enumerator InstanceContextMode .Among the options provided by him are: PerSession , PerCall and Single . Are three options that will cover extensively from now. PerSession mode PerSession that when omitted is the mode used by WCF, creates an instance of the class that corresponds to service for each customer. Activation is performed when the first method is invoked by him and the instance is active, responding to all subsequent requests until the client closes the connection, which typically happens when the method Close the proxy ( ClientBase ) is invoked (remembering that method Dispose method also invokes the Close ). Just by staying active object between the opening and the closing, it is typically referred to as Session client side and as Private Session on the service side. Each active instance of the service side corresponding to an active instance of the proxy that is on the side of client, ie, if a single client to create five instances of the same proxy , even if it points to the same service, a class will be created for each side of the service to meet their calls, and may not a Session be shared with another, even though coming from the same client. Even the client to create multiple threads using the same instance of theproxy to make several calls, the service will be able to meet only a single thread and, so other threads will have to wait for the release to be processed. Can we change this behavior using techniques provided by WCF competitions, but they are beyond the scope of this article. The following code snippet illustrates how we can apply the attribute ServiceBehaviorAttribute in the implementation class of the service, defining it as PerSessionbut if omit the attribute, the behavior is the same because, as stated above, is the default configuration of WCF:
using System;
using System.ServiceModel;
[ServiceBehavior (InstanceContextMode = InstanceContextMode.PerSession)]
public class ServidoDeClientes: IClientes
{
private Dictionary <int, string> _clientes;
// Builder
public int Add (string name)
{
int key = this._clientes.Count + 1;
this._clientes.Add (key, name);
return key;
}
}
|
As we can see, the class is defined as PerSession . In this case, as the instance will be active as long as the proxy, we can store data between requests in the class itself, or in its internal members, as is the case of the object_clientes . When the proxy is closed, it notifies the service that the session was terminated and, if it implements the IDisposable interface , the method Dispose is invoked *. * Because the Dispose method is invoked asynchronously, ie on a worker thread, the context of the transaction is not propagated into the Dispose method and, therefore, the same can not depend on such contextual information. But for session support to work correctly, we need to analyze under which binding class will be exposed. To be able to correlate the messages from a particular client to a particular instance, WCF must be able to identify the customer and when we use bindingsthat provide this natively through the protocol (such as TCP or IPC), not no problem, because they maintain a continuous connection, also known as session at the transport level and, thus, one can easily identify who is the client. By the nature of the HTTP protocol that's already a bit more complex, because each call a new connection is made, and with it, the BasicHttpBiding not support Sessions ; already WSHttpBinding is able to emulate the session at the transport level, including a SessionID in the headers of the message that uniquely identifies the client, much like what happens with ASP.NET. 's SessionID is represented by a GUID and both client the service are able to retrieve it so it can be used at runtime for any given task, and for the purpose of debugging / logging .WCF (as well as worked in COM +) provides a contextual information containing (more on context below) class, which are related to the current call that, in addition to bringing information about transactions and security, also informs the SessionID . This information is accessed differently on the client against the server. The following code snippet illustrates how to proceed to recover such information on both sides:
// Service
Debug.WriteLine (OperationContext.Current.SessionId);
// Customer
Debug.WriteLine (proxy.InnerChannel.SessionId);
|
There is another type that we need to pay attention. This is the enumerator SessionMode that can be assigned to the property SessionMode attribute ServiceContractAttribute that is applied to the interface of the service agreement. This information will be available in the contract of service, so that the runtime WCF knows he must use a Session . This enumerator provides three options, which are described below:
- Allowed: Specifies that the contract provided that the support session binding also support. By default, this option is set in the contracts when it is not explicit.
- NotAllowed: Determines that the contract does not accept bindings that initiate sessions.
- Required: Specifies that the contract requires a binding that supports sessions, and if it does not, an exception of type InvalidOperationException will be thrown during the service burden.
As we noted, the aim of this enumerator is to ensure that the contract will be exhibited from a binding that supports (or not) the Sessions . The default setting determines the property SessionMode to Allowed , and with it, if you are using a binding that does not support sessions, such as the BasicHttpBinding , no exception is thrown, but it will not behave as expected, ie, can not maintain state between calls. Already when we choose the optionNotAllowed and provide the contract from a binding that natively provides support sessions, such as TCP, then an exception is thrown during the service burden. Finally, the option Required requires that the contract be exposed under a binding that supports sessions and, if not support, as well as the previous option, an exception is thrown during the service burden. The following code snippet illustrates how to set this property in the contract of service:
using System;
using System.ServiceModel;
[ServiceContract (SessionMode = SessionMode.Required)]
public interface ICliente
{
[OperationContract]
int Add (string name);
}
|
Order Execution
When use contracts that support session, sometimes we need to determine the order of execution, so garatindo a method to be able to initialize the session; have another method may be executed only if the session is already properly created, and there is still the possibility of a method to logout. To have a control over this, we used two properties called IsInitiating and IsTerminating attribute OperationContractAttribute . These properties will demarcate the session timeout in the service and consistency is accomplished while charging the same to ensure that it is with the option SessionMode defined as Required . By default, the property IsInitiating is set to True andIsTerminating as False , allowing any method log. The interesting thing is that this technique will prevent you make consistencies within the method to know if the session is already active or not, because the WCF itself ensures that, once you are trying to access a method that allows initializing the session and the same not yet been built. To illustrate, let's imagine that we have a contract that defines some typical operations for electronic commerce. Operations are to identify the customer from a log , ability to add products to recover the full value of the products, and finally a method to finalize the purchase. The code below illustrates how we should do to configure these methods within the interface to ensure the order of calls:
using System;
using System.ServiceModel;
[ServiceContract (SessionMode = SessionMode.Required)]
public interface IComercioEletronico
{
[OperationContract (IsInitiating = true)]
EfetuarLogin bool (string name);
[OperationContract (IsInitiating = false)]
void AdicionarProduto (ProductID int, int amount);
[OperationContract (IsInitiating = false)]
RecuperarValorTotal decimal ();
[OperationContract (IsInitiating = false, IsTerminating = true)]
FinalizarCompra void ();
}
|
Despite the property IsInitiating be defined by default as True , it was not necessary to specify it in the methodEfetuarLogin ; since the two intermediate methods, AdicionarProduto and RecuperarValorTotal not allow boot or log off (remember that property IsTerminating by default is always False ), and finally the method FinalizarCompraends the session because it defines IsInitiating as False and IsTerminating as True . With this contract we can properly implemented, the client side, create a reference to the service, instantiate the proxy and consume methods. If you try to invoke a method that does not create the session before invoking the method that has this purpose, you will receive an exception of type InvalidOperationException stating that the method that is trying to summon can only be triggered after the session created. The code snippet below shows how to invoke methods in their correct sequence (note that this does not change anything in the client code):
using (proxy = new ComercioEletronicoClient ComercioEletronicoClient ())
{
proxy.EfetuarLogin ("Israel ECSA");
proxy.AdicionarProduto (12, 4);
proxy.AdicionarProduto (12, 3);
proxy.AdicionarProduto (3, 3);
Console.WriteLine (proxy.RecuperarValorTotal ());
proxy.FinalizarCompra ();
}
|
If you try to call any method before the method EfetuarLogin , an exception is thrown, saying this is not possible, forcing you to invoke the methods in the correct order. Moreover, it is important to say that the methodFinalizarCompra are the property IsTerminating set to True , to invoke it, WCF will remove the current instance, invalidating the proxy . If you need to make new calls, you will have to create a new proxy . Though this technique is being discussed in the section that discusses the way PerSession , it can also be adopted in a service that is exposed through mode Single , which will be addressed more down. Disabling Instance model PerSession allows multiple messages are correlated to the same instance, keeping the active object on the service side, meeting the requirements of a particular proxy . In fact the instances are contained within a context and when a session is created, the host creates a new context instance to accommodate within it. The image below illustrates graphically how this process happens:
![]() |
Figure 1 - The relationship between the context and the service instance. |
As we can see, the instance is always contained within a context which, in turn, has the same lifetime of the object. However, in an environment where you want to have greater control regarding the management of contexts and also instances, perhaps for reasons of performance or even consistency, WCF decouples the management of proceedings in relation to the context within which it resides and with Therefore, you can define when to discard the instance (before or after the method call), but still having access to the current context, something that was not possible before. This control is useful at times when the method uses valuable resources where you can not wait until the session ends to which they are released. Such control can be done imperatively or declaratively. This means that we can, within a method, invoke a WCF method that releases the instance or in a declarative way, where we can decorate the methods that are part of the service to dispose of the body before or after the execution. For the first form, we resort to the method ReleaseServiceInstance class InstaceContext , as shown in the code example below:
[ServiceBehavior (InstanceContextMode = InstanceContextMode.PerSession)]
public class ServicoDeComercioEletronico: IComercioEletronico
{
Other methods //
public void FinalizarCompra ()
{
// Finalize the purchase
OperationContext.Current.InstanceContext.ReleaseServiceInstance ();
}
}
|
In the declarative model, we use the attribute OperationBehaviorAttribute . This attribute provides a property called ReleaseInstance that accepts the two items contained within the enumerator ReleaseInstanceMode that tell the WCF instance that should be recycled at a specific point in the process. The options of this enumerator are addressed below:
- None: This is the default option that recycles the object according to the value set on the propertyInstanceContextMode ( PerSession , PerCall and Single ).
- BeforeCall: Recycles the object prior to calling the operation.
- AfterCall: Recycles the object after the call operation. Similar to the method ReleaseServiceInstance .
- BeforeAndAfterCall: recycles the object before and after the call operation. This option is very similar to the services configured as PerCall .
Here is the same example we saw above, only now in declarative mode. It is important to note that in both cases these settings are done in the class that implements the contract:
[ServiceBehavior (InstanceContextMode = InstanceContextMode.PerSession)]
public class ServicoDeComercioEletronico: IComercioEletronico
{
Other methods //
[OperationBehavior (ReleaseInstanceMode = ReleaseInstanceMode.BeforeCall)]
public void FinalizarCompra ()
{
// Finalize the purchase
}
}
|
Determine which of the three session options to choose ( Allowed , NotAllowed or Required ), depend greatly on what your contract purports to accomplish. Services configured as PerSession is costly and does not scale well with respect to the services configured as PerCall . This is because while the proxy remain active on the client side, the corresponding class serving their requests will also be active on the service side. If calls are made quite frequently, keep the proxy can be a good solution; longer when calls are sporadic or if you need scalability and consistency, then the best way is to resort to PerCall , which will be addressed below. PerCall While the feature set of services as PerSession is to keep the active object on the service side while there is a proxy on the client side, the PerCall is the opposite. Often customers holding a reference to the object for an extended period of time and actually make use of it in a few moments. This will cause unnecessary objects consume memory on the service side, without even being used. services configured as PerCall create a new service instance for each call to any operation. When the method returns, the object is removed from memory, existing only during the execution of the method requested by the client. For classes that implement the IDisposable interface , moments before the class to be removed, the method Dispose will be fired but, unlike the model PerSession , the method Dispose will run on the same thread of the operation and, consequently, you will still have access to the context. this management mode, you need to pay attention to some details that change significantly from the way PerSession .The first is with respect to competition; as each call creates a new dedicated instance, then you will not need to deal with environmental multi-threading , because it will never happen. Another important detail is related to state management. As the instance that the request will be destroyed when the method returns, you can not save you some information between requests and, if wanted, you need to create and manage a repository, in addition to also need to uniquely identify each client call and, in most cases, it influences a change in the contract of service. Following the same example we used in order PerSession , the class will change slightly ServidoDeClientesfor right now, use the model PerCall . All we need is to set the property InstanceContextMode attributeServiceBehaviorAttribute to PerCall and everything already works with this new behavior:
using System;
using System.ServiceModel;
[ServiceBehavior (InstanceContextMode = InstanceContextMode.PerCall)]
public class ServidoDeClientes: IClientes
{
private Dictionary <int, string> _clientes;
// Builder
public int Add (string name)
{
int key = this._clientes.Count + 1;
this._clientes.Add (key, name);
return key;
}
}
|
As is to be expected, every call to the Add , it will always create a new instance of the class and, consequently, all content will be recreated, not retaining information between requests. As stated above, if you need to keep some information between requests, you need to boot this information from a repository, such as a database, file system, or even static variables. single model already in Single ( Singleton ) behavior is very different for the two options that come up. The idea of this model is to have a single instance serving all the requests that arrive for this service, regardless of which endpoint will request. This object will live while the host that hosts live. As a key advantage, so the male does not create for every client or every call a new instance of the object but in contrast, there are some disadvantages that are a little bit as difficult to deal with. The first case is related to competition: how do you have multiple clients accessing the same instance, objects contained within it may also be accessed at the same time and, if not worrying about how to access them, you may have problems in the final result process or even deadlocks . Another known problem but you can not do much about, just the need to have a single object providing all requests, is that it (instance) is active even when there is no task to run it and depending on the amount of resources the same stores, we may have future problems. To use the mode Single as well as others, we must resort to attribute ServiceBehaviorAttribute , setting the property InstanceContextMode as Single . But it is important to note that for internal members, will be necessary that you understand the potential problems that can happen because of multiple clients making simultaneous requests, and this requires a change in programming and / or access the internal resources of the class. Competition is not treated here, it needs a separate Article to address this. The following code illustrates the same example ( ServidoDeClientes ) but using mode Single :
using System;
using System.ServiceModel;
[ServiceBehavior (InstanceContextMode = InstanceContextMode.Single)]
public class ServidoDeClientes: IClientes
{
private Dictionary <int, string> _clientes;
// Builder
public int Add (string name)
{
int key = this._clientes.Count + 1;
this._clientes.Add (key, name);
return key;
}
}
|
The class ServiceHost , which is responsible for managing the instance of the service class, has some overloads of the constructor that, in one version, accepts an instance of type ( Type ) of service; in this case the ServiceHost is responsible for instantiating the class by invoking the default constructor of the same. Already in another version of the constructor ServiceHost , it receives a parameter of type object , allowing you to instantiate the implementation class of the service. This is useful when the service implementation needs some additional information (via constructor or properties) to work. Below is an example that shows this technique:
ServicoDeClientes srv = new ServicoDeClientes ("connection_string");
srv.NumeroDeTentativas = 5;
using (ServiceHost host = new ServiceHost (srv,
new Uri [] {new Uri ("net.tcp: // localhost: 9292")}))
{
// ...
}
|
Conclusion: This article showed the three forms we have to manage the instance of a class that serves requests.It is important to analyze the advantages and disadvantages of each to decide which one is ideal for the service that is being developed. Moreover, the choice of the management mode interferes directly in write mode code, precisely to enable the service to behave well in an environment multi-threading , since the modes PerSession andSingle allow that to happen.
Comments
Post a Comment