Silverlight HttpWebRequest.Create висит внутри асинхронного блока - PullRequest
10 голосов
/ 16 июня 2010

Я пытаюсь создать прототип вызова 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 

Это может быть проблема с песочницей, поскольку мой серебряный свет обслуживается моей файловой системой, а Uri - это ссылка на localhost - хотя я даже не получаю исключения. Мысли? * * 1004

Thx


ОБНОВЛЕНИЕ 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?

Ответы [ 4 ]

5 голосов
/ 25 июня 2010

(Спасибо, что отправили это в fsbugs, чтобы заставить нас внимательно посмотреть.)

Проблема в Async.RunSynchronously. При вызове в потоке пользовательского интерфейса это блокирует поток пользовательского интерфейса. И получается, что WebRequest.Create() в Silverlight отправляет поток пользовательского интерфейса. Так что это тупик.

В общем, старайтесь избегать Async.RunSynchronously в Silverlight (или в любом потоке пользовательского интерфейса). Вы можете использовать Async.StartImmediate в этом примере. В качестве альтернативы, я думаю, вы можете без проблем вызвать RunSynchronously из любого фонового потока. (Я сам не пробовал достаточно комплексных сценариев Silverlight, чтобы предложить еще больше советов. Вы можете проверить

Программирование игр на F # (с Silverlight и WPF)

F # и Silverlight

F # асинхронный на стороне клиента

для нескольких коротких примеров.)

(В ретроспективе команда разработчиков F # считает, что, возможно, нам не следовало включать Async.RunSynchronously в FSharp.Core для Silverlight; метод потенциально нарушает дух платформы (без блокирующих вызовов). Возможно, мы откажемся этот метод в будущих выпусках Silverlight. С другой стороны, он по-прежнему имеет действительное использование для параллелизма с интенсивной загрузкой процессора в Silverlight, например, для параллельной работы с кодом (не-IO) в фоновых потоках.)

2 голосов
/ 16 июня 2010

Похоже, похожая проблема здесь - хотя нет ссылки на silverlight (на самом деле это "класс обслуживания Windows"):

http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/10854fc4-2149-41e2-b315-c533586bb65d

0 голосов
/ 01 июня 2011

У меня была похожая проблема. Я делал Silverlight MVVM ViewModel для привязки данных из Интернета. Дон Сайм прокомментировал себя:

Я не эксперт по связыванию данных, но я верю, что вы не можете «спрятать» асинхронность такой модели представления для WPF и Silverlight. Я думаю, что вам нужно выставить Task, Async или наблюдаемая коллекция. AFAIK единственный способ связать Silverlight и WPF асинхронно к свойству, если оно является наблюдаемой коллекцией.

В любом случае, я установил F # Power Pack, чтобы получить AsyncReadToEnd. Это не помогло ... Я добавил домены в доверенные сайты, но это не помогло ... Затем я добавил MySolution.Web -asp.net-site и 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
0 голосов
/ 16 июня 2010
...