Запустить операцию службы в потоке, отличном от потока службы

#c# #.net #winforms #multithreading #wcf

#c# #.net #winforms #многопоточность #wcf

Вопрос:

Я работаю над приложением WinForms, которое будет содержать WebBrowser и будет действовать как служба для другого процесса. Я хотел бы реализовать NavigateAndWait метод, но, по-видимому, когда я вызываю методы моей службы (моего приложения WinForms) из клиента, эти методы выполняются в том же потоке или каким-то образом синхронизируются с потоком пользовательского интерфейса службы. Это то, что у меня есть до сих пор:

Обслуживание:

 public class Browser : IBrowser
{
    private bool _Navigating = false;

    public bool Navigating
    {
        get { return _Navigating; }
    }

    public Browser()
    {
        ServiceForm.Instance.webBrowser1.DocumentCompleted  = new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
    }

    void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        if(e.Url == ServiceForm.Instance.webBrowser1.Url) _Navigating = false;
    }

    public void Navigate(string url)
    {
        _Navigating = true;
        ServiceForm.Instance.webBrowser1.Navigate(url);
    }
}
  

Клиент:

     private void button1_Click(object sender, EventArgs e)
    {
        EndpointAddress endpointAddress = new EndpointAddress("net.pipe://localhost/PipeReverse/PipeReverse");
        NetNamedPipeBinding pipeBinding = new NetNamedPipeBinding();
        ChannelFactory<IBrowser> pipeFactory = new ChannelFactory<IBrowser>(pipeBinding, endpointAddress);
        IBrowser browser = pipeFactory.CreateChannel();
        browser.Navigate("http://www.google.com");
        while (browser.Navigating) { }
        MessageBox.Show("done!");
    }
  

Это работает нормально, за исключением того, что мой клиент на некоторое время зависнет (буквально!). Я мог бы легко запустить button1_Click другой поток в моем клиенте, но что я действительно хотел бы сделать, так это реализовать my NavigateAndWait (что в основном было бы последними тремя строками кода в button1_Click методе) в моем сервисе. Но я пробовал это, и он никогда не возвращается, по-видимому, потому DocumentComplete , что обработчик событий никогда не вызывается, потому что я нахожусь внутри while цикла, выполняемого в потоке пользовательского интерфейса службы.

Итак, мой вопрос в том, как я могу сказать WCF запустить операцию моей службы в потоке, отличном от потока пользовательского интерфейса, чтобы я мог выполнить свой while цикл в этом другом потоке?

Комментарии:

1. Плохо: «пока (браузер. Навигация) { }»

2. @Steve: что я должен использовать вместо этого (учитывая, что я пытаюсь написать NavigateAndWait метод)?

3. Поместить событие в ваш интерфейс iBrowser и вызвать его из вашего webBrowser1_DocumentCompleted метода?

4. Это не было NavigateAndWait бы методом. Я знаю, как использовать webBrowser1_DocumentCompleted событие, но, как вы можете видеть, я пытаюсь обернуть его, как WaitN это делает библиотека.

5. Вы намеренно хотите заблокировать основной поток? Не кажется хорошей идеей. Если вы хотите дождаться потока, вам следует изучить примитивы синхронизации потоков, которые есть в .NET для вас, вместо того, чтобы пытаться выполнить блокировку с помощью цикла while. Я рад, что вы решили удалить комментарий о том, что я трачу ваше время.

Ответ №1:

Вам нужно использовать UseSynchronizationContext = false опцию в [ServiceBehavior] атрибуте вашего сервиса. Это скажет WCF не принудительно отправлять все запросы в поток, в котором он был создан (в вашем случае, в поток пользовательского интерфейса). Этот атрибут будет находиться в классе службы (а не в интерфейсе).

Комментарии:

1. Означает ли это, что принудительное исполнение не означает, что оно может выполняться в потоке пользовательского интерфейса, или если заставить его этого не делать?

2. Хорошо, это сработало. Просто нужно убедиться, что он никогда не будет запускаться в потоке пользовательского интерфейса службы (если, конечно, я не вызываю его из потока пользовательского интерфейса). Знаете ли вы, так ли это?