Во-первых, используйте
.GetAwaiter().GetResult()
если вам нужно получить результат синхронно.
Во-вторых, ваш дедлок это хрестоматийный пример, примерно как детский мат. Дело в том, что вы не указали
.ConfigureAwait(false)
в своём асинхронном вызове, это значит, что CLR будет ждать освобождения вызывающего потока, чтобы продолжить выполнять код после await. Однако вызывающий поток уже бесконечно занят ожиданием завершения вашего асинхронного метода там, где вы получаете Result - вот вам и типичный deadlock.
Таким образом, вам нужно либо добавить
.ConfigureAwait(false)
к вашему асинхронному вызову (это приведет к необходимости выполнять дальнейшие изменения в UI через диспетчер,
Dispatcher.Invoke
в WPF), либо запустить свой код в контексте синхронизации, отличном от того, который используется в UI - самый простой способ это вообще не использовать контекст - выполнить свой код внутри Task.Run:
Task.Run(async() => html = await browser.GetSourceAsync());
Или
private async Task<string> GetHTMLFromWebBrowser()
{
return await browser.GetSourceAsync();
}
....
Task.Run(async() => html = await GetHTMLFromWebBrowser());
.ConfigureAwait() в таком случае не нужен, т. к. без контекста синхронизации он ничего не делает.