I have a WCF service that is hosted in a Windows Service.
The WCF service is injected with a ConcurrentQueue<SomeClass>.
The Windows Service (that hosts the WCF service) is also injected with the ConcurrentQueue<SomeClass>.
The Windows Service starts the WCF service, and also spawns a worker thread.
The worker thread pushes (Enqueue) objects of SomeClass to the ConccurrentQueue.
I would like somehow for the WCF Service to be triggered when an object is enqueued to the ConcurrentQueue so that it could dequeue it (and any other object that might be in the queue), and send a message to all connected clients.
.
TWO QUESTIONS :
How do I make the WCF service 'hook' on the 'Enqueue' method of the injected ConccurentQueue, so that when objects are pushed into the queue - the WCF service will do something about it ?
If I do manage to somehow hook the 'Enqueue' event, and now the worker thread in the Windows Service has enqueued two objects into the queue - that means that it would also 'trigger' the WCF service's 'Enqueue hook' twice - will those two triggered events happen in different threads ? I need to somehow make sure that the WCF service pulls the objects from the queue in order. I do not want to suddenly see that for every Enqueue operation - the WCF service triggers in a seperate thread and pulls objects out ...
I hope my questions are clear enough ...
.
[Update]
After a chat with Chris, I have come to the conclusion that the best way to go at this would be to seperate the worker thread from the WCF service, and make the worker thread call the WCF service as a client. This means that I don't have to play around with the queue.
Wrap the ConcurrentQueue in a simple class that exposes Enqueue & Dequeue calls, then place your hook inside of this class. Whenever YourClass.Enqueue is called, trigger the WCF activity, which can call YourClass.Dequeue. YourClass.Dequeue will drain the queue & place it into an ordered enumerable that the WCF service can then process in order.
Related
Presently I have one class which monitor serial ports for incoming data, process the data and raises events through delegates/events based on the received data. This is a stand alone application. Now I have to convert it to a service so that the serial port monitor class will start as a service when the windows starts and a client applications subscribes to the events from either a remote PC or from the local machine. I have seen many articles on using WCF for this kind of applications. But WCF is message based and it will create a service obect when the client is requested. But my requirement is the service should be started automatically and the client application should be able to subscribe for the events of the service class instance which is already created during startup. How can I achieve this using WCF ?
The default behavior in WCF is to create a new instance of your service class to handle each incoming request, but you can override this by decorating your class with:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
To get good performance with a Singleton, though, there's a few things you'll need to consider:
Since you'll likely need to do some configuration of your Singleton instance, you'll probably want to use the ServiceHost constructor method that takes a Singleton instance as an argument. (For an example, see Figure 8 Initializing and Hosting a Singleton in this article
Threading: The default threading model (ConcurrencyMode) only allows a single thread to have access to your Singleton instance at a time. You may need to look at using ConcurrencyMode = ConcurrencyMode.Multiple to get good performance (which means you'll need to handle threading-related issues yourself).
Make sure the methods in your Callback contract are marked as [OperationContract(IsOneWay = true)] so that publishing events back to the subscribers doesn't cause your service instance to block until the event handler completes. (Using WCF in this way is covered in detail in this article by Juval Lowy
I have some queries about WCF and multithreading.
My plan is to place items onto the Thread Pool and for it to process messages from the MSMQ queue.
I also will be hosting WCF in WAS.
I am wondering how the threading will work at this point. For example messages will be picked up by the WCF binding to the MSMQ queue and I know that WAS will spin up the service as and when it requires to. But lets say if we have 100 messages to process (100 messages per second for example) - would these be delivered in a threaded way or in a single thread?
If in a threaded manner then how best to commit or abort transactions? Any special considerations?
Sorry for the questions - just need to clarify this.
Its not clear what "placing items onto the Thread Pool" does but on the WCF side, a service using the netMsmqBinding handles "calls" in a similar way as other WCF bindings. The difference is that a "call" is actually an MSMQ message in a queue.
This article on netMsmqBinding gives a very clear explanation of how the binding works. If you configure the WCF service with its default InstanceContext setting (per call or per session depending on the .NET version), the service instances will pick up messages off the queue as-if they were a standard call each. There are setting in MSMQ and WCF that can affect this behavior to make the messages be processed sequentially but that's not the default.
Let WCF handle multi-threading for you by leaving the service set to per call (or per session) and for transactions, look at the code in this sample in MSDN to see how to work with them.
I am trying to understand how instances with WCF works. I have a WCF service which the InstanceContextMode set to PerCall (so for each call of every client a new instance will be created) and ConcurrencyMode set to Single (so the service instance is executing exactly one or no operation call at a time).
So with this I understand that when a client connects a new instance is created. But what happens when the client leaves the service. Does the instance die. The reason I ask is because I need to implement a ConcurrentQueue in the service. So a client will connect to the service and put loads of data to be processed and then leave the service. The workers will work of the queue. After the work is finished I need the instance to be destroyed.
Basically, learning from the "WCF Master Class" tought by Juval Lowy, per-call activation is the preferred choice for services that need to scale, i.e. that need to handle lots of concurrent requests.
Why?
With the per-call, each incoming request (up to a configurable limit) gets its own, fresh, isolated instance of the service class to handle the request. Instantiating a service class (a plain old .NET class) is not a big overhead - and the WCF runtime can easily manage 10, 20, 50 concurrently running service instances (if your server hardware can handle it). Since each request gets its own service instance, that instance just handles one thread at a time - and it's totally easy to program and maintain, no fussy locks and stuff needed to make it thread-safe.
Using a singleton service (InstanceContextMode=Single) is either a terrible bottleneck (if you have ConcurrencyMode=Single - then each request is serialized, handled one after another), or if you want decent performance, you need ConcurrencyMode=Multiple, but that means you have one instance of your service class handling multiple concurrent threads - and in that case, you as a programmer of that service class must make 100% sure that all your code, all your access to variables etc. is 100% thread-safe - and that's quite a task indeed! Only very few programmers really master this black art.
In my opinion, the overhead of creating service class instances in the per-call scenario is nothing compared to the requirements of creating a fully thread-safe implementation for a multi-threaded singleton WCF service class.
So in your concrete example with a central queue, I would:
create a simple WCF per-call service that gets called from your clients, and that only puts the message into the queue (in an appropriate fashion, e.g. possibly transforming the incoming data or something). This is a quick task, no big deal, no heavy processing of any kind - and thus your service class will be very easy, very straightforward, no big overhead to create those class instances at all
create a worker service (a Windows NT service or something) that then reads the queue and does the processing - this is basically totally independent of any WCF code - this is just doing dequeuing and processing
So what I'm saying is : try to separate the service call (that delivers the data) from having to build up a queue and do large and processing-intensive computation - split up the responsibilities: the WCF service should only receive the data and put it into a queue or database and then be done with it - and a second, separate process should do the processing/heavy-lifting. That keeps your WCF service lean'n'mean
Yes, per call means, you will have a new insance of the service per each connection, once you setup the instance context mode to percall and ConcurrencyMode to single, it will be single threaded per call. when the client leaves, done with the job, your instance will dispose. In this case, you want to becareful not to create your concurrentqueue multiple times, as far as i can imagine, you will need a single concurrentqueue? is that correct?
I would recommend you to use IntanceContextMode=Single and ConcurrencyMode to Mutli threaded. This scales better.if you use this scheme, you will have a single concurrent queue, and you can store all your items within that queue.
One small note, ConcurrentQueue, has a bug, you should be aware of, check the bug database.
new to WCF.
I have a client which is deadlocking when calling a WCF service.
The service will invoke a callback to the client at the time of the call which is marked as IsOneWay. I have confirmed that the service is not blocking on the callback.
The client then immediately calls the same service again (in a tight loop), without having yet serviced the callback. The client then deadlocks (and a breakpoint on the service side never gets triggered).
So to recap:
CLIENT SERVICE
Call service -----------------------> (service breakpoint triggers)
(waiting for dispatch thread) <------ Invoke callback (IsOneWay - doesn't block)
Service returns
Call service again immediately -----? (service breakpoint doesn't trigger)
(deadlock)
I am assuming that the callback has grabbed some WCF lock at the client end, and then the second service call from the client also wants that lock, so deadlock results. But this is just assumption.
I have read about ConcurrencyMode but I can't decide which mode to use, or where to put it because I'm not 100% clear on what is going on, and what is being blocked exactly.
I would also prefer to keep all callbacks being serviced by the dispatch thread if possible as it keeps the code simpler.
Can any WCF experts shed light on exactly what is going on here?
Many thanks
OK, think I've sussed it.
WCF services default to single threaded. All calls and callbacks get marshalled to a single thread (or SynchronizationContext to be more accurate).
My app is a single threaded WPF app, so the SynchronizationContext gets set to the dispatch thread.
When the callback comes in it tries to marshal the call to the dispatch thread, which of course is sat blocking on the original service call. I'm not clear it locks exactly, but there's obviously some global lock that it tries to get before waiting for the dispatch thread.
When the dispatch thread then calls the service again, it deadlocks on this global lock.
Two ways around it:
1) Create the service proxy on a different thread in the first place. All calls will get marshalled through this thread instead and it won't matter that the dispatch thread is blocked.
2) Apply [CallbackBehavior(UseSynchronizationContext = false)] attribute to the client class that implements the callback. This means WCF will ignore the synchronisation context when the callback comes in, and it will service it on any available thread.
I went with 2. Obviously this means I need to marshal callbacks that could update the GUI to the dispatch thread myself, but luckily my callback implementation is a small wrapper anyway, so I just do a _dispatcher.BeginInvoke() in each callback method to marshal ASYNCHRONOUSLY. The dispatch thread will then service when it gets a chance which is what I wanted in the first place.
The sequence that you have depicted resembles a synchronous call. While in an async call, the sequence would be:
Client Server
Call service --------------->ProcessRequest(1) //Your for loop for instance.
Call service --------------->ProcessRequest(2)
Call service --------------->ProcessRequest(3)
Call service --------------->ProcessRequest(4)
Call service --------------->ProcessRequest(5)
Callback awake <---------------Response1 //Responses tends to pour in...
Callback awake <---------------Response2
Callback awake <---------------Response3
Callback awake <---------------Response4...
In each case of each async web service call, the system creates a separate IO thread(IOCP thread), and processes the request. In this, seldom you will find a deadlock.
I have found this way, even when called within a loop, to be working very well.
You can, for instance, register for the event .OnProcessComplete, and then call the ProcessCompleteAsync method.
I have an existing WCF service that I now need to have consume an external WCF callback (aka duplex) service. The duplex service is by its nature asynchronous and yet I need to keep my original WCF service synchronous. Is there a well known pattern to do this? What are the most important pitfalls I need to watch out for?
My current intention is to invoke the duplex service and then wait for a ManualResetEvent to be raised. When the callback is called by the duplex, it would reset the event and make the waiting operation resume and complete its work.
Yes, I'd go this way too. Pay attention to how you control these events' lifetime. Seems like you'll need to pass some id to the duplex service so that, when callback arrives, this id could be resolved into the original ManualResetEvent.