Using ASP.NET readonly session with SignalR websockets - asp.net

I am trying to use a readonly ASP.NET session as shown by David Fowler in this gist: https://gist.github.com/davidfowl/4692934
But does this also apply when using WebSockets as the transport> I am running IIS (Express) 8.0.
What I see is that the hub method is called before the Application_BeginRequest method is called or Application_BeginRequest is not called at all. (I am using SignalR version 1.1.0)
Which Application events are called when a SignalR request is received?

Begin request should be called once during the websocket handshake and never called again after that. Hub invocations do not imply an http request is being made.

Related

Owin on IIS web requests hang indefinitely

We are running an Owin applications on IIS 8.5 on Win 2012 R2 behind a loadbalancer. One some occations, requests to certain URLs hang indefinitely. If the user selects cancel in the browser, and reloads the page, everything is OK and the server responds quickly.
In IIS manager, we can see the requests hanging:
The hang seems to occur inside the Owin pipeline. We are running .NET 4.5.2 and the latest Owin packages.
Here's the code for the /api/whoami endpoint:
[Authorize]
public class WhoAmIController : ApiController
{
[Route("whoami")]
[HttpGet]
public IHttpActionResult Whoami()
{
return Json(ClaimsPrincipal.Current.Identity.Name);
}
}
An observation is that requests to this endpoint hangs in the AuthenticateRequest stage in the IIS pipeline, not PreExecuteRequestHandler which is the default IIS stage for the OWIN pipeline. Our only authentication method is cookie authentication, which executes in the AuthenticateRequest stage.
Any ideas?
Edit: adjusted screenshot
The problem was that we had code executing on the IIS event PreSendRequestHeaders, which apperently is bad according to
http://www.asp.net/aspnet/overview/web-development-best-practices/what-not-to-do-in-aspnet,-and-what-to-do-instead#presend
Our intention was to adjust HTTP headers on the way out on all request. The fix was to move the code to the BeginRequest event.
Have you tried adding .ConfigureAwait(false) to your async calls?
Doing so will make the continuation continue on the "correct" thread.

SignalR Server to Client only

I setup SignalR in my application and it works very nice!
I have a Hub which is only supposed to push messages from the server to the client.
However, i can also call the method from the client back to the server, doing like this:
// this makes a call from the client to the server
$.connection.appplicationHub.server.productCreated();
Is there a way to prevent this?
This was a bad question.
To send messages from Server to Client, i don't need to create the method in the Hub class. Methods created in the Hub class are made for Client -> Server messages.

Getting HttpRequest from SignalR Hub

I have a web site with SignalR Hub (and jQuery code at the client for connecting).
I need to get the HttpRequest object for authentication.
The signalR have a Context.Request object(which is Microsoft.AspNet.SignalR.Owin.ServerRequest) but I can't find the way to convert it into an HttpRequest.
Does any one have an idea how to perform that?
Edit:
As it turns out, you can always go to HttpContext.Current and use the Request/Response object. But be careful, Not all reqular operations are supported, some of them will result in ThreadAborted Exception

Unable to set proxy for SignalR HubConnection

Using version 2.0 for Asp.NET SignalR, we have created a prototype application that has a WPF client application and a web site that has SignalR configured. This prototype works correctly when run on the local developer computer and when the web site was deployed to an internal development server.
An issue that has been encountered once the web site was deployed to an external server; the following exception is encountered when the HubConnection.Start method is called:
HttpClientException
A first chance exception of type 'Microsoft.AspNet.SignalR.Client.HttpClientException' occurred in mscorlib.dll
Additional information: StatusCode: 407, ReasonPhrase: 'Proxy Authentication Required ( Forefront TMG requires authorization to fulfill the request. Access to the Web Proxy filter is denied…
The network that the developer computer is on requires the use of a proxy to reach the Internet. The web site that has the SignalR component also has some WCF endpoints; these can be connected to using the HttpClient within the WPF client application when the proxy is set in code. The same approach to set the proxy was done on the HubConnection but the error is encountered.
Below is code on how the proxy is set to the HubConnection; the same credentials work when accessing the other, non-signalR, endpoints:
var proxyInfo = new WebProxy(new Uri(“theAddress”));
proxyInfo.Credentials = new NetworkCredential(“theUserName”, “thePassword”, “theDomain”);
hubConnection.Proxy = proxyInfo;
Is there something else that has to be set with the HubConnection for it to use the proxy?
Thanks,
Scott
The issue is that there is a bug with the 4.5 .NET Client for SignalR; the proxy information is not being sent with the requests in the HubConnection. This is a regression from the 1.0 release.
The link below contains the information:
https://github.com/SignalR/SignalR/issues/2856

Isolating specific browser instance with SignalR

We are building an app which will send messages to the browser using SignalR. The user may have multiple browser instances open and we would like each message to be sent to the appropriate browser. Our understanding is that the ClientId ConnectionId would allow us to do this. The issue we're running into is accessing the ClientId ConnectionId, or SessionId, at the appropriate times in the codebase. Here's our scenario:
A MVC Action executes and, as part of that processing, a call to a Biztalk endpoint is made. The Biztalk execution is out of process (from the point of view of the MVC Action) and doesn't return when completed. This is by design. To notify the MVC application that it has completed, Biztalk sends a message to the MVC application's SignalR hub by calling the /myapp/signalr endpoint. The message is received by SignalR and then should be routed to the appropriate browser instance.
Since the message to SignalR is being sent by Biztalk, and not the MVC application, the ClientId of the connection to SignalR is not the one that identifies the browser instance that should receive the message. So what we are attempting to implement is somethign similar to the Return Address pattern by including the ClientId ConnectionId of the browser instance that initiates the Biztalk call in the message to Biztalk. When Biztalk sends its message to SignalR one of the contents is that original ClientId ConnectionId value. When SignalR processes the message from Biztalk it then can use the ClientId ConnectionId included in the message to route that message to the appropriate browser instance. (Yes we know that this won't work if the browser has been closed and re-opened and we're fine with that.)
The problem we face is that when initially sending the message to Biztalk from our MVC Action we cannot access the ClientId ConnectionId as it's only available in the Hub's Context. This is understandable since the MVC Action doesn't know which Hub context to look for.
What we have tried in it's place is to pass the SessionId through the Biztalk message and return it to SignalR. This solves the problem of including the browser instance identifier in the Biztalk message and returning it to SignalR. What it introduces is the fact that when a client connects to the Hub we cannot access the Session (and thus the SessionId) in the Hub's OnConnect method.
David Fowler posted a gist that reportedly shows how to make readonly SessionState accessible in a Hub but it doesn't work. (https://gist.github.com/davidfowl/4692934) As soon as we add this code into our application messages sent to SignalR cause a HTTP 500 error which is caused by SignalR throwing the following exception.
[ArgumentNullException: Value cannot be null.Parameter name: s]
System.IO.StringReader..ctor(String s) +10688601
Microsoft.AspNet.SignalR.Json.JsonNetSerializer.Parse(String json, Type targetType) +77
Microsoft.AspNet.SignalR.Json.JsonSerializerExtensions.Parse(IJsonSerializer serializer, String json) +184
Microsoft.AspNet.SignalR.Hubs.HubRequestParser.Parse(String data) +101
Microsoft.AspNet.SignalR.Hubs.HubDispatcher.OnReceived(IRequest request, String connectionId, String data) +143
Microsoft.AspNet.SignalR.<>c__DisplayClassc.<ProcessRequest>b__7() +96
Microsoft.AspNet.SignalR.<>c__DisplayClass3c.<FromMethod>b__3b() +41
Microsoft.AspNet.SignalR.TaskAsyncHelper.FromMethod(Func`1 func) +67
No matter the mode that we set SessionStateBehavior (as shown by David Fowler's gist) we either get this exception when sending a message to the Hub or SessionState is null when we are in the Hub's OnConnect.
So, after all that pre-amble, what we are asking is how do people update the appropriate client when working with this type of disconnected messaging in SignalR?
If you're looking to send data to clients outside of a normal request to a hub then I'd recommend having a static Concurrent Dictionary on your hub that manages your users and maps them to corresponding connection Id's.
With this approach you can send to any user at any point based on their mapped Connection Id. Therefore when sending your data to Biztalk all you need to do is send your user id (created by you) and then when the data flows back to SignalR you can lookup the ConnectionId (if one exists) for that given user id.
Lastly, you can manage your user mappings by adding users to your concurrent dictionary in OnConnected, adding only if they are not there in OnReconnected, and removing in OnDisconnected.

Resources