WCF InstanceContextMode.Multiple issues - wcf

So I'm hosting WCF service in a WinForms application. I have the following
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerCall)]
public class Test : ITest
{
public string TestIt(string input)
{
Thread.Sleep(5000);
return "test";
}
}
I'm using Named Pipes and have two instances of another application that act as clients to the above WCF service (running in a WinForms application). I thought based on the ConcurrencyMode setting of Multiple that when Client1 calls the Test Service, Client2 doesn't have to wait till the first call is complete. However, when Client1 calls TestIt, Client2 blocks until the call from Client1 is complete!?!?! Shouldn't it make a new instance each time based on the above settings?
Also, is the best way to keep a WinForms application that is hosting a WCF service responsive is by running the WCF service on a separate thread?
NOTE: Setting [CallbackBehavior(UseSynchronizationContext = false)] on the Test class does not alleviate the problem. The service still only responds to one request at a time.

Sounds like you want to set this
http://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.usesynchronizationcontext.aspx
to false. By default, if there is a synchronization context when service.Open() happens, WCF will pick it up and use it. But if you don't want that feature, this flag is how to turn it off.

After digging into this a bit more the only way I was able to get this to work properly was to start the ServiceHost on a separate thread in the WinForms application. If you don't do that setting the ConcurrencyMode and InstanceContextMode attributes does nothing.

I had the same problem.
My class that implemented Callback also contained methods for wcf client, so when I was calling some method from remote service and service was calling Callback method, I was creating a deadlock.
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class AppContext : ICustomerOrderCallback
{
//WCF Proxy client
private CustomerOrderClient _client = null;
public AppContext()
{
InstanceContext context = new InstanceContext(this);
_client = new CustomerOrderClient(context);
_client.Subscribe(); //Remote method for subscribing callback
}
public void SendMessage(string message)
{
//Calling Remote method
_client.SendMessage(message);
}
//....code
//callback method
public void OnMessageReceived(string message)
{
//.....code
}
}
So I created a separate class for callback, added attribute CallBehavior to it and everything worked OK.
public class AppContext
{
private CustomerOrderClient _client = null;
private MyCallbackClass _myCallback = null;
public AppContext()
{
_myCallback = new MyCallbackClass();
InstanceContext context = new InstanceContext(_myCallback);
_client = new CustomerOrderClient(context);
_client.Subscribe();
}
public void SendMessage(string message)
{
_client.SendMessage(message);
}
}
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyCallbackClass : ICustomerOrderCallback
{
public void OnMessageReceived(string message)
{
//.....code
}
}

Related

Closing WCF Connections from service

I have recently started a new job where WCF services are being used. I have used them in the past and am comfortable with them but from what I can recall if the client does not close the connection it has the ability to bring your service down entirely. I am aware of the proper procedure for closing the connections but if the responsibility is on the client, they may not follow the same practices and potentially have the ability to bring the service down. Is there any other way of handling the closing of the connections so that it is not reliant on the client doing the right thing? It seems odd that anyone who has access to your service has the ability to bring it down with such ease...
Thank you very much for any insights!
One option is to use session time out in the server. This actually faults the client channel.
There are only really three ways in which a session can terminated:
1) The client closes the proxy
2) The service's receiveTimeout is exceeded before the client sends another request
3) The service throws a non-fault exception which will fault the channel and so terminate the session
If you don't want the client involved then you only have 2 and 3 neither of which end well for the client - they will get an exception in both situation on the next attempt to talk to the service.
You could use Duplex messaging and get the service to notify the client that its requires session termination - the client then gets an opportunity to close down the proxy gracefully but this is a cooperative strategy
Or you need to use duplex (but still the client will have to call the service).
Here is some important points of the service implementation:
a: Use a static dictionary to keep the Client’s IP and callback channel. Before writing on the share object, lock the object.
b: Gets the IP address of the client using the GetAddressAsString method. You can get the IP of the client from the incoming message. The following statement shows how can we get the IP adddress of the Client in WCF:
RemoteEndpointMessageProperty clientEndpoint = OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
String ipAddress = clientEndpoint.Address;
If you are using the namepipe binding, you will not get the RemoteEndpointMessageProperty.
c: When the client creates the proxy of the service, it will call StartingService method immediately. Inside the StartingService method, I am keeping the callback channel of the client and current instance into the dictionary.
d: When the user of WCF service wants to disconnect a client, he/she will call the Disconnect method with the IP Address of the client.
e: The Disconnect method uses the IP Address to get the callback channel of the client and associate service instance of the client from the dictionary. Eventually, it notifies the client by using callback channel and close the incoming channel.
Here is the implementation through code:
[ServiceContract(CallbackContract=typeof(INotifyClientCallback),SessionMode=SessionMode.Required)]
public interface IService1
{
[OperationContract]
bool StartingService();
}
public interface INotifyClientCallback
{
[OperationContract(IsOneWay = true)]
void Disconnecting();
}
INotifyClientCallback interface for Callback.
Step 2: Implementation of the Contact:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service1 : IService1
{
private static readonly Dictionary subscribers = new Dictionary();
public static event EventHandler onClientAdded;
///
/// Returns the IP Address of the Client
///
///
public string GetAddressAsString()
{
if (!OperationContext.Current.IncomingMessageProperties.ContainsKey(RemoteEndpointMessageProperty.Name))
{
return "127.0.0.1";
}
RemoteEndpointMessageProperty clientEndpoint =
OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
return clientEndpoint.Address;
}
public bool StartingService()
{
//Get the callback reference
INotifyClientCallback callback = OperationContext.Current.GetCallbackChannel();
string IPAddress = GetAddressAsString();
lock (subscribers)
{
if (!subscribers.ContainsKey(IPAddress))
{
subscribers[IPAddress] = new CommunicationStore()
{ NotifyCallback = callback,
IService = OperationContext.Current.InstanceContext
};
if (onClientAdded != null)
{
onClientAdded(IPAddress, null);
}
}
}
return true;
}
public static void Disconnect(string ipAddress)
{
if (subscribers.ContainsKey(ipAddress))
{
CommunicationStore com = subscribers[ipAddress];
if (((ICommunicationObject)com.NotifyCallback).State == CommunicationState.Opened)
{
try
{
//fires the callback method
com.NotifyCallback.Disconnecting();
com.IService.IncomingChannels.FirstOrDefault().Close();
}
catch (Exception)
{
throw;
}
}
}
}
}
public class CommunicationStore
{
public InstanceContext IService { get; set; }
public INotifyClientCallback NotifyCallback { get; set; }
}

Running WCF service method during start of Windows Service

I have got WCF service running as Windows service and I need to run a method of the WCF Service when Windows Service is starting. Is it possible in any way?
[ServiceContract]
public interface IWebMonitorServiceLibrary
{
[OperationContract]
void TestMethod();
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class WebMonitorServiceLibrary : IWebMonitorServiceLibrary
{
#region properties
#endregion
#region events
#endregion
public WebMonitorServiceLibrary()
{
Initialization();
}
private void Initialization()
{
/////////
}
public void TestMethod()
{
//////////
}
}
You don't explain why you want this initialization code to run, but given you almost never want to use a single-instance WCF service, the proper way would be to use dependency injection (see How do I pass values to the constructor on my wcf service?).
Create an object in which you store the things you want to initialize, which you initialize on your Windows Service start:
public class SomeSettingsYouWantToInitialize
{
public string SomeSetting { get; set; }
}
public class WindowsServiceInstance : ServiceBase
{
protected override void OnStart(string[] args)
{
InitializeWcfService();
}
private void InitializeWcfService()
{
var settings = new SomeSettingsYouWantToInitialize
{
SomeSetting = "Foo"
};
_yourDependencyContainer.Register<SomeSettingsYouWantToInitialize>(settings);
}
}
Then (using whatever dependency injection framework you use), inject that into your service's constructor:
public class WebMonitorServiceLibrary
{
public WebMonitorServiceLibrary(SomeSettingsYouWantToInitialize settings)
{
// do stuff with settings
}
}
Generally, no. This is because by default (and following best practice) you will have configured your service to run per-call (or per session), which means there can be multiple instances of your actual service running in your service host.
Therefore, any requirement for you to be able to return an instance of the service from the service host will involve some nasty plumbing code and is not advised.
Specifically, however, there are two approaches you could use to do what you want.
The first involves running your service in InstanceContextMode.Single - this means there will be a single service instance which will handle all requests. If you do this then you can simply create the service instance and then pass it into the servicehost when you start the windows service:
var service = new MyService();
var host = new ServiceHost(service);
You then have access to the service instance and can call the operation directly.
service.MyOperation("something");
The second thing you can do for when you don't want to run a singleton service you can make your service implementation just a wrapper around a static instance of a shared class that actually process the requests. As an example:
public class MyService : IMyService
{
private static IMyService instance = new MySharedServiceClass();
public static IMyService Instance
{
get { return instance ; }
}
public bool MyOperation(string something)
{
return instance.MyOperation(something);
}
}
Then you can call the method on the class like this:
var host = new ServiceHost(typeof(MyService));
var instance = MyService.Instance;
instance.MyOperation("something");
I would still avoid doing this if at all possible. Think to yourself why do you even want this method called on startup? Surely it would be better to have this code directly in the windows service if it's something that needs to be run on startup?

WCF: calling self-hosted service from client callback handler

Problem:
getting a deadlock exception message in the WCF client.
Scenario:
Service calls a client callback (this call is completely independent and is initiated by some condition on the server).
While inside the client callback function, the client calls a function in the service and that's when the deadlock exception is thrown:
This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on CallbackBehaviorAttribute.
I tried to simplify the code as much as I can. I did read this article but still I cant find where the problem is: http://msdn.microsoft.com/en-us/library/cc294424.aspx
I'd appreciate any suggestions....
SERVICE:
[ServiceContract(Namespace = "http://abc.com/Core", SessionMode = SessionMode.Required, CallbackContract = typeof(ISvcCallback))]
public interface ISvc
{
// One way only - does not wait until operation completes and returns
// Can initiate session
[OperationContract(IsOneWay = true)]
void Initialize(string appId);
[OperationContract(IsInitiating = false)]
Account GetCurrentAccount();
}
public interface ISvcCallback
{
/// <summary>
/// Report status of the account
/// </summary>
/// <param name="acct"></param>
[OperationContract(IsOneWay=true)]
void AccountStatus(Account acct);
}
Service Implementation
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
public class Svc : ISvc
{
public Account GetCurrentAccount()
{
SipAccount sipAcct = null;
try
{
Account acct = m_MyBusinessObject.GetCurrentAccount();
}
catch (Exception ex)
{
}
return Acct;
}
}
}
CLIENT:
public class CallbackHandler : WcfSipItfService.IWinSipItfCallback
{
public void AccountStatus(Account Acct)
{
try
{
// display accout status in UI by delegate-wrapped event
// delegate and event declarations are somewhere else
// and work fine...
if (DisplayAccountStatusEvent != null)
DisplayAccountStatusEvent(Acct);
}
catch (Exception ex)
{
....
}
}
private void OnDisplayAccountStatusEvent(Account acct)
{
// call service function results in deadlock
Account acct = GetCurrentAccount();
}
}
The service is Duplex - uses WSDualHttpBinding.
The deadlock appears to be due to you making a new out bound call while processing a callback from the previous call.
The error message states that you may be able to solve it by "specify ConcurrencyMode of Reentrant or Multiple on CallbackBehaviorAttribute".
Edit
I missed the code that was off the screen. Couple of things to check:
Why do you need instance mode single?
Did you updated the service references after changing the concurrency mode?
What's your client? Is it a UI client? if so, you need to add callbackBehavior UseSynchronizationContext=false to client that implements callback contract.

How can a WCF Service Raise Events to its Clients?

I want to know is there way of Event Handling in WCF.
I came across Callbacks in WCF, but i want to do Event Handling in WCF.
My requirement is like i want to raise event to particular clients not to all the clients using Event Handling in WCF and i also want to maintain session.
I have seen Publisher/Subscriber model in WCF which deals with Callback , but this model publish to all the clients who have subscribed but i want to publish only to selected clients.
I think that can be done using Events in WCF.
Client side :
public class Callbacks : IServiceCallback
{
public void CallToMyClient(string name)
{
this.CallToMyClient(name);
}
}
protected void Page_Load(object sender, EventArgs e)
{
Callbacks callback = new Callbacks();
ServiceClient client = new ServiceClient(new InstanceContext(callback));
client.SubscribeClient();
client.DoSomeWork();
}
There is no Event in WCF to notify it's client but there is a callback channel, the purpose of the callback channel is same as event though the working principle is totally different in both cases.
To notify a particular client what you could do is store callback channel of that client while subscribing to somewhere, (I prefer Dictionary in this case). Later you can pick the instance and invoke your callback method over that channel, doing so only one client will get notified.
UPDATE
If you are interested here is the code:
public interface IClientCallback
{
//Your callback method
[OperationContract(IsOneWay = true)]
void CallToMyClient(string name);
}
[ServiceContract(CallbackContract = typeof(IClientCallback))]
public interface ITestService
{
[OperationContract(IsOneWay = true)]
void SubscribeClient();
[OperationContract(IsOneWay = true)]
void DoSomeWork();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class ServiceImplementation : ITestService
{
private static readonly List<IClientCallback> CallbackChannels = new List<IClientCallback>();
/// <summary>
/// client should call this method before being notified to some event
/// </summary>
public void SubscribeClient()
{
var channel = OperationContext.Current.GetCallbackChannel<IClientCallback>();
if (!CallbackChannels.Contains(channel)) //if CallbackChannels not contain current one.
{
CallbackChannels.Add(channel);
}
}
public void DoSomeWork()
{
//Here write your code to do some actual work
//After you done with your work notify client
//here you are calling only the first client that is registered
IClientCallback callbackChannel = CallbackChannels[0];
callbackChannel.CallToMyClient("You are the only one receving this message");
}
}
WCF Duple Operation and UI Threads By jeff.barnes
Perhaps this can help you.
The WCF doesn't support event handler. Callback channel is the way for it
If you are using WCF for RPC(as apposed to web service or rest) you can use .Net Remoting to perfrom event invocation cross process.
You cannot use events. You can use callbacks to simulate events.

Problems with WCF and Transaction

I have declared field "_accessToken" in my service implementation and initializing it inside a method call GetToken(). GetToken is the first method called by client. When client first time calls GetEmployees method which annotated with transaction, it returns the data. It checks _accesstoken value inside GetEmployees method which is not null in during first call However becomes null in subsequent calls!
What is the problem? Can anyone tell me.
Service Contract:
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IEmployeeService
{
[OperationContract]
LoginResponse Getoken(LoginRequest request);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
EmployeeResponse GetEmployees(EmployeeRequest request);
}
Service Implementation
private string _accessToken;
public TokenResponse GetToken(TokenRequest request)
{
_accessToken = new Guid();
}
[OperationBehavior(TransactionScopeRequired = true,TransactionAutoComplete = true)]
public EmployeeResponse GetEmployees(EmployeeRequest request)
{
if (_accessToken != null)
{
// Do processing
}
}
I'm not sure this has anything to do with transactions, rather your services instance management. I suspect you're using percall, in which case all calls get their own service instance. Try using per session, this should resolve your problem.
Here is some reading material: http://msdn.microsoft.com/en-us/magazine/cc163590.aspx
HTH,
Steve
The problem is in ServiceBehaviorAttribute ReleaseServiceInstanceOnTransactionComplete, which is set to true by default. While the attribute is enabled service instance will be destroyed after any transaction.
You can set the attribute to false, however it will make very complex solution and is bad architecture.
For example your service have two methods:
public void Method1()
{
//transaction
//use data base resources table1;
}
public void Method2()
{
//transaction
//use data base resources table1;
}
If the client calls Method1, then calls Method2 there can be in some cases deadlock, or Method2 will be waiting for releasing table1 by Method1.
Better use default settings. Or use PerCall session when session instance is recreated for every call.