Как асинхронно ожидать ответа от внешнего приложения, которое перехватывает вывод на принтер - PullRequest
2 голосов
/ 07 февраля 2012

Я разработал систему, которая состоит из 3 отдельных приложений:

  1. Веб-приложение
  2. Приложение службы WCF, которое получает запросы от веб-приложения, выполняет соответствующее действие и печатает результат, используя класс SendKeys SendKeys.SendWait("^p"); (при этом отправляется команда Ctrl + P, которая печатает то, что на экране).
  3. Консольное приложение, которое перехватывает вывод принтера (виртуальный принтер через Redmon) через Console.In (как предложено здесь

Приложение службы WCF и веб-приложение могут легко взаимодействовать, но между приложением службы и консольным приложением отсутствует прямая связь. Консольное приложение запускается только при наличии задания на принтер, а приложение WCF не знает результат задания на печать.

Существует ли способ заставить приложение службы WCF получать обратную связь от печатного задания (было ли оно в порядке или нет), чтобы оно могло отправлять соответствующий ответ обратно в веб-приложение, не делая Thread.Sleep() каждую секунду, пока принтер приложение заканчивает печать и сохраняет результат в файл или базу данных?

Можно ли как-нибудь приостановить поток в приложении-службе WCF и возобновить его (при отправке информации обратно) из приложения консоли принтера после завершения процесса печати?

Edit:

Мне удалось найти решение по советам Ричарда Блюетта. Это решение заставит приложение службы WCF ждать, пока задание печати будет завершено, но оно будет ограничивать выполнение приложением WCF только одного задания печати за раз.

Я создаю EventWaitHandle с некоторым ключом в приложении WCF, например:

EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.ManualReset, "unique-key");
WaitHandle.WaitAny(new WaitHandle[] { ewh });

И я могу вернуться к теме из Консольного приложения, например:

EventWaitHandle ewh = EventWaitHandle.OpenExisting("unique-key");
ewh.Set();

С решением Ричарда этого не произойдет, и несколько вызовов службы WCF могут выполняться одновременно.

1 Ответ

1 голос
/ 07 февраля 2012

Предполагая, что для задания на печать существует уникальный идентификатор, консольное приложение может вызвать службу WCF, чтобы сообщить, что задание на печать выполнено успешно или не выполнено.

Служба WCF должна будет либо блокироваться до тех пор, пока не поступит вызов завершения (ожидающий, скажем, ManualResetEventSlim), либо вам придется записать службу как асинхронную службу , чтобы поток запроса мог быть возвращен пул во время выполнения задания на печать.

Причина, по которой вам нужен уникальный идентификатор для задания на печать, заключается в том, что вам придется хранить структуру данных в памяти в сервисе, отображая уникальный идентификатор на событие, чтобы вы могли сигнализировать правильный запрос на ожидание, когда его задание будет выполнено

Когда служба WCF создает задание на печать, она помещает запись, скажем, в ConcurrentDictionary, отображающий printJobId в не сигнализированный ManualResetEventSlim (по одному для каждого задания печати). Затем он ожидает сигнала события.

Теперь, когда задание на печать завершается, консольное приложение, в свою очередь, вызывает службу WCF, передавая свой printJobId. Эта операция относится к словарю, захватывает событие и сигнализирует о нем. Исходный вызов теперь просыпается, зная, что задание на печать завершено.

Статус задания на печать также может быть передан через эту структуру данных словаря, поэтому у вас будет что-то вроде

class PrintJob
{
    public PrintJob()
    { 
        Event = new ManualResetEventSlim();
    }

    public ManualResetEventSlim Event {get; private set;}

    public int Status{ get; set;}
}

и словарь сопоставит printJobId с одним из них для каждого задания печати. Консольное приложение под названием операция установит статус результата задания печати

...