Почему один и тот же точный код вылетает в одном приложении и работает в другом?
Я пытаюсь вызвать метод Rest API Web в приложении из клиентского приложения. У меня есть два клиентских приложения - с одним оно работает, с другим - нет.
Код для вызова метода REST идентичен. Это точно такой же точный код сервера, конечно.
В сбойном клиентском приложении оно терпит неудачу в этой строке:
var webResponse = (HttpWebResponse)webRequest.GetResponse();
... и код в обоих приложениях абсолютно одинаков до момента отказа, за исключением того, что отказавший находится в обработчике событий, а рабочий - нет. Ну, еще одно (связанное) отличие, кроме того, что тестовый код находится в обработчике событий, а "реальный" код находится в отдельном методе, заключается в том, что отдельный метод также находится в отдельном классе. Почему это будет иметь значение, я не знаю, но я вроде как хватаюсь за соломинку здесь. Вот:
Cursor.Current = Cursors.WaitCursor;
try
{
// Cannot start with String.Empty or " "; they both fail for some reason - Controller method is not even called.
string lastIDFetched = "0";
const int RECORDS_TO_FETCH = 100;
bool moreRecordsExist = true;
try
{
while (moreRecordsExist)
{
string formatargready_uri = string.Format("http://localhost:28642/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest)WebRequest.Create(formatargready_uri);
// GET is the default method/verb, but it's here for clarity
webRequest.Method = "GET";
var webResponse = (HttpWebResponse)webRequest.GetResponse();// <-- this throws an exception when there is no longer any data left
Определение неверного метода:
private void buttonGetInvItemsInBlocks_Click(object sender, EventArgs e)
Определение метода работы:
public static List<HHSUtils.InventoryItem> GetBatchOfInventoryItems()
На той, которая не работает, F10 в последней строке идет прямо к блоку исключений (goto считается вредным - без шуток!), Но исключение мне ничего не показывает - зависание над этой строкой:
catch (Exception ex)
... я вижу только " Exception | System.Exception base {object} | object "
Оба клиента встроены в Visual Studio 2008 и предназначены для.NET 3.5; сервер VS 2013, .NET 4.5.1
Вот подсказка, я полагаю: в сбойном коде целевое устройство установлено на "Устройство Windows CE" (оно развертывается на портативное устройство, которым я управляю через "Удаленное управление дисплеем для Windows CE")
Кто-нибудь здесь связывается с их внутренним Коломбо?
ОБНОВИТЬ
Я изменил код из этого:
var webResponse = (HttpWebResponse)webRequest.GetResponse();
...к этому:
using (var webResponse = (HttpWebResponse)webRequest.GetResponse())
... и это не имеет значения - он все равно переходит прямо из этой строки в блок catch без полезных данных в отображаемом исключении.
В моем тестовом приложении я изменил код, чтобы использовать "более лучший" способ (с помощью); это работает в любом случае, тогда как другое приложение не работает ни в коем случае. IOW: использование use - это хорошо, но в этом случае нет никакой разницы.
ОБНОВЛЕНИЕ 2
В ответ на ответ JayC я попробовал все следующие "строки подключения" - все с одинаковым результатом:
string uri = string.Format("http://localhost:28642/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); // Fails on "using" line below with no usable exception data
//string uri = string.Format("http://192.112.263.38:28642/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); <-- same failure
//string uri = string.Format("http://192.112.263.38/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); <-- same failure
//string uri = string.Format("http://192.112.263.38:80/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); <-- same failure
//string uri = string.Format("http://192.112.263.38:777/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); <-- same failure
//string uri = string.Format("http://192.112.263.38:28642/api/inventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); <-- same failure
//string uri = string.Format("http://192.112.263.38/api/inventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); <-- same failure
//string uri = string.Format("http://192.112.263.38:80/api/inventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); <-- same failure
//string uri = string.Format("http://192.112.263.38:777/api/inventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH); <-- same failure
ОБНОВЛЕНИЕ 3
В ответ на комментарий Романа Грубера о CAS: в Википедии есть страница для устранения неоднозначности для CAS ( http://en.wikipedia.org/wiki/Cas_(disambiguation)), но ни одна из предложенных возможностей не представляется разумной для этого контекста.
Основная статья, OTOH, содержит несколько аббревиатур CAS в разделе Computing. На что вы ссылаетесь:
Central Authentication Service, a single sign-on protocol
Channel Associated Signaling, a type of communication signaling
Code Access Security in the Microsoft .NET framework
?
ОБНОВЛЕНИЕ 4
Хорошо, я добавил код, предложенный парой кошек:
catch (WebException webex)
{
HttpWebResponse hwr = (HttpWebResponse) webex.Response;
HttpStatusCode hsc = hwr.StatusCode;
MessageBox.Show(string.Format("{0} Status code == {1}", webex.Message, hsc.ToString()));
}
... и вот что я вижу, когда точка останова достигает улова:
И вот сообщение об ошибке показано:
"Удаленный сервер возвратил ошибку: (400) Bad Request. Код состояния == Bad Request"
Я думаю, что проблема в "строке подключения"; как видно из обновления 2, я перепробовал все, что только мог придумать, и ничего не работает, чтобы подключить устройство к рабочему столу.
5 ответов
Неудачное приложение развертывается на переносном устройстве, и все же URI установлен на localhost??
Возможно, вы захотите использовать имя хоста, которое соответствует фактическому компьютеру, на котором размещена служба.
Редактировать: я ничего не знаю об устройствах Windows CE, но кажется, что должны быть более простые способы получения более явной информации об исключениях от устройства, которое развернуто на устройстве. Я подозреваю, что это ваша главная проблема, которую нужно решить, если случится так, что ваша непосредственная проблема будет решена с помощью того, что я упомянул выше. Я надеюсь, что это что-то тривиальное, как debug="True"
это можно было бы установить в файле app.config, но мне пришлось бы это исследовать.
Вы пытались запустить приложение на устройстве CE без отладчика? Просто любопытно, происходит ли сбой только в среде отладки или нет.
Также Роман Грубер задал хороший вопрос, а я не увидел ответа:
Вы можете видеть устройство с вашего компьютера, но может ли устройство видеть сеть? Откройте веб-браузер на устройстве и попробуйте получить доступ к любой странице в сети, чтобы проверить...
Просто длинный выстрел: есть ли разница в потоках между обоими приложениями? Если я правильно понимаю, сбойное приложение вызывает сетевой код из основного потока (из обработчика событий кнопки). Android может вызвать сбой вашего приложения, если вы сделаете это (чтобы основной поток не блокировался). Но я не знаю, имеет ли Windows CE подобную систему...
Я попробую это как ответ, чтобы уточнить мои заметки по вопросам:
1.: CAS = Code Access Security - извините, я предположил, что аббревиатура достаточно распространена в среде.NET.
2.: Аутентифицировать запрос на сервере:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Credentials = new NetworkCredential("username", "password");
Но: я просто понял кое-что еще... предыдущие ответы и / или вопросы немного вводят меня в заблуждение, и полоса прокрутки в вашем примере кода тоже не помогла. Это метод "WebRequest.Create", который вызывает исключение?? Это еще не доступ к любой сети вообще. Это не может быть ни имя хоста / IP-адрес, ни какие-либо учетные данные, связанные в этом случае. Это все еще может быть связано с CAS. Но, скорее всего, это неправильный URI...
Попробуйте добавить
MessageBox.Show(formatargready_uri);
перед вызовом WebRequest. Создайте и посмотрите URL-адрес вашего приложения на устройстве. URI-разбор тоже может быть "легковесным". Далее, я бы порекомендовал также использовать окно сообщения внутри блока catch:
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
3.: Подключение к рекламной сети: все, что вы указываете, это то, что вы можете видеть устройство с вашего ПК, но может ли устройство видеть сеть? Откройте веб-браузер на устройстве и попробуйте получить доступ к любой странице в сети, чтобы проверить...
Мне пришлось добавить это в C: \ Users \ clay \ Documents \ IISExpress \ config \ applicationhost.config:
<binding protocol="http" bindingInformation="*:28642:shannon2" />
... и использовать эту "строку подключения" в моем коде:
http://shannon2:28642/api/InventoryItems
Теперь я могу подключиться; Я думаю, что я был очень близок (так близко, и все же так далеко) раньше, но это должна была быть именно такая комбинация, чтобы работать.