WCF service with working thread?

I am trying to write a WCF service that will be in a windows service. This WCF service will simply add rows to the list, and then the workflow will process this list periodically. What is the best way to achieve this? I read conflicting examples that left me confused. What is the best way to use the service and stream for a list object?

Update: Thanks for the answers. To clarify, I am not trying to synchronize the list or how to make it thread safe. All this is similar to the same principles as in C ++. What I'm struggling with is defining this list so that it is accessible from both the WCF service and the workflow. In C ++, I would create a list in the global scope, but C # does not have a global scope. If I define it in the WCF service class, the stream will not be able to see it. If I define this in the service class (where the thread function is defined and started), the WCF service will not be able to see it. I'm sure some time ago I did something similar in ATL, but on Friday afternoon, and the gray cells refused during the day.

Update2: Where should I define the workflow? In the Windows service class (i.e. in the host) or in the WCF service? Should a WCF service be a single-user service that has a list item and stream function? This solves the access problem. Having done a lot of COM, I think of the WCF service as a COM component when an instance dies after it is accessed. This prompted me to enable the static list and stream function in the Windows service class. This still seems like a more natural place for it, but maybe I just don't think about the .NET way.

+6
source share
6 answers

1) Create a Windows service

2) Host WCF in WS ( http://msdn.microsoft.com/en-us/library/ms731758.aspx )

3) Make thread synchronization ( http://www.albahari.com/threading/part2.aspx )

4) profit!

+3
source

Here is a small little shell that uses parallel collections in .NET 4 (in this case, I also use the parallel task library in .NET 4 for this example). Your expression about the problem seems to be a classic producer / consumer on different threads or processes, so this should give you a decent idea on how to structure things:

namespace ConcurrentCollectionTest { using System; using System.Collections.Concurrent; using System.Threading.Tasks; internal static class Program { private static void Main(string[] args) { ConcurrentQueue<string> cq = new ConcurrentQueue<string>(); BlockingCollection<string> bc = new BlockingCollection<string>(cq); bool moreItemsToAdd = true; // Consumer thread Task.Factory.StartNew(() => { while (!bc.IsCompleted) { string s = bc.Take(); Console.WriteLine(s); } }); // Producer thread Task.Factory.StartNew(() => { int i = 1; while (moreItemsToAdd) { bc.Add("string " + i++); } bc.CompleteAdding(); }); // Main Thread Console.ReadLine(); moreItemsToAdd = false; Console.ReadLine(); } } } 
+2
source

A common pattern is to start the service host at the beginning of the service. After starting, you can create a workflow. Workflow and service calls must access a common data structure that needs to be synchronized. Have service deposit points in a shared data object and tell Wait handle to start the workflow. As soon as the worker completes reset the wait descriptor state.

+1
source

I think that you are asking specifically how you pass the reference of the collection instance to the WCF service instance. Here's the gist of the problem: usually ServiceHost code will deploy WCF service instances based on the InstanceContextMode parameter for the service (the default is PerSession). This means that it will grow the instance per client session on demand. Since your host code cannot directly access these automatically created instances, you cannot enter a shared collection.

One solution for your host is to provide an instance of the WCF service with a shared collection, added either through a constructor parameter or through a property setting tool. There is a constructor for ServiceHost that accepts this instance, but has a big compromise. This approach means that you are creating a single-level WCF service ( InstanceContextMode = Single ), so scalability will suffer. You can mitigate this a bit by setting ConcurrencyMode to a few, but you will also have to write your WCF service code to handle internal resource synchronization.

+1
source

You can start the workflow in the static WCF service constructor. Of course, there would be only one worker thread, regardless of ConcurrencyMode and InstanceContextMode . If this is what you want, then the following code may work for you.

 [ServiceContract] public interface IYourService { [OperationContract] void QueueStringValue(string value); } [ServiceBehavior(...)] public class YourService : IYourService { private static BlockingCollection<string> s_Queue = new BlockingCollection<string>(); static YourService() { var thread = new Thread( () => { while (true) { string value = s_Queue.Take(); // Process the string here. } }); thread.IsBackground = true; thread.Start(); } public void QueueStringValue(string value) { s_Queue.Add(value); } } 

I used the producer-consumer pattern to implement workflow logic. The BlockingCollection class provides a simple mechanism for implementing this template.

+1
source

. In C ++, I would create a list in the global scope, but C # does not have a global scope.

Any public static member is displayed worldwide. Of course, you have to do your own synchronization.

0
source

Source: https://habr.com/ru/post/888648/


All Articles