#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. Хорошо, это сработало. Просто нужно убедиться, что он никогда не будет запускаться в потоке пользовательского интерфейса службы (если, конечно, я не вызываю его из потока пользовательского интерфейса). Знаете ли вы, так ли это?