Sunday, July 25, 2010

WCF 5

Problem of Fault on channel:
Once the fault occurs on proxy object, It becomes useless. You can't even call proxy.close() on it, Because of object got faulted. The reason is because of implementation of ICommunicationObject interface. This interface is contract for basic state machine for all communication oriented objects in system. And once the channel is faulted, it goes into fault state. So In order to overcome such problem we need to test state  of proxy object and accordingly apply method on it.
If(serviceClient.State == CommunicationState.faulted)
{
..
}
Or we can subscribe to fault event of communication object.
Once the object is faulted we must create a new instance of it.

Auto-Open Vs Open:
WCF support ICommunicationObject which has different states:
Created -> Opening -> Opened -> Closing -> Closed
WCF supports auto-open. This feature allows you to call an I/O method while the object is in the Created (or Opening) state. And objects I/O method ensures that the object transitions to the opened state before calling the inner channel. If you are using a session and you need to send multiple messages concurrently and you care that the first couple messages are actually sent concurrently, you should not use auto-open.
Whenever some method is invoked there is serviceChannel class which does some work and call this
channel.send(message)
Concurrent messages with auto open creates problem,Because it works like this:
If(this.State == created)
{
Open channel
}
So every call has to wait for first call to get finish.Then also there will be race condition for messages to be sent. If the order of message is important then it will create problem. Point to note here is that if we are using multithreading then also the order is not defined.I agree with the same but what if we are using some async calls which must be deterministic.
So in order to avoid it we must open the channel manually by using .open method.

Session limit on server side:
There is always MaxConcurrentSessions on server side. Default value for this is 10. If we are opening channels and crossing the limit of MaxConcurrentSessions, then we can get some timeout errors.
Ex:
for (int i = 0; i < 100; i++)
{
    proxy = create channel Using factory
    proxy.Mymethod();
    ((IChannel)proxy).Close();
}
Here if we don't use .close() method and haven't set anything on MaxConcurrentSessions. Then at i=10 it will say time out. and the loop will only be able to create 10 channels.
In order to solve this problem add these statements inside system.servicemodel block inside behaviours tag
behavior name="myBehavior">
serviceThrottling maxConcurrentCalls="Integer" maxConcurrentInstances="Integer" maxConcurrentSessions="Integer"  />
/behavior>
And in service tag write this:
service name="mySvc" behaviorConfiguration="myBehavior">

.Close Vs .Abort:
.Close will close the connection gracefully. If there is any call left it will wait for its response and then only it will close the connection.But Abort() is a forced close.
We can understand the difference between these 2 by following code:
try
{
    myeClient.CallSomething();
    myClient.Close();
}
catch(FaultException)
{
    myClient.Abort();
}


Generics class mapping in proxy: 
Generics is very common in today world of coding. But WCF does not support use of generics methods for service operation. So open generics type cannot  be used for in it. People may think that it is limitation of WCF, But it is not so, Actually it is limitation of WSDL(Used to expose service metadata to consumers).
Then is there no way that we can expose generic object client side?
The answer is Yes!!!!
Service side Code: Service:
[DataContract]
public class MyObj
{
   ..
}

[ServiceContract]
Public interface IBoundedGenerics
{
    [OperationContract]
    MyObj GetObj(int id);
}


On client side the proxy get created like this:
[DataContract]
public class MyObjOfint
{
   ...
}
Resulting Name = Generic Class Name + “of” + Type Parameter + Hash
Hash is there to reduce name collision risk. But causes ugly name. So in order to avoid it we can use
[DataContract(Name = "MyObjOf{0}"]
It will create name of our choice.

No comments:

Post a Comment