Silverlight HttpWebRequest.Create зависает внутри асинхронного блока
Я пытаюсь прототипировать вызов Rpc на веб-сервер JBOSS из Silverlight (4). Я написал код и работает в консольном приложении, поэтому я знаю, что Jboss отвечает на веб-запрос. Портирование его на Silverlight 4 вызывает проблемы:
let uri = new Uri(queryUrl)
// this is the line that hangs
let request : HttpWebRequest = downcast WebRequest.Create(uri)
request.Method <- httpMethod;
request.ContentType <- contentType
Это может быть проблема с песочницей, так как мой silverlight отключается от моей файловой системы, а Uri - ссылка на localhost - хотя я даже не получаю исключения. Мысли?
спасибо
ОБНОВЛЕНИЕ 1
Я создал новый проект и портировал свой код, и теперь он работает; что-то должно быть неустойчивым с точки зрения интеграции F # Silverlight. По-прежнему хотелось бы поразмышлять над отладкой "висячего" веб-сайта в старой модели...
ОБНОВЛЕНИЕ 2
let uri = Uri("http://localhost./portal/main?isSecure=IbongAdarnaNiFranciscoBalagtas")
// this WebRequest.Create works fine
let req : HttpWebRequest = downcast WebRequest.Create(uri)
let Login = async {
let uri = new Uri("http://localhost/portal/main?isSecure=IbongAdarnaNiFranciscoBalagtas")
// code hangs on this WebRequest.Create
let request : HttpWebRequest = downcast WebRequest.Create(uri)
return request
}
Login |> Async.RunSynchronously
Мне что-то не хватает; блок Async отлично работает в консольном приложении - не разрешено ли в приложении Silverlight?
Ответы
Ответ 1
(Спасибо, что отправили это в fsbugs, чтобы заставить нас внимательно посмотреть.)
Проблема Async.RunSynchronously
. При вызове потока пользовательского интерфейса это блокирует поток пользовательского интерфейса. И получается, что WebRequest.Create()
в Silverlight отправляется в поток пользовательского интерфейса. Так что это тупик.
В общем, старайтесь избегать Async.RunSynchronously
в Silverlight (или в любом потоке пользовательского интерфейса). Вы можете использовать Async.StartImmediate
в этом примере. В качестве альтернативы, я думаю, вы можете вызвать RunSynchronously
из любого фонового потока без проблем. (Я еще не пробовал достаточно сложных сквозных сценариев Silverlight, чтобы предложить еще несколько советов. Вы можете проверить
Игровое программирование в F # (с Silverlight и WPF)
F # и Silverlight
F # async на стороне клиента
для нескольких коротких примеров.)
(В ретроспективе команда разработчиков F # считает, что мы, возможно, не должны были включать Async.RunSynchronously
в FSharp.Core для Silverlight, способ потенциально нарушает дух платформы (без блокирующих вызовов). Возможно, мы будем осуждать этот метод в будущих версиях Silverlight. С другой стороны, он по-прежнему имеет допустимые применения для интенсивного использования ресурсов parallelism для Silverlight, например, для запуска параллельного параллельного (не-IO) кода в фоновом потоке.)
Ответ 2
Похоже на аналогичную проблему - хотя ссылка на silverlight не указана (на самом деле это "класс обслуживания Windows" ):
http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/10854fc4-2149-41e2-b315-c533586bb65d
Ответ 3
У меня была аналогичная проблема. Я делал Silverlight MVVM ViewModel для привязки данных из Интернета.
Дон Симе прокомментировал себя:
Я не специалист по связыванию данных, но я верьте, что вы не можете "скрыть" асинхронность такой модели для WPF и Silverlight. Я думаю, вам нужно будет выставить задачу, Async или наблюдаемый сбор. AFAIK единственный способ заставить Silverlight и WPF связываться асинхронно к свойству, если оно является наблюдаемой коллекцией.
В любом случае, я установил F # Power Pack для получения AsyncReadToEnd.
Это не решило дело... Я добавил домены на доверенные сайты, но это не помогло... Затем я добавил MySolution.Web -asp.net-сайт и clientaccesspolicy.xml. Я не знаю, имели ли они эффект.
Теперь, с Async.StartImmediate, я получил вызов веб-службы:
let mutable callresult = ""
//let event = new Event<string>()
//let eventvalue = event.Publish
let internal fetch (url : Uri) trigger =
let req = WebRequest.CreateHttp url
//req.CookieContainer <- new CookieContainer()
let asynccall =
async{
try
let! res = req.AsyncGetResponse()
use stream = res.GetResponseStream()
use reader = new StreamReader(stream)
let! txt = reader.AsyncReadToEnd()
//event.Trigger(txt)
callresult <- txt //I had some processing here...
trigger "" |> ignore
with
| :? System.Exception as ex ->
failwith(ex.ToString()) //just for debug
}
asynccall |> Async.StartImmediate
Теперь мне понадобится моя ViewModel для прослушивания изменяемого вызова.
В вашем случае вам также нужен crossdomain.xml для сервера.
Триггер необходим для использования UI-потока:
let trigger _ =
let update _ = x.myViewModelProperty <- callresult
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(new Action(update)) |> ignore
fetch serviceUrl trigger
Ответ 4
Я думаю, что вы нажимаете максимальное ограничение на http-соединения: см. Асинхронный вызов веб-сервера в Silverlight и максимальные HTTP-соединения и http://weblogs.asp.net/mschwarz/archive/2008/07/21/internet-explorer-8-and-maximum-concurrent-connections.aspx