问题描述:

I have setup a console application that just runs a loop and emits a message using Signal R. The client that is listening is an angular application.

When I run locally, (Both the Console application and the Angular Site) it works fine. However, when I run my console application in my Vagrant VM (Ubuntu HOST), then I get an all too familiar error message such as the following:

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)

I have ran into issues similar to this before (maybe this exact one) so here are some initial details

The code I have looks like the following:

 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. There are no exception or error logs being thrown on the server.
  2. I have enabled CORS in SignalR
  3. I have tried to use both http://*:12345 and http://localhost:12345 and http://0.0.0.0:12345
  4. The Emmit library is just syntactic sugar and makes direct pass through to SignalR (I have tried same exact with SignalR directly.
  5. I have tried different combinations of enabling/disabling EnableJSONP
  6. I know SignalR is working and accessible through the VM because I can hit http://localhost:12345/signalr/hubs and it shows proxy file.
  7. I have setup port fowarding to the Vagrant VM for port 12345
  8. I have disabled firewall on VM HOST (Ubuntu) with sudo ufw disable

The code for the client looks like the following:

 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;

});

UPDATE

I enabled logging and here is the output. Before another person recommends I enable CORS, I don't think that CORS is the issue, I think its just the cascading impact of something else that is having an issue.

UPDATE

I have ran this in multiple environments with the following results:

  1. Ran in Docker container on Vagrant VM (Ubuntu) - ERROR OCCURS
  2. Ran directly on Vagrant VM (Ubuntu) - ERROR OCCURS
  3. Deployed in Docker Container to Tutum - ERROR OCCURS
  4. Ran directly through Visual Studio on Windows - EVERYTHING WORKS
  5. Ran directly on Mac oSX (on Mono obviously) - EVERYTHING WORKS

I have added the following 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);

}

}

And when I check my logs, the only logs that are printed out are the following:

 BuildConnect

BuildAuthorizeConnect

UPDATE

I am not sure if this will be relevant or how I may have missed it, but I checked the response from the 500 and have posted it to Here

It looks like it is showing it is related to Improperly protected user's key pairs in '/root/.config/.mono/keypairs'.

Also, I am not sure if this link contains sensitive information. If somebody can let me know if it does, I would appreciate it.

I did a minimal amount of research thus far and came across SignalR.Owin works under Windows but returns 500 for Mono on Linux

When I check the Network tab for the negotiate request, I get the following

** Headers**

Remote Address:127.0.0.1:12345

Request URL:http://localhost:12345/signalr/negotiate?clientProtocol=1.5&userId=12345&connectionData=%5B%7B%22name%22%3A%22testemitter%22%7D%5D&_=1446964166640

Request Method:GET

Status Code: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

网友答案:

Although your app contains app.UseCors(CorsOptions.AllowAll), the original error message is pretty clear that this is a CORS issue.

The Origin URL (http://localhost:8100) is different than the SignalR server URL (http://localhost:12345) With CORS, the scheme, domain, and port have to match; in this case, the port is different.

Here's what to do:

  1. Ensure the URLs are actually correct and are what you expect. (Port 8100)
  2. Capture the HTTP traffic on the client. You can do this using Fiddler or a similar tool. You can also just use the "network" tab of the chrome debugger.
  3. Verify that the initial page load actually contains the CORS header. You should see Access-Control-Allow-Origin: in the response header. Based on how you've configured it, the value should be: *

...I believe the issue here is that you've enabled CORS on the SignalR server (Port 12345), but CORS needs to be enabled on your webserver. (Port 8100)

EDIT

The original question was edited. With the addition of the HTTP headers, the error message has changed from a CORS issue to a 500 error.

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]

I did a minimal amount of research thus far and came across SignalR.Owin works under Windows but returns 500 for Mono on Linux

The GitHub Issue that you linked to exactly matches what you've described. Since it's marked closed, the obvious question is to see if what's described in the ticket also applies to you. From the ticket:

davidfowl commented on May 22, 2013 - I just fixed the build in the dev branch yesterday. It requires mono 3.0.10 to run and works fine now.

So, verify two things:

  1. The version of Mono installed on your server. The Ticket says Mono 3.0.10 is needed. What version do you have?
  2. SignalR needs to include the changes. It's one or both of these. Ensure that whatever version of SignalR you're using includes these changes:
    • Change 1
    • Change 2

Lastly, if you need to, you do have the option of injecting your own version of SignalR.Core/Infrastructure/DefaultProtectedData.cs. You can simply set it in the OWIN pipeline. From the SignalR Source Code:

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

See the selected answer for insight into the problem and potential solution.

I solved the problem by making sure I had a version of Mono 3.0.10 or later. I am using Docker, so this was as easy as updating my FROM statement in my Dockerfile.

相关阅读:
Top