Асинхронный вызов Silverlight 4 для потоковой передачи XML в арсенале World of Warcraft на C #

Я застрял на этих выходных и с треском провалился!
Пожалуйста, помогите мне вернуть себе рассудок !!

Ваша задача

Я подумал, что для моего первого приложения Silverlight было бы интересно использовать арсенал World of Warcraft для составления списка персонажей моей гильдии. Это предполагает создание асинхронного перехода от Silverlight (да!) К арсеналу WoW, основанному на XML. ПРОСТО ЭХ?

Взгляните на эту ссылку и откройте исходный код. Вы поймете, что я имею в виду: http://eu.wowarmory.com/guild-info.xml?r=Eonar&n=Gifted и талантливые

Ниже приведен код для получения XML (вызов ShowGuildies справится с возвращенным XML - я протестировал это локально и знаю, что это работает).

Мне вообще не удалось получить ожидаемый возвращенный XML.

Примечания:

  • Если браузер способен преобразовывать XML, он это сделает, в противном случае будет предоставлен HTML. Думаю, он проверяет UserAgent
  • Я опытный веб-разработчик asp.net на C #, так что не торопитесь, если вы начнете говорить о нативном для Windows Forms / WPF
  • Кажется, я не могу установить параметр UserAgent в .net 4.0 - по какой-то причине это не похоже на свойство объекта HttpWebRequest - я думаю, что раньше он был доступен.
  • Silverlight 4.0 (изначально был создан как 3.0 до того, как я обновил свою установку Silverlight до 4.0)
  • Создано с использованием C # 4.0
  • Пожалуйста, объясните, как будто вы разговариваете с веб-разработчиком, а не с профессиональным программистом, лол!

Ниже приведен код - он должен вернуть XML из арсенала wow.

private void button7_Click(object sender, RoutedEventArgs e)
{
   // URL for armoury lookup
                string url = @"http://eu.wowarmory.com/guild-info.xml?r=Eonar&n=Gifted and Talented";

                // Create the web request
                HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);

                // Set the user agent so we are returned XML and not HTML
                //httpWebRequest.Headers["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)";

                // Not sure about this dispatcher thing - it's late so i have started to guess.
                Dispatcher.BeginInvoke(delegate()
                {
                    // Call asyncronously
                    IAsyncResult asyncResult = httpWebRequest.BeginGetResponse(ReqCallback, httpWebRequest);

                    // End the response and use the result
                    using (HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.EndGetResponse(asyncResult))
                    {
                        // Load an XML document from a stream
                        XDocument x = XDocument.Load(httpWebResponse.GetResponseStream());

                        // Basic function that will use LINQ to XML to get the list of characters.
                        ShowGuildies(x);
                    }
                });
            }

            private void ReqCallback(IAsyncResult asynchronousResult)
            {
                // Not sure what to do here - maybe update the interface?
            }

Очень надеюсь, что кто-нибудь сможет мне помочь!

Спасибо, мучо! Дэн.

PS Да, заметил иронию в названии гильдии :)


person Dan B    schedule 23.05.2010    source источник


Ответы (1)


Во-первых, Dispatcher.BeginInvoke требуется только тогда, когда вы находитесь в другом потоке, чем поток пользовательского интерфейса (где происходит все, что связано с silverlight / WPF). В событии щелчка вы уже находитесь в потоке пользовательского интерфейса, поэтому вызывать его не нужно.

Во-вторых, BeginGetResponse - это асинхронная операция, поэтому по завершении она вызовет функцию обратного вызова в другом потоке, здесь ReqCallback. Именно в этом методе вы можете вызвать EndGetResponse. Этот шаблон применим ко всем BeginX / EndX, которые вы найдете в фреймворке.

Однако, поскольку вы находитесь в другом потоке, вам нужно использовать BeginInvoke для отправки метода обратно в поток пользовательского интерфейса.

Код будет выглядеть так:

private void button7_Click(object sender, RoutedEventArgs e) {
    string url = @"http://eu.wowarmory.com/guild-info.xml?r=Eonar&n=Gifted and Talented";
    HttpWebRequest httpWebRequest = (HttpWebRequest) WebRequest.Create(url);
    httpWebRequest.BeginGetResponse(ReqCallback, httpWebRequest);
}

private void ReqCallback(IAsyncResult asyncResult)
{
    HttpWebRequest httpWebRequest = (HttpWebRequest) asyncResult.AsyncState;
    using (HttpWebResponse httpWebResponse = (HttpWebResponse) httpWebRequest.EndGetResponse(asyncResult))
    {
        XDocument x = XDocument.Load(httpWebResponse.GetResponseStream());
        Dispatcher.BeginInvoke((Action) (() => ShowGuildies(x)));
    }
}

Обратите внимание, что вы также можете обрабатывать XML в потоке и использовать диспетчер только для отправки обратно гильдий в пользовательский интерфейс, чтобы избежать зависания пользовательского интерфейса, если XML очень длинный для синтаксического анализа (не должно быть).

Изменить: исправил код. Вам нужно только реализовать ShowGuildies. Что касается подключения к Интернету и задержек, поскольку операция выполняется в другом потоке, пользовательский интерфейс не зависает. Вы можете подумать о том, чтобы показать анимацию загрузки или что-то в этом роде.

person Julien Lebosquain    schedule 23.05.2010
comment
К сожалению, этот код не компилируется. Можете выложить рабочий образец? Я изо всех сил пытаюсь заставить его работать, и больше кода, который не работает, еще больше меня напрягает :) 1. httpWebRequest не существует в ReqCallBack 2. Часть (Action) () = ›ShowGuildies (x) мне очень нравится ваша помощь и последний бит звучат интересно - хотя на синтаксический анализ не должно быть много времени, мне также приходится справляться с задержкой во времени и подключением к Интернету. Ваше здоровье! - person Dan B; 24.05.2010
comment
Кроме того, я видел много примеров, которые я пробовал, но они просто не работают. Для такого простого примера, используя ссылку выше - было бы здорово увидеть, как эксперт заставит это работать - все выходные - теперь я злюсь :) - person Dan B; 24.05.2010
comment
Привет, Жюльен, Спасибо за обновленный код, я попробую и посмотрю, как далеко я продвинулся. Может быть, после сна у меня все станет понятнее. В любом случае, я дам вам знать, как это будет происходить. Я уже реализовал ShowGuildies для локальной версии файла xml, так что, надеюсь, все вышеперечисленное поможет! - person Dan B; 24.05.2010
comment
Думаю, мы почти закончили, но теперь у меня появляется ошибка безопасности (даже если я загружаю на рабочий сервер). Самая внутренняя ошибка просто говорит об ошибке безопасности. Не особо полезно! Есть файл междоменной политики, который может вызвать это, но не знаете, как это обойти !? в System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse (IAsyncResult asyncResult) в System.Net.Browser.BrowserHttpWebRequest. ‹› c__DisplayClass5. ‹EndGetResponse› b__4 (playOnline.BendClass5. ‹EndGetResponse› b__4 (playOnline.SendState). ›B__0 (объект sendState) - person Dan B; 25.05.2010
comment
РЕШЕНО - использовал службу WCF для работы в качестве прокси из-за междоменной безопасности и ограничений на изменение заголовка. Спасибо за все советы. - person Dan B; 27.05.2010