Служба WCF с рабочим потоком? - PullRequest
6 голосов
/ 20 мая 2011

Я пытаюсь написать сервис WCF, который будет находиться в службе Windows. Эта служба WCF будет просто добавлять строки в список, а затем рабочий поток будет периодически обрабатывать этот список. Каков наилучший способ достичь этого? Я прочитал противоречивые примеры, которые привели меня в замешательство. Каков наилучший способ службы и потока совместно использовать объект списка?

Обновление: Спасибо за ответы до сих пор. Просто чтобы уточнить, я не борюсь с синхронизацией списка или как сделать его потокобезопасным. Это все похоже на те же принципы, что и я в C ++. Я борюсь с тем, где определить этот список, чтобы он был доступен как из службы WCF, так и из рабочего потока. В C ++ я бы создал список в глобальной области видимости, но C # не имеет глобальной области видимости. Если я определю его в классе обслуживания WCF, поток не сможет его увидеть. Если я определю это в классе обслуживания (где функция потока определена и запущена), служба WCF не сможет его увидеть. Я уверен, что я сделал нечто подобное в ATL некоторое время назад, но сегодня пятница, и серые клетки отказались от этого дня.

Update2: Где я должен определить рабочий поток? В классе службы Windows (т.е. хосте) или в службе WCF? Должна ли служба WCF быть единственной службой, имеющей член списка и функцию потока? Это решает проблему доступа. Сделав много COM, я думаю о WCF-сервисе как о COM-компоненте с экземпляром, умирающим после обращения к нему. Это привело меня к желанию поместить статический список и функцию потока в класс обслуживания Windows. Это все еще кажется более естественным для этого, но, возможно, я просто не думаю о .NET.

Ответы [ 6 ]

3 голосов
/ 20 мая 2011

1) Создать службу Windows

2) Хост WCF в WS (http://msdn.microsoft.com/en-us/library/ms731758.aspx)

3) Сделать синхронизацию потоков (http://www.albahari.com/threading/part2.aspx)

4) прибыль!

2 голосов
/ 20 мая 2011

Вот небольшая оболочка, которая использует параллельные коллекции в .NET 4 (в этом отношении я также использую для этого примера библиотеку параллельных задач в .NET 4).Похоже, что ваша формулировка проблемы - классический производитель / потребитель для разных потоков или процессов, так что это должно дать вам хорошее представление о том, как структурировать вещи:

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();
        }
    }
}
1 голос
/ 20 мая 2011

Вы можете запустить рабочий поток в статическом конструкторе службы WCF. Конечно, будет только один рабочий поток независимо от ConcurrencyMode и InstanceContextMode. Если это то, что вы хотите, то следующий код может работать для вас.

[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);
  }
}

Я использовал шаблон «производитель-потребитель» для реализации логики рабочего потока. Класс BlockingCollection предоставляет простой механизм для реализации этого шаблона.

1 голос
/ 20 мая 2011

Я думаю, что вы конкретно спрашиваете, как передать ссылку на экземпляр коллекции в экземпляр службы WCF. Вот суть проблемы: обычно код ServiceHost раскручивает экземпляры службы WCF на основе параметра InstanceContextMode для службы (значение по умолчанию - PerSession). Это означает, что он будет раскручивать экземпляр на сеанс клиента по требованию. Поскольку ваш хост-код не может напрямую обращаться к этим автоматически созданным экземплярам, ​​вы не можете внедрить общую коллекцию.

Одним из решений для вашего хоста является предоставление экземпляра службы WCF с общей коллекцией, добавляемой либо с помощью параметра конструктора, либо с помощью установщика свойства. Существует конструктор для ServiceHost, который использует этот экземпляр, но имеет существенный компромисс. Этот подход означает, что вы создаете одноэлементную службу WCF ( InstanceContextMode = Single ), поэтому масштабируемость пострадает. Вы можете несколько смягчить это, установив ConcurrencyMode в несколько значений, но вам также придется написать код службы WCF для обработки внутренней синхронизации ресурсов.

1 голос
/ 20 мая 2011

Общий шаблон заключается в запуске хоста службы во время запуска службы. После запуска вы можете создать свой рабочий поток. Рабочий поток и сервисные вызовы должны будут получить доступ к общей структуре данных, которая должна быть синхронизирована. Попросите сервис депонировать элементы в общем объекте данных и подайте дескриптор ожидания для запуска рабочего потока. После того, как работник завершает сброс состояния дескриптора ожидания.

0 голосов
/ 20 мая 2011

. В C ++ я бы создал список в глобальной области видимости, но C # не имеет глобальной области видимости.

Любой открытый статический член является глобально видимым. Конечно, вам придется реализовать собственную синхронизацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...