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);
});
}
}
}
http://*:12345
and http://localhost:12345
and http://0.0.0.0:12345
Emmit
library is just syntactic sugar and makes direct pass through to SignalR
(I have tried same exact with SignalR directly.EnableJSONP
http://localhost:12345/signalr/hubs
and it shows proxy file.12345
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:
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:
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:
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With