针对Vagrant VM进行协商时,SignalR错误

时间:2015-11-03 16:00:06

标签: asp.net vagrant signalr owin signalr.client

我已经设置了一个控制台应用程序,它只运行一个循环并使用Signal R发出一条消息。正在监听的客户端是一个角度应用程序。

当我在本地运行时,(控制台应用程序和Angular站点)都可以正常运行。但是,当我在我的Vagrant VM(Ubuntu HOST)中运行我的控制台应用程序时,我得到一个非常熟悉的错误消息,如下所示:

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)

我之前遇到过类似的问题(可能是这个问题),所以这里有一些初步细节

我的代码如下所示:

  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. 服务器上没有抛出异常或错误日志。
  2. 我在SignalR中启用了CORS
  3. 我尝试同时使用http://*:12345http://localhost:12345以及http://0.0.0.0:12345
  4. Emmit库只是语法糖,直接传递给SignalR(我已经尝试过直接使用SignalR。
  5. 我尝试了启用/停用EnableJSONP
  6. 的不同组合
  7. 我知道SignalR正在工作并可通过VM访问,因为我可以点击http://localhost:12345/signalr/hubs并显示代理文件。
  8. 我已经为端口12345
  9. 的Vagrant VM设置了端口端口
  10. 我已使用sudo ufw disable
  11. 在VM HOST(Ubuntu)上禁用了防火墙

    客户端的代码如下所示:

        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;
      });
    

    更新

    我启用了日志记录,这是输出。在另一个人建议我启用CORS之前,我不认为CORS是问题,我认为这只是其他问题的层叠影响。

    enter image description here

    更新

    我在多个环境中运行了这个,结果如下:

    1. 在Vagrant VM(Ubuntu)上的Docker容器中运行 - 错误发生
    2. 直接跑到Vagrant VM(Ubuntu) - ERROR OCCURS
    3. 在Docker Container中部署到Tutum - ERROR OCCURS
    4. 直接通过Windows上的Visual Studio - 一切正常工作
    5. 直接在Mac oSX上播放(显然是在Mono上) - 一切正常工作
    6. 我添加了以下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);
          }
      }
      

      当我检查我的日志时,打印出的唯一日志如下:

       BuildConnect
       BuildAuthorizeConnect
      

      更新 我不确定这是否相关或我是如何错过的,但我检查了500的回复并将其发布到Here

      看起来它显示它与Improperly protected user's key pairs in '/root/.config/.mono/keypairs'.

      有关

      此外,我不确定此链接是否包含敏感信息。如果有人能告诉我它是否真的,我将不胜感激。

      到目前为止,我做了很少量的研究,遇到了SignalR.Owin works under Windows but returns 500 for Mono on Linux

      当我检查协商请求的网络选项卡时,我得到以下

      **标题**         远程地址:127.0.0.1:12345         请求网址:http://localhost:12345/signalr/negotiate?clientProtocol=1.5&userId=12345&connectionData=%5B%7B%22name%22%3A%22testemitter%22%7D%5D&_=1446964166640         请求方法:GET         状态代码:500内部服务器错误

          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
      

2 个答案:

答案 0 :(得分:3)

虽然您的应用包含app.UseCors(CorsOptions.AllowAll),但原始错误消息非常清楚,这是一个CORS问题。

  

Original Error message

Origin URL(http://localhost:8100)与SignalR服务器URL(http://localhost:12345)不同。使用CORS,方案,域和端口必须匹配;在这种情况下,端口是不同的。

以下是该做什么:

  1. 确保网址确实正确并且符合您的预期。 (港口8100)
  2. 捕获客户端上的HTTP流量。您可以使用Fiddler或类似工具执行此操作。您也可以使用chrome调试器的“网络”选项卡。
  3. 验证初始页面加载实际上是否包含CORS标头。您应该在响应标头中看到Access-Control-Allow-Origin:。根据您的配置方式,值应为:*
  4. ...我认为这里的问题是您已经在SignalR服务器(端口12345)上启用了CORS,但是需要在您的网络服务器上启用CORS。 (港口8100)

    修改

    原始问题已被编辑。添加HTTP标头后,错误消息已从CORS问题更改为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]
    
         

    到目前为止,我做了很少量的研究,遇到了SignalR.Owin works under Windows but returns 500 for Mono on Linux

    您链接的GitHub Issue与您描述的完全匹配。由于它被标记为已关闭,因此显而易见的问题是查看故障单中描述的内容是否也适用于您。从机票:

      

    davidfowl于2013年5月22日发表评论 -   我昨天刚刚在dev分支中修复了构建。它需要单声道3.0.10才能运行并且现在正常工作。

    所以,验证两件事:

    1. 服务器上安装的Mono版本。门票说需要Mono 3.0.10。你有什么版本?
    2. SignalR需要包含更改。这是其中一个或两个。确保您使用的SignalR版本包含以下更改:
    3. 最后,如果需要,您可以选择注入自己的 SignalR.Core / Infrastructure / DefaultProtectedData.cs 版本。你可以简单地set it in the OWIN pipeline。来自SignalR Source Code

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

答案 1 :(得分:0)

请参阅所选答案,以深入了解问题和潜在解决方案。

我通过确保我有Mono 3.0.10或更高版本的版本解决了这个问题。我正在使用Docker,所以这就像在我的Dockerfile中更新我的FROM语句一样简单。