2015-11-03 38 views
6

Mam skonfigurować aplikację konsoli, która po prostu uruchamia pętlę i emituje komunikat za pomocą Signal R. Klient, który nasłuchuje, jest aplikacją kątową.Błąd SignalR podczas żądania Negotation podczas testowania Vagrant VM

Po uruchomieniu lokalnie, (zarówno aplikacja konsoli, jak i strona kątowa) działa dobrze. Jednak gdy uruchamiam moją aplikację konsoli w moim Vagrant VM (Host Ubuntu), a następnie pojawia się nazbyt znajomy komunikat o błędzie, takie jak:

GET http://localhost:12345/signalr/negotiate?clientProtocol=1.5&userId=12345&connectionData=%5B%7B%22 
name%22%3A%22testem 
itter%22%7D%5D&_=1446565284280 500 (Internal Server Error) 

mam wpadł problemów podobnych do tego wcześniej (może to dokładna jeden) więc tutaj są pewne wstępne dane

Kod mam wygląda następująco:

namespace test 
    { 
     public class Program 
     { 
      public static void Main(string[] args) 
      { 
       try 
       { 
        using (WebApp.Start<EmmitStartup>("http://*:12345")) 
        { 
         Console.Out.WriteLine("Emmit started on http://*:12345"); 

         IEmitterFactory factory = new EmitterFactory(); 
         while (true) 
         { 
          Thread.Sleep(5000); 
          ITestEmitter emitter = factory.Create((ctx) => 
           { 
            return new TestEmitter(ctx); 
           }); 
          emitter.SayHello(); 
          emitter.Echo("Hello World:" + DateTime.Now); 
         } 
        } 
       } 
       catch (Exception e) 
       { 
        Console.Out.WriteLine(e.Message); 
        Console.Out.WriteLine(e.StackTrace); 
        Console.ReadLine(); 
       } 
      } 
     } 

     public class TestEmitter:Emitter,ITestEmitter 
     { 
      public TestEmitter(IEmitterContext emitterContext) : base(emitterContext) 
      { 
      } 

      public TestEmitter(IEmitterContext emitterContext, EmitterModel model) : base(emitterContext, model) 
      { 
      } 

      public TestEmitter(IDictionary<string, object> model) : base(model) 
      { 
      } 

      public void SayHello() 
      { 
       EmitterContext.Clients.All.onSayHello(); 
      } 

      public void Echo(string message) 
      { 
       EmitterContext.Clients.All.onEcho(message); 
      } 
     } 

     public interface ITestEmitter 
     { 
      void SayHello(); 
      void Echo(string message); 
     } 
     public class EmmitStartup 
     { 
      public void Configuration(IAppBuilder app) 
      { 

       app.UseCors(CorsOptions.AllowAll); 
       app.Map("/signalr", map => 
       { 
        map.UseCors(CorsOptions.AllowAll); 
        GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule()); 
        var config = new HubConfiguration() 
        { 
         EnableDetailedErrors = true, 
         EnableJavaScriptProxies = true, 
         EnableJSONP = true 
        }; 
        map.RunSignalR(config); 
       }); 
      } 
     } 
    } 
  1. Nie ma żadnych wyjątków lub dzienniki błędów wyrzucane na serwerze.
  2. mam włączone CORS w SignalR
  3. Próbowałem używać zarówno http://*:12345 i http://localhost:12345 i http://0.0.0.0:12345
  4. Biblioteka Emmit jest po prostu cukier syntaktyczny i sprawia, że ​​bezpośredni przechodzi do SignalR (próbowałem dokładnie taki sam z SignalR bezpośrednio.
  5. próbowałem różnych kombinacji włączanie/wyłączanie EnableJSONP
  6. wiem SignalR działa i dostępny przez VM bo mogę trafić http://localhost:12345/signalr/hubs i pokazuje plik proxy.
  7. mam ustawienia portu fowarding do Vagrant VM do portu 12345
  8. mam wyłączoną zaporę na VM hosta (Ubuntu) z sudo ufw disable

Kod dla klienta wygląda następująco:

var emmitProxy = null; 
    Emmit.createProxy({ 
     emitter:'testEmitter', 
     path:'http://localhost:12345/signalr', 
     listeners:{ 
      'onSayHello':function(){ 
       $log.info('onSayHello triggered') 
      }, 
      'onEcho':function(message){ 
       $log.info(message); 
      } 
     }, 
     onError:function(){ 
      //an error occured 
      $log.error('testEmitter:onError'); 
     }, 
     onDisconnected:function(){ 
      //proxy was disconnected 
      $log.debug('testEmitter:onDisconnected'); 
     }, 
     queryParams:{ 
      userId:'12345' //optional 
     } 
    }).then(function(newProxy){ 
     emmitProxy = newProxy; 
    }); 

AKTUALIZACJA

Włączyłem logowanie, a tutaj jest wynik. Zanim inna osoba poleci, że włączę CORS, nie sądzę, że CORS jest problemem, myślę, że to tylko kaskadowy wpływ czegoś innego, który ma problem.

enter image description here

UPDATE

I ran tym, w różnych środowiskach, o następujących właściwościach:

  1. Ran pojemnika dokowanym na Vagrant VM (Ubuntu) - błąd występuje
  2. Działa bezpośrednio na Vagrant VM (Ubuntu) - ERROR OCCURS
  3. Deploye d w Docker kontenera do Tutum - błąd występuje
  4. Ran bezpośrednio przez Visual Studio w systemie Windows - wszystko działa
  5. Ran bezpośrednio na Mac OSX (na Mono oczywiście) - wszystko działa

Dodałem następujące IHubPipelineModule

public class ErrorHandlingPipelineModule:HubPipelineModule 
{ 
    public override Func<HubDescriptor, IRequest, bool> BuildAuthorizeConnect (Func<HubDescriptor, IRequest, bool> authorizeConnect) 
    { 
      try 
      { 
       Console.Out.WriteLine ("BuildAuthorizeConnect"); 
       return base.BuildAuthorizeConnect (authorizeConnect); 
      } 
      catch (Exception exception) 
      { 
       Console.Out.WriteLine ("AuthorizeConnect Failure"); 
       Console.Out.WriteLine(exception.Message); 
      } 
      return base.BuildAuthorizeConnect(authorizeConnect); 
    } 

    protected override void OnAfterDisconnect (IHub hub, bool stopCalled) 
    { 
     try 
     { 
      Console.Out.WriteLine ("OnAfterDisconnect"); 
      base.OnAfterDisconnect (hub, stopCalled); 
      Console.Out.WriteLine ("After OnAfterDisconnect"); 
     } 
     catch (Exception exception) 
     { 
      Console.Out.WriteLine ("AfterDisconnect Failure"); 
      Console.Out.WriteLine(exception.Message); 
     } 
    } 

    protected override bool OnBeforeDisconnect (IHub hub, bool stopCalled) 
    { 
      try 
      { 
       Console.Out.WriteLine ("OnBeforeDisconnect"); 
       return base.OnBeforeDisconnect (hub, stopCalled); 
      } 
      catch (Exception exception) 
      { 
       Console.Out.WriteLine ("BeforeDisconnect Failure"); 
       Console.Out.WriteLine(exception.Message); 
      } 
      return base.OnBeforeDisconnect (hub, stopCalled); 
    } 


    public override Func<IHub, System.Threading.Tasks.Task> BuildConnect(Func<IHub, System.Threading.Tasks.Task> connect) 
    { 
      try 
      { 
       Console.Out.WriteLine("BuildConnect"); 
       return base.BuildConnect(connect); 
      } 
      catch (Exception exception) 
      { 
       Console.Out.WriteLine(exception.Message); 
      } 
      return base.BuildConnect(connect); 
    } 

    protected override void OnAfterConnect(IHub hub) 
    { 
     try 
     { 
      Console.Out.WriteLine("OnAfterConnect"); 
      base.OnAfterConnect(hub); 
     } 
     catch (Exception exception) 
     { 
      Console.Out.WriteLine ("OnAfterConnect Failure"); 
      Console.Out.WriteLine(exception.Message); 
     } 
    } 

    protected override bool OnBeforeConnect(IHub hub) 
    { 
     try 
     { 
      Console.Out.WriteLine("OnBeforeConnect"); 
      return base.OnBeforeConnect(hub); 
     } 
     catch (Exception exception) 
     { 
      Console.Out.WriteLine ("OnBeforeConnect Failure"); 
      Console.Out.WriteLine(exception.Message); 
     } 
     return base.OnBeforeConnect (hub); 
    } 
} 

I kiedy sprawdzasz logi, tylko kłody, które są drukowane są następujące:

BuildConnect 
BuildAuthorizeConnect 

UPDATE Nie jestem pewien, czy to będzie istotne i jak może mi brakowało, ale sprawdziłem odpowiedź od 500 i napisali je Here

Wygląda na to, że pokazuje to powiązane z Improperly protected user's key pairs in '/root/.config/.mono/keypairs'.

Ponadto, nie jestem pewien, czy ten link zawiera poufne informacje. Jeśli ktoś może dać mi znać, jeśli to zrobi, byłbym wdzięczny.

Zrobiłem minimalną ilość badań do tej pory i natknąłem SignalR.Owin works under Windows but returns 500 for Mono on Linux

Kiedy sprawdzić zakładkę Network na żądanie negocjacji, mam następujące

nagłówków ** ** Remote Address: 127,0 .0.1: 12345 Zapytanie URL: http://localhost:12345/signalr/negotiate?clientProtocol=1.5&userId=12345&connectionData=%5B%7B%22name%22%3A%22testemitter%22%7D%5D&_=1446964166640 Zapytanie Metoda: Pobierz kod status: 500 Internal Server Error

HTTP/1.1 500 Internal Server Error 
    Access-Control-Allow-Origin: http://localhost:8100 
    Access-Control-Allow-Credentials: true 
    X-Content-Type-Options: nosniff 
    Content-Type: text/html 
    Server: Mono-HTTPAPI/1.0 
    Date: Sun, 08 Nov 2015 06:30:28 GMT 
    Connection: close 
    Transfer-Encoding: chunked 

    Accept:text/plain, */*; q=0.01 
    Accept-Encoding:gzip, deflate, sdch 
    Accept-Language:en-US,en;q=0.8 
    Cache-Control:no-cache 
    Connection:keep-alive 
    Content-Type:application/x-www-form-urlencoded; charset=UTF-8 
    Cookie:JSESSIONID.ae4b31f4=aqpz31hevinaauwftyijure; JSESSIONID.26c95422=1m32u58exuvjz5jrojszqziqh; JSESSIONID.3fd19426=iv9fawaej3nt14yzcruj45si5; JSESSIONID.8868ba42=1gh4w06alx8ehuuj1adr5w8y8; JSESSIONID.947cfb91=nyxfrp6u0pny1sl8gwlouprh4; screenResolution=1280x800 
    Host:localhost:12345 
    Origin:http://localhost:8100 
    Pragma:no-cache 
    Referer:http://localhost:8100/ 
    User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36 

Odpowiedz

3

Mimo że Twoja aplikacja zawiera app.UseCors(CorsOptions.AllowAll), oryginalny komunikat o błędzie jest całkiem jasny, że jest to problem CORS.

Original Error message

Pochodzenie URL (http://localhost:8100) jest inny niż adres URL serwera SignalR (http://localhost:12345) Z CORS, schemat, domenę i port trzeba dopasować; w tym przypadku port jest inny.

Oto co należy zrobić:

  1. Upewnić się, że adresy URL są rzeczywiście prawdziwe i są tym, co można się spodziewać.(Port 8100)
  2. Uchwyć ruch HTTP na kliencie. Możesz to zrobić za pomocą Skrzypka lub podobnego narzędzia. Możesz także po prostu użyć karty "sieci" w debugerze chrome.
  3. Sprawdź, czy początkowe ładowanie strony zawiera nagłówek CORS. Powinieneś zobaczyć Access-Control-Allow-Origin: w nagłówku odpowiedzi. W oparciu o jak skonfigurowaniu go, wartość powinna wynosić: *

... Uważam, że problemem jest to, że masz włączony CORS na serwerze SignalR (port 12345), ale CORS musi być włączone na twoim serwerze internetowym. (Port 8100)

EDIT

Oryginalny pytanie był edytowany. Po dodaniu nagłówków HTTP komunikat o błędzie zmienił się z błędu CORS na błąd 500.

CryptographicException: Improperly protected user's key pairs in '/root/.config/.mono/keypairs'. 
... 
CryptographicException: Data protection failed. 
System.Security.Cryptography.ProtectedData.Protect (System.Byte[] userData, System.Byte[] optionalEntropy, DataProtectionScope scope) [0x00000] 
Microsoft.AspNet.SignalR.Infrastructure.DefaultProtectedData.Protect (System.String data, System.String purpose) [0x00000] 

Zrobiłem minimalną ilość badań do tej pory i natrafiliśmy SignalR.Owin works under Windows but returns 500 for Mono on Linux

GitHub Issue że związana ściśle pasuje do tego, co opisałeś. Ponieważ jest on oznaczony jako zamknięty, oczywistym pytaniem jest sprawdzenie, czy to, co opisano w bilecie, dotyczy również ciebie. Z biletu:

davidfowl skomentował w dniu 22 maja 2013 r - Właśnie ustalił budować w branży dev wczoraj. Do uruchomienia działa teraz w wersji 3.0.10 i działa dobrze.

więc sprawdzić dwie rzeczy:

  1. Wersja Mono zainstalowane na serwerze. Bilet mówi, że Mono 3.0.10 jest potrzebny. Jaką masz wersję?
  2. SignalR musi uwzględniać zmiany. To jedna lub obie z nich. Upewnić się, że niezależnie od wersji SignalR używasz zawiera następujące zmiany:

Wreszcie, jeśli chcesz, masz możliwość wstrzykiwania własną wersję z SignalR.Core/Infrastructure/DefaultProtectedData.cs. Możesz po prostu set it in the OWIN pipeline. Z SignalR Source Code:

  // Use the data protection provider from app builder and fallback to the 
      // Dpapi provider 
      IDataProtectionProvider provider = builder.GetDataProtectionProvider(); 
      IProtectedData protectedData; 
+0

Gdyby to był CORS, czy w ogóle by nie zadziałało?Jak już wspomniałem, działa lokalnie idealnie dobrze i pochodzi z różnych portów. – TheJediCowboy

+0

Czy zweryfikowałeś nagłówki HTTP? –

+0

Naprawdę właśnie go teraz wyciągam. Byłem zapakowany w inne rzeczy. – TheJediCowboy

0

Zobacz wybraną odpowiedź na wgląd problemu i potencjalnego rozwiązania.

Rozwiązałem problem, upewniając się, że mam wersję Mono 3.0.10 lub nowszą. Używam Docker, więc było to tak proste, jak zaktualizowanie mojego oświadczenia FROM w moim pliku Dockerfile.