2015-06-18 4 views
2

Я работаю над проектом, который использует API RTC и формирует аутентификацию. Я наткнулся на немного странное поведение, и я просто не могу понять этого.HttpWebRequest .GetResponse throws WebException «Операция завершена»

Сценарий, который сыграл на сегодняшний день, заключается в том, что я могу успешно запустить этот проект локально до конца. То есть, этот конкретный кусок кода может:

  1. Связаться с удаленным сервером и успешно пройти проверку подлинности
  2. После аутентификации я могу передать XML, чтобы обновить билет в RTC

Проблема начинается когда я публикую на нашем сервере IIS (7.5). Все работает нормально вплоть до последнего вызова .GetResponse, который использует метод PUT для передачи моего XML для обновления билета в RTC. Я продолжаю получать «Операция истекло».

Я потратил буквально дни, пытаясь понять, что это делает всевозможные вещи, но ничего не оказалось полезным.

В качестве теста я изменил метод PUT во втором вызове GET. И это работает! Если я использовал PUT с .AllowAutoRedirect = false, он работает так, что я получаю ответ назад, но потом ничего не происходит на стороне RTC, поэтому запрос явно игнорируется. Я также заметил, что возвращаемый статус помечен как «Найдено» вместо «ОК».

Некоторые люди думали, что на этом этапе возможно отсутствие связи между удаленным сервером и веб-сервером. Это не так, если аутентификация работает, и это происходит с тем же сервером. Я также вручную передал вызов XML/PUT с использованием RESTClient на веб-сервере, который был принят отлично.

Я просто не могу понять, почему он работает от конца до конца при запуске локально, но разыгрывается после развертывания в IIS?

Я попытался использовать трассировку журнала, и я не совсем уверен, получаю ли я от него что-нибудь полезное. Это может быть совершенно не связаны, но я могу видеть это в журнале, который генерируется на сервере IIS:

<EventData> 
    <Data Name="ContextId">{00000000-0000-0000-12AF-0080000000F8}</Data> 
    <Data Name="ModuleName">ManagedPipelineHandler</Data> 
    <Data Name="Notification">128</Data> 
    <Data Name="HttpStatus">500</Data> 
    <Data Name="HttpReason">Internal Server Error</Data> 
    <Data Name="HttpSubStatus">0</Data> 
    <Data Name="ErrorCode">0</Data> 
    <Data Name="ConfigExceptionInfo"></Data> 
</EventData> 

Как я уже говорил, я не уверен, если это даже связано с проблемой я имею, но вместо того, чтобы игнорировать его, я думал, что поделюсь.

код, который формирует вызов (извините стандарт кодирования, это работа, и получил грязный пробуя различные вещи, чтобы решить эту проблему)

//Setup webrequest 
       CookieContainer _cookies = new CookieContainer(); 
       HttpWebRequest request = (HttpWebRequest)WebRequest.Create(getPath); 
       var test44 = test4.ToString(); 

       request.CookieContainer = _cookies; 
       request.ContentType = "application/rdf+xml"; 
       request.Accept = "application/rdf+xml"; 
       request.Method = "PUT"; 
       request.AllowAutoRedirect = true; 
       request.AllowWriteStreamBuffering = true; 
       request.Timeout = 40000; 


       byte[] bytes = Encoding.ASCII.GetBytes(test44); 
       request.ContentLength = bytes.Length; 
       Stream dataStream = request.GetRequestStream(); 

       dataStream.Write(bytes, 0, bytes.Length); 
       dataStream.Close(); 



       //Pass request 
       logger.Info("Made it up to start of RTC request for secure document."); 
       using (HttpWebResponse getrespn = requestSecureDocument(request, "https://myserver:9100/jazz", "username", "pass", test44)) 
       { 

        //Stream ReceiveStream = getrespn.GetResponseStream(); 
        // Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); 
        //StreamReader readStream = new StreamReader(ReceiveStream); 
        //response = readStream.ReadToEnd(); 


        getrespn.Close(); 
       } 

Сегмент кода, который взаимодействует с сервером RTC (на основе, например, из: https://nkumar83.wordpress.com/2013/06/13/consuming-rtc-rational-team-concert-oslc-apis-using-c-post-1-authentication/ со своими собственными ухищрений):

public static HttpWebResponse requestSecureDocument(HttpWebRequest _requestItem, string _rtcServerURL, string _userName, string _password, string passXml) 
    { 
     try 
     { 
      //FormBasedAuth Step 1: Request the resource 
      HttpWebRequest _request = (HttpWebRequest)WebRequest.Create(_requestItem.RequestUri); 
      _request.CookieContainer = _requestItem.CookieContainer; 

      //store the response in _docResponse variable 
      HttpWebResponse _docResponse = (HttpWebResponse)_request.GetResponse(); 

      //HttpStatusCode.OK indicates that the request succeeded 
      if (_docResponse.StatusCode == HttpStatusCode.OK) 
      { 
       //X-com-ibm-team... header signifies form based authentication is being used 
       string _rtcAuthHeader = _docResponse.Headers["X-com-ibm-team-repository-web-auth-msg"]; 
       if ((_rtcAuthHeader != null) && _rtcAuthHeader.Equals("authrequired")) 
       { 
        _docResponse.GetResponseStream().Flush(); 
        _docResponse.Close(); 

        //Prepare form for authentication 

        HttpWebRequest _formPost = (HttpWebRequest)WebRequest.Create(_rtcServerURL + "/j_security_check"); 


        _formPost.Method = "POST"; 
        _formPost.Timeout = 30000; 
        _formPost.CookieContainer = _request.CookieContainer; 
        _formPost.Accept = "text/xml"; 
        _formPost.ContentType = "application/x-www-form-urlencoded"; 



        string _authString = "j_username=" + _userName + "&j_password=" + _password; 
        Byte[] _outBuffer = Encoding.UTF8.GetBytes(_authString); 
        _formPost.ContentLength = _outBuffer.Length; 
        Stream _str = _formPost.GetRequestStream(); 
        _str.Write(_outBuffer, 0, _outBuffer.Length); 
        _str.Close(); 


        //FormBasedAuth Step 2: Submit the login form and get response 

        HttpWebResponse _formResponse = (HttpWebResponse)_formPost.GetResponse(); 

        _rtcAuthHeader = _formResponse.Headers["X-com.ibm-team.repository-web-auth-msg"]; 

        //Check if auth failed 
        if ((_rtcAuthHeader != null) && _rtcAuthHeader.Equals("authfailed")) 
        { 
         //auth fialed 
         var fail = ""; 
        } 
        else 
        { 
         //login successful 

         //FormBasedAuth Step 3: Resend the request for the protected resource 
         _formResponse.GetResponseStream().Flush(); 
         _formResponse.Close(); 

         using (HttpWebResponse getresp = (HttpWebResponse)_requestItem.GetResponse()) *** THIS IS TH LINE WHICH THROWS THE EXCEPTION *** 
         { 
          return getresp; 
         } 
        } 
       } 
      } 
      return _docResponse; 

     } 
     catch (WebException e) 
     { 
      var filePath = AppDomain.CurrentDomain.GetData("DataDirectory") + @"/trapA.xml"; 
        using (StreamWriter writer = new StreamWriter(filePath, true)) 
        { 
         writer.WriteLine("Message: Failed to trigger getresponse successfully: " + e); 
        } 

     } 
     return null; 
    } 

Надежда кто-то может помочь: о)

+0

Обновление только с дополнительной информацией. Я пытался получить более подробную информацию о веб-эксклюзии, то есть код состояния и описание состояния, но, как представляется, они недоступны, поскольку при попытке доступа к этим свойствам генерируется нулевая ссылка. HRESULT возвращается -2146233079. – Sulphy

+0

Ну, я подумал, что я попробую использовать метод WebClient, чтобы он работал локально, и невероятно, что я получаю то же самое, что и при публикации на веб-сервере. Мне интересно, есть ли что-то с самим сервером, поэтому попробуем установить последний и самый большой установщик .net (v4.5.2), посмотрим, что это делает. – Sulphy

+0

Увы, без радости: o ( – Sulphy

ответ

1

Ну, я рад сказать, что я, наконец, дошел до сути этого. Оказывается, проблема не имеет ничего общего с IIS и действительно работает, когда публикуется «если» я не использую клиент RTC для обновления билетов.

Краткая история заключается в том, что наш клиент RTC использует собственный скрипт для публикации на нашем веб-сайте api. Однако клиент RTC, похоже, блокирует запись в билете, который пытается обновить, который сохраняется до тех пор, пока не будет предоставлен ответ от нашего API.Конечно, этого не может быть, потому что часть ответа заключается в подтверждении успешного обновления, которое не может произойти из-за блокировки, сделанной клиентом RTC.

Решение заключалось в том, чтобы как можно быстрее получить звонок из RTC. Таким образом, сегмент кода, который аутентифицирует и обращается к RTC для создания обновлений, теперь обернут некоторым новым кодом для создания нового потока. Это позволило закрыть соединение примерно через 5 секунд, и все время наше приложение продолжает делать необходимые звонки для завершения транзакции.

Thread t = new Thread(() = > { 
//code here 

} 
+0

Хорошая обратная связь. +1 – VonC