How to enable SignalR server side tracing on OWIN self host? - signalr

I keep getting intermittent No transport could be initialized successfully. error in my OWIN self hosted application with SignalR and I haven't been able to find a problem yet, all transport types just fail silently during initialization sometimes.
I'm trying to enable logging and tracing on server side, but can't find how I can do it.
I've seen this article http://www.asp.net/signalr/overview/testing-and-debugging/enabling-signalr-tracing
but I don't think I can do it with OWIN
How can I set up SignalR server side logging? I'm interested in iniitialization tracing - my client and server side method calls work fine.

This isn't ideal, but I'm at least getting some trace after installing Microsoft.Owin.Diagnostics nuget package and then:
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.Properties["host.AppMode"] = "development";
app.UseErrorPage(new Microsoft.Owin.Diagnostics.ErrorPageOptions { ShowExceptionDetails = true });
app.MapSignalR();
}
This returns HTML to the client with a stack trace and some other useful info. Hope it helps.

Related

SignalR not firing "disconnected" event

I'm using SignalR to push updates out to connected web clients. I listen to the disconnected event in order to know when I should start my reconnection logic
$.connection.hub.disconnected(function() {
// Initiate my own reconnection logic
});
The SignalR hub is hosted in in IIS (along with my site)
[assembly: OwinStartup(typeof(Startup))]
namespace MyNamespace.SignalR
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
Upon connection, the client calls a server method to join a group
public class MyHub : Hub
{
public void JoinGroup(string groupName)
{
Groups.Add(Context.ConnectionId, groupName);
}
}
And then I push messages to this group:
context.Clients.Group(groupName).sendMessage();
If I manually recycle the application pool in IIS, SignalR starts trying to reconnect and I eventually receive a disconnected event on the client side if it fails (after the timeout).
However, my problem is that if I manually restart the website in IIS, I do not receive any disconnected event at all, and I can't see in the logs that SignalR has detected any connection problem at all. How can I detect that I have been disconnected?
I know I should probably persist the group connections somehow, since that is saved in memory I guess. But that shouldn't affect the initial problem that the client receives no notification of the disconnection? Shouldn't the client side signalr code throw some kind of exception/event?
disconnected fires first when the built in logic for reconnection have timed out. You also need to listen to the recconect event, something like i did here
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/blob/ReconnectOnClosed/SignalR.EventAggregatorProxy.Client.JS/jquery.signalR.eventAggregator.js#L157
So I finally found out what the problem is and how to solve it. Some background though:
At the moment we manually release new versions of our application by going to "Basic settings..." under the website in IIS and changing the "Physical Path" from C:\websites\version1 to C:\websites\version2. Apparently this gives the same behavior as doing a restart of the website in IIS (not a hard reset, not stopping the website, not recycling the app pool) and according to this: "does NOT shut the site down, it merely removes the Http.sys binding for that port". And no matter how long we wait, the connected clients never receive any kind of indication that they should reconnect.
So the solution is to recycle the application pool after each release. The "lost" clients will receive disconnected events and reconnect to the new version of the site.

SignalR Connect Returns 504

I have a weird behavior going on with SignalR, I have a hub defined like so:
public class NotificationHub : Hub
{
//Empty
}
on my js I have the following:
function blabla {
// bla bla
$.connection.NotificationHub.client.AppendNewStory = function (story) {
// appends a new story, long jquery code
};
$.connection.hub.start().done(function () {
_ConnectionStarted = true; // there must be some built in way
});
}
I call js from a class on my mvc project
public SomeClass
{
private IHubContext _context;
public SomeClass()
{
_context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
}
public void Notify(SomeData ...)
{
_context.Clients.User(userId).AppendNewStory(data);
}
}
Problem has two symptoms:
Server to client class fail intermittently (can't figure out a scenario).
My web server seems to get VERY SLOW, subsequent ajax calls and regular webrequests timeout.
Using fiddler I found the following:
SignalR/hubs call succeeds.
SignalR negotial call succeeds.
connect with WebSockets transport failed with HTTP 504!
subsequent connect calls try foreverFrame and long polling, both succeed with 200.
a poll request is issued and NEVER RETURNS! after that everything becomes slow or hangs.
Something that might aid the debugging, server hangs if i'm opening 2 tabs or more. a single tab seems ok.
I'm also using IE 11 and chrome, same problem except chrome tries serverSentEvents instead of foreverFrame.
Any ideas on how to debug this issue, see why I get 504? or why the server hangs? I have Windows 8.1 Update 1, IIS 8, SignalR 2.0, .NET 4.5.1.
Did you install WebSockets in Windows 8.1? Do this under add/remove features. I had similar random issues connecting until I did this. I also had to enable the following setting in the web.config:
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
Is there anything in between your server and browser. Some proxies have trouble with web sockets and server sent events. Try choosing the transports in the javascript. I saw similar things with Firefox over OpenIG. OpenIG didn't like server sent events and just hung.
One possibility that you'll want to investigate is whether you're running into a limit on the number of connections allowed to IIS. I'm not sure whether websocket connections are included in that limit, but normal connections - and a long polling connection will consume one of those - are typically limited to "3" on a the "Basic" version of Windows 8 (and are limited to 10 on the Professional and other versions). I'm guessing that your long polling connection(s) are consuming all the available connections, and that's what is causing everything else to time out.
See here for more details:
http://www.jpelectron.com/sample/WWW%20and%20HTML/IIS-%20OS%20Version%20Limits.htm
I'd either upgrade to Professional (if you're already at "Professional", then discount this answer), or install Websockets and see if that helps things.
Ok thanx to everyone who answered, you all helped debug the issue, unfortunately nothing worked.
problem turned out I needed to set the targetFramework attribute in web.config:
<httpRuntime targetFramework="4.5.1">
Everything worked smoothly afterwards.

How do I see Exception details in SignalR when self hosted with OWIN

I am currently receiving a 500 error message when trying to connect my .NET WPF application to a server running SignalR that is self hosted with OWIN. I have tried setting the EnableDetailedErrors to true in the hub configuration. I have also tried OnIncomingError in the HubPipelineModule. Neither have worked. Any other ideas on how I can see the specific error?
You can use the IAppBuilder.UseErrorPage() extension method to see exception details instead of a blank 500 response. This method is available via the Microsoft.Owin.Diagnostics NuGet package.
Make sure you call UseErrorPage before calling MapSignalR or adding other middleware that may throw an exception.
More information on UseErrorPage can be found in the Add OWIN Diagnostics section of the following article: http://www.asp.net/aspnet/overview/owin-and-katana/getting-started-with-owin-and-katana

SignalR cross-domain without CORS

I'm trying to get a confirmation that yes, a client can send and receive messages to an ASP.NET site on another domain without requiring that the IIS server running the SignalR-enabled ASP.NET supports CORS.
Can someone provide me with an example I can look at where CORS is not used as the cross-domain mechanism?
We have IE 9 clients and want to have three sites on different domains push/pull to a single ASP.NET + SignalR server. Can this be done? How?
If cors is not available SignalR uses longPolling transport with jsonp.
Keep in mind jsonp is insecure by design AND can limit your data you send over the wire since all data is sent via the query string.
You should not have to provide any additional information on the client for SignalR to use jsonp, it should just work.
To ensure that cross domain communication works on the server you'll have to enable it:
Routes.RouteTable.MapHubs(new HubConfiguration { EnableCrossDomain = true });
To enable this when using SignalR 2.0 with the OWIN middleware instead of the regular ASP.NET pipeline, install the Microsoft.Owin.Cors package from NuGet, then do something like this:
[assembly: OwinStartupAttribute(typeof(OwinStartup))]
namespace Website.App_Start
{
public partial class OwinStartup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.RunSignalR(new HubConfiguration {EnableJSONP = true});
}
}
}
}
More details here: http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-javascript-client#crossdomain
Just to add, WebSockets (cross origin) will require CORS, so eventually (if you want to use web sockets) you will need to support this on the server.

authentication in singalR selfhost server- and web client in SSL

I have a singalR self host server that is hosting my singalR in a console application on https
I am using this packages to self host:
Install-Package Microsoft.Owin.Hosting -pre
Install-Package Microsoft.Owin.Host.HttpListener -pre
Install-Package Microsoft.AspNet.SignalR.Owin
i have a web client which is backed by WebApi, I can connect to my selfhosted singalR from my webclient and send messages however I would now like to add authentication to this, which means only logged in users can send messages to my selfhosted singalR server.
I used [Authorize] attribute before my method
[Authorize]
public void Test(string test)
{
Console.WriteLine(test);
}
I have my web client authentication done via forms authentication however after logging in sucessfully in my webclient, when i do call singalR method, i recieve javascript error
Uncaught Value cannot be null. Parameter name: user
It tells that my method is protected but somehow my user is not passed to my self hosted singalR server, What is missing here?
Support for this was introduced with SignalR 1.0, you can read a little about that on David Fowlers blog. The problem is, with it being so new it's a little sparsely documented.
I'm not exactly sure what's going on in your application at the moment but you can find a similar question already on Stack Overflow which might help you get on the right track: Integrating SignalR with existing Authorization
Basically, you can create a SignalR Attribute that implements IAuthorizeHubConnection and IAuthorizeHubMethodInvocation, then decorate your Hubs/Methods that you want authorized.
public class HubAuthorizeAttribute : Attribute, IAuthorizeHubConnection, IAuthorizeHubMethodInvocation {
public virtual bool AuthorizeHubConnection(HubDescriptor hubDescriptor, Microsoft.AspNet.SignalR.IRequest request) {
IAuthorizationProvider authorizationProvider = DependencyResolver.Current.GetService<IAuthorizationProvider>();
return authorizationProvider.IsAuthorizedController(hubDescriptor.Name);
}
public virtual bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext) {
IAuthorizationProvider authorizationProvider = DependencyResolver.Current.GetService<IAuthorizationProvider>();
return authorizationProvider.IsAuthorizedAction(hubIncomingInvokerContext.MethodDescriptor.Hub.Name, hubIncomingInvokerContext.MethodDescriptor.Name);
}
}
Alternatively, you could add the HubAuthorizeAttribute as a HubPipeline Module to Globally require Authorization.
var globalAuthorizer = new HubAuthorizeAttribute ();
GlobalHost.HubPipeline.AddModule(new AuthorizeModule(globalAuthorizer, globalAuthorizer));
I've asked a similar question a few times over the last days in the SignalR JabbR chat and haven't got any answer.
When I was about to post my question here I found your question and this other one. Unfortunately, from the answer given there a couple of weeks ago, it seems like SignalR itself provides no Authentication support, so that's a huge problem for many selfhosted applications (we were intending to use Integrated Windows Authentication with SignalR...)

Resources