How to keep Azure AD sign-on parameters with ASP.NET subdomains - asp.net

I'm implementing, to an existing ASP.NET web application, the authentication via Azure AD and OpenIdConnect. All the packages version are listed at the end of the question
The application correctly contacts the Microsoft login service and the id_token is returned in the HTTP response, but when I try to access it inside the code with the Request structure, it appears to be Nothing.
(In the image below, Request.Url is the action url used within the Microsoft service returned form)
Going by exclusion in all the steps that the application performs, I think that the problem could be found in the URL structure generated by ASP.NET, in my case is http://localhost:50725/CONNECTION_ID/HomePage.aspx, where the CONNECTION_ID field is dynamic and reassigned for each connection.
Analyzing the HTTP packets, in fact, I find as a response to the sending of the token by Microsoft a "redirect" to the address linked to the user's connection, which, when loaded, loses the data related to authentication
<html>
<head>
<title>Object moved</title>
</head>
<body>
<h2>Object moved to here.</h2>
</body>
</html>
Based on other guides/answers and the Azure Application Registration form, I could not use any wildcards to define the return url for the authentication process.
How can I keep track of the authentication parameters to fully authenticate the user in my application?
EDIT
Debugging even more the code-flow I've found another issue, basically the Azure login procedure response triggers the Session_start event inside the Global.asax, therefore is creates a new Session.
The situation that I'm observing is the following:
The user opens the web application and tries the "Microsoft Login" option
The request is made to the login service
The id_token is passed via HTTP POST request back to the application, this triggers the Application_BeginRequest event inside the Global.asax
The request then triggers the Session_start event also from the Global.asax creating a new session and a new "base Url" for the current connection, therefore loosing track of the original session who called the authentication method and the id_token previously received
So, the real problem seems to be to keep the current session active and reload it with the authentication parameter provided by Microsoft
PACKAGES VERSION
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.Cors" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Cors" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.IdentityModel.Logging" version="5.3.0" targetFramework="net45" />
<package id="Microsoft.IdentityModel.Protocols" version="5.3.0" targetFramework="net45" />
<package id="Microsoft.IdentityModel.Protocols.OpenIdConnect" version="5.3.0" targetFramework="net45" />
<package id="Microsoft.IdentityModel.Tokens" version="5.3.0" targetFramework="net45" />
<package id="Microsoft.Owin" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Cors" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Cookies" version="4.2.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.OpenIdConnect" version="4.2.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
<package id="System.IdentityModel.Tokens.Jwt" version="5.3.0" targetFramework="net45" />
</packages>

We have tried the same in our environment and it works fine.
To Authenticate Azure AD(Microsoft Identity) in asp.net application we need to provide app registration details in our appsettings.json in below format.
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "microsoft.onmicrosoft.com",
"TenantId": "xxxxxxxxxxxxxxxxxxb47",
"ClientId": "xxxxxxxxxxxxxxxxxx02",
"CallbackPath": "/signin-oidc",
"SignedOutCallbackPath": "/signout-callback-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
You need to add following Required packages , In my case .csproj as below:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-WebApplication11-xxxx027-0xx2-xxA-xxD-D39xxx</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.1" NoWarn="NU1605" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.1" NoWarn="NU1605" />
<PackageReference Include="Microsoft.Identity.Web" Version="1.16.0" />
<PackageReference Include="Microsoft.Identity.Web.UI" Version="1.16.0" />
</ItemGroup>
</Project>
Here is my program.cs file
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
builder.Services.AddRazorPages()
.AddMicrosoftIdentityUI();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.MapControllers();
app.Run();
Add AUTHORIZE attribute in homecontroller.cs as below:
SAMPLE OUTPUT FOR REFERNCE:-
signin:
Successfully signout:
For more information please refer this MICROSOFT DOCUMENTATION: Add sign-in to Microsoft to an ASP.NET web app

Related

Insights InstrumentationKey not populated after assignment in global.asax.cs

I have a .NET Framework 4.6.1 Web API solution which uses these Nuget packages:
<package id="Microsoft.ApplicationInsights" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.4.0" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.Web" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.WindowsServer" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.9.1" targetFramework="net461" />
<package id="Microsoft.AspNet.TelemetryCorrelation" version="1.0.5" targetFramework="net461" />
In the global.asax.cs I have this code:
protected void Application_Start()
{
TelemetryConfiguration.Active.InstrumentationKey = ConfigurationManager.AppSettings[$"Insights-{EnvironmentConfig.EnvironmentName}"];
GlobalConfiguration.Configure(WebApiConfig.Register);
}
I can confirm that the ConfigurationManager.AppSettings[] value retrieval does indeed retrieve a valid Insights key.
In the controllers I have:
public class MyController : ApiController
{
TelemetryClient telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
[Route("api/DoSomething")]
[HttpPost]
public async Task<HttpResponseMessage> DoSomething()
{
try
{
// stuff happens
}
catch (Exception ex)
{
telemetryClient.TrackException(ex); // does not log
throw ex;
}
}
}
If I put a stop point at // stuff happens (there is actual code there, of course) and inspect the telemetryClient I can see the InstrumentationKey property is empty. This means I need to add a line everywhere I instantiate the TelemetryClient class and deliberately populated it.
How can I get it to be populated from global.asax.cs onwards?
Tried with both appsetting property ConfigurationManager.AppSettings & WebConfigurationManager.AppSettings I am able to view the Instrumentation key in TelemetryConfiguration & logs over Application Insights.
We are adding our instrumentation key in TelemetryConfig which is available in Telemetryconfig.
protected void Application_Start()
{
TelemetryConfiguration.Active.InstrumentationKey = ConfigurationManager.AppSettings[$"Insights-{EnvironmentConfig.EnvironmentName}"];
//TelemetryConfiguration.Active.InstrumentationKey = WebConfigurationManager.AppSettings[$"Insights-{EnvironmentConfig.EnvironmentName}"];
GlobalConfiguration.Configure(WebApiConfig.Register);
}

Rebus: Is it not possible to use Rebus.Castle.Windsor along with Rebus 5.3

While trying to use rebus castle windsor along with rebus 5.3 then giving compile time error that "IHanlderActivator" is defined in an assembly which is not referenced, must add a reference to assembly rebus 4.0
Is rebus castle windsor only compatible with rebus 4.0 now?
It's certainly possible.
I've just created a Console Application (.NET 4.7.2) and installed the
Rebus
Rebus.Castle.Windsor
Rebus.XmlConfig (because I can see you're using that)
NuGet packages, which in turn resulted in the following packages.config:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Castle.Core" version="4.2.0" targetFramework="net472" />
<package id="Castle.Windsor" version="4.1.0" targetFramework="net472" />
<package id="Newtonsoft.Json" version="11.0.1" targetFramework="net472" />
<package id="Rebus" version="5.3.1" targetFramework="net472" />
<package id="Rebus.Castle.Windsor" version="4.1.0" targetFramework="net472" />
<package id="Rebus.XmlConfig" version="4.0.0" targetFramework="net472" />
</packages>
With this little program:
namespace ConsoleApp1
{
class Program
{
static void Main()
{
using (var container = new WindsorContainer())
{
Configure.With(new CastleWindsorContainerAdapter(container))
.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "windsor-test"))
.Routing(r => r.TypeBasedRoutingFromAppConfig())
.Start();
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
}
}
}
}
I get this:
Could you try and check e.g. how your packages.config differs from mine?

Microsoft.WebApplication.targets + Disable_CopyWebApplication=True doesn't prevent a csproj from creating a _PublishedWebsites folder

Got a dummy project + a console project which apply xslt transformations so they employ Microsoft.WebApplication.targets in their respective .csproj files like so:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{39560935-7551-4789-9666-4A48AD0FE3C7}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>...</RootNamespace>
<AssemblyName>...</AssemblyName>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
**<Disable_CopyWebApplication>True</Disable_CopyWebApplication>**
</PropertyGroup>
[...]
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<UsingTask TaskName="TransformXml" AssemblyFile="$(VSToolsPath)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="BeforeBuild">
<Exec Command=".\.nuget\nuget.exe restore .\packages.config -PackagesDirectory .\..\packages" />
<Delete Files="Config\ConnectionStrings\ConnectionStrings.config" />
<Message Text="=====================================================================================================================================================" />
<Message Text="Applying XSLT transformations (Disable_CopyWebApplication='$(Disable_CopyWebApplication)') using 'Microsoft.WebApplication.targets' from:" />
<Message Text="" />
<Message Text="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" />
<Message Text="" />
<TransformXml Source="Config\ConnectionStrings\ConnectionStrings.base.config" Transform="Config\ConnectionStrings\ConnectionStrings.$(Configuration.Replace('dbg#', '').Replace('rls#', '')).config" Destination="Config\ConnectionStrings\ConnectionStrings.config" />
<Message Text="=====================================================================================================================================================" />
</Target>
To generate production builds for said projects in our build server we build them like so:
<MSBuild Projects="$(_solutionFile)"
Targets="$(TargetProject)"
Properties="Platform=$(Platform);OutputPath=$(PublishUrl);Configuration=$(Configuration);"
ToolsVersion="15.0"
/>
As shown above we employ
<Disable_CopyWebApplication>True</Disable_CopyWebApplication>
Still the _PublishedWebsite folder does get created anyways. What could we be missing here?
UPDATE
According to the debugging statements we placed in our .csproj file the "Microsoft.WebApplication.targets" which gets employed during the build is this one:
"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets"
The internal task which copies the "website" (exe in our case) is this:
<Target Name="_CopyWebApplication"
Condition="!$(Disable_CopyWebApplication) And '$(OutDir)' != '$(OutputPath)'"
DependsOnTargets="$(_CopyWebApplicationDependsOn)">
<CallTarget Condition="'$(OnAfter_CopyWebApplication)' != ''" Targets="$(OnAfter_CopyWebApplication)" RunEachTargetSeparately="true" />
</Target>
This task appears to be working as intended because it turns out that _PublishedWebsite doesn't contain any of the compiled dlls of the exe-project. It contains only the roslyn dlls/exes with the following folder structure:
<Project_Output_Folder>\_PublishedWebsites\<Project.Name.Here>\bin\roslyn
I take it that the inclusion of the nuget packages:
Microsoft.Net.Compilers
and/or
Microsoft.CodeDom.Providers.DotNetCompilerPlatform
is what's causing the problem. The nuget packages being used are these:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="6.2.0" targetFramework="net471" allowedVersions="[6.2.0]" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.8" targetFramework="net471" allowedVersions="[1.0.8]" />
<package id="Microsoft.Net.Compilers" version="2.6.1" targetFramework="net471" developmentDependency="true" allowedVersions="[2.6.1]" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net471" allowedVersions="[10.0.3]" />
<package id="Oracle.ManagedDataAccess" version="12.2.1100" targetFramework="net471" allowedVersions="[12.2.1100]" />
<package id="Oracle.ManagedDataAccess.EntityFramework" version="12.2.1100" targetFramework="net471" allowedVersions="[12.2.1100]" />
<package id="StructureMap" version="4.6.1" targetFramework="net471" allowedVersions="[4.6.1]" />
<package id="System.Reflection.Emit.Lightweight" version="4.3.0" targetFramework="net471" allowedVersions="[4.3.0]" />
</packages>
So I guess the question boils down to how can one make the Compilers package respect the dont-copy flag we are setting?

PhoneGap (Build) & SignalR, works everywhere except when actually installed on device with vague error

I have created a SignalR server, a web client, and a mobile application built with PhoneGap Build. When I launch the PhoneGap application with lite-server, PhoneGap CLI, or the PhoneGap Desktop Application the SignalR works flawlessly between the web client and the PhoneGap application. This includes using the PhoneGap mobile application to connect to the PhoneGap Desktop application. The only time it fails is when I build it with PhoneGap Build and install the APK on the device. I have no explanation for this error.
I have handled CORS through the WEB.CONFIG of the server. It is a plain ASP.NET application that just has an OWIN startup file to configure SignalR and a Hub class.
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, DELETE, TOKEN" />
<add name="Access-Control-Allow-Credentials" value="false"/>
</customHeaders>
</httpProtocol>
</system.webServer>
The frustrating part is that the error that is produced when $.connection.hub.start fails is just "Error: Error during negotiation request"
When 'deviceready' event triggers I call initiateSignalR()
var appConfig = {
'serverUrl': "http://wolf-signalrserver.azurewebsites.net"
}
var initiateSignalR = function(){
if ($.signalR) {
}
var username = prompt("username");
var success = `
<div class ="serverMessage">
<span>--- WELCOME, ${username} ---</span>
</div>
`
$('#chatbox').append(success)
$.connection.hub.logging = true
$.connection.hub.qs = { 'username': username }
$.connection.hub.url = appConfig.serverUrl + "/signalr";
var chatHub = $.connection.chatHub
chatHub.client.broadcastMessage = function (name, message) {
console.log("Data Incoming ---- Name: " + name + " Message: " + message);
var message = `
<div class="row">
<span class="col-sm-2">${name}:</span>
<span class="col-sm-9"> ${message}</span>
</div>
`
$('#chatbox').append(message)
}
$('#messageButton').on('click', function () {
chatHub.server.send(username, $('#messageBox').val())
})
$('#messageForm').on('submit', function (e) {
e.preventDefault();
chatHub.server.send(username, $('#messageBox').val())
})
$.connection.hub.start({ withCredentials: false, jsonp: true })
.done(function () {
console.log("Connected successfully to SignalR");
var success = `
<div class ="serverMessage">
<span>--- Successfully connected to the server ---</span>
</div>
`
$('#chatbox').append(success)
})
.fail(function (err) {
console.log("Unable to connect to SignalR")
alert(err);
})
}
I have a git repo of this here: https://github.com/PhilWolf91/SignalR
I realize there are tons of questions here with this, but none of them have a detailed answer to how they fixed it.
Ex: SignalR .Net Client fails with 500 server error on device, on simulator works fine
OK. I'm a giant idiot. When I was cleaning up the Config.Xml I removed the network permission AND the default White List plugin.
<feature name="http://api.phonegap.com/1.0/network" />
<gap:plugin name="cordova-plugin-whitelist" source="npm" />
Full functional config for this project
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.wolf.signalrphonegap" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:gap="http://phonegap.com/ns/1.0">
<name>SignalRPhoneGap</name>
<description>
Hello World sample application that responds to the deviceready event.
</description>
<author email="phillip.wolf91#gmail.com" href="http://phillipwolf91.wordpress.com">
Wolf Software
</author>
<feature name="http://api.phonegap.com/1.0/network" />
<gap:plugin name="cordova-plugin-whitelist" source="npm" />
<content src="index.html" />
<preference name="DisallowOverscroll" value="true" />
<preference name="android-minSdkVersion" value="14" />
<platform name="android">
</platform>
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<platform name="android">
<allow-intent href="market:*" />
</platform>
</widget>
I now have SignalR working between the Server, Web Client, and PhoneGap app installed on the device

Intermittent problems with SignalR Hubs (in the Cloud) callback from Server to Client method

So far, SignalR Hubs has been working perfectly with a locally hosted website in IIS 7.5 on my dev machine. I have the client making a signalr call to the server on a click event, then the server does a 20 second thread delay before sending a response back to the callback method on the client. This works consistently across all browsers. However, when I deploy my application to the Windows Azure Cloud, SignalR begins to have these intermittent problems. Specifically, there seems to be a problem with the server reaching the callback method on the client. I verified this by watching the network traffic in Chrome Dev Tools. I can clearly see the POST connection being made out by signalr. It sits in "pending" status for 20 seconds and then the POST successfully completes when the server responds back. However, the callback method (with a simple alert message) on the client-side doesn't always fire for some reason. NOTE: In my testing, I noticed some strange behavior that when the callback method is not firing, I could get it to fire by doing a normal download of a file (by using href = window.baseUrl + '/CloudStorage/DownloadZip?') and then clicking on the button that triggers the signalr. As I'm watching this in network traffic, somehow that window.baseUrl BOM command triggers the signalr to do a reconnect. Would appreciate any help!
EDIT: I am using IE 10, latest Chrome, and latest Firefox for all my testing. IE 10 seems to have the most issues with signalr when the app is in the cloud, which is a little strange to me since this is an MS product. Also, I'm using version 1.1.2 of SignalR.
Here are my code snippets:
SERVER SIDE:
[HubName("MultiFile")]
public class MultiFile : Hub
{
[HubMethodName("Send")]
public void Send(string DocID)
{
System.Threading.Thread.Sleep(20000);
// Call the addMessage method on caller client
Clients.Caller.addMessage(DocID);
}
}
CLIENT SIDE:
$('#dBtn').click(function () {
var docIds = sceneLayoutService.getSelection();
var href;
var docIdsParam;
if (docIds.length === 0) {
// signalr test code below
// Proxy created on the fly
var test_connection = $.connection.MultiFile;
// Declare a function on the MultiFile hub so the server can invoke it
test_connection.client.addMessage = function (message) {
alert(message);
};
// Start the connection
$.connection.hub.start().done(function () {
// Call the chat method on the server
test_connection.server.Send("you need to select one!");
});
return false;
}
else if (docIds.length == 1) {
docIdsParam = "docId=" + docIds;
href = window.baseUrl + '/CloudStorage/Download?' + docIdsParam;
}
else {
docIdsParam = jQuery.param(docIds.map(function (value) {
//var parts = value.match(/[e[B|b]:\/\/[^\/]*\/\d*\/(\d*)/);
//return { "name": "docIds", "value": parts[1] };
return { "name": "docIds", "value": value };
}));
href = window.baseUrl + '/CloudStorage/DownloadZip?' + docIdsParam;
}
$(this).attr('href', href);
return true;
});
LIST OF PACKAGES:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Company.CONNECT.Analytics.eFWrapper" version="1.0.0.1" targetFramework="net40" />
<package id="Company.CONNECT.Analytics.Logging" version="1.0.0.11" targetFramework="net40" />
<package id="Company.CONNECT.Web" version="1.1.0.12" targetFramework="net40" />
<package id="Castle.Core" version="2.5.2" targetFramework="net40" />
<package id="Castle.Core-log4net" version="2.5.2" targetFramework="net40" />
<package id="Castle.Windsor" version="2.5.4" targetFramework="net40" />
<package id="Castle.Windsor-log4net" version="2.5.2" targetFramework="net40" />
<package id="CommonServiceLocator" version="1.0" targetFramework="net40" />
<package id="EnterpriseLibrary.Common" version="5.0.505.0" targetFramework="net40" />
<package id="EnterpriseLibrary.WindowsAzure.Configuration" version="5.0.1118.2" targetFramework="net40" />
<package id="EntityFramework" version="4.1.10331.0" targetFramework="net40" />
<package id="HtmlAgilityPack" version="1.4.6" targetFramework="net40" />
<package id="jQuery" version="2.0.2" targetFramework="net40" />
<package id="jQuery.UI.Combined" version="1.10.3" targetFramework="net40" />
<package id="jQuery.Validation" version="1.8.0" targetFramework="net40" />
<package id="jQuery.vsdoc" version="1.5.1" targetFramework="net40" />
<package id="log4net" version="1.2.10" targetFramework="net40" />
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Providers" version="1.1" targetFramework="net40" />
<package id="Microsoft.AspNet.Providers.Core" version="1.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.JS" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.1.2" targetFramework="net40" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.0.0" targetFramework="net40" />
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net40" />
<package id="Microsoft.Data.Edm" version="5.5.0" targetFramework="net40" />
<package id="Microsoft.Data.OData" version="5.5.0" targetFramework="net40" />
<package id="Microsoft.IdentityModel" version="6.1.7600.16394" targetFramework="net40" />
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.1" targetFramework="net40" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
<package id="Microsoft.WindowsAzure.ConfigurationManager" version="2.0.1.0" targetFramework="net40" />
<package id="Modernizr" version="2.6.2" targetFramework="net40" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net40" />
<package id="Owin" version="1.0" targetFramework="net40" />
<package id="Pkcs12ProtectedConfigurationProvider" version="1.0.1" targetFramework="net40" />
<package id="RequireJS" version="2.1.8" targetFramework="net40" />
<package id="SevenZipSharp" version="0.64" targetFramework="net40" />
<package id="SlowCheetah" version="2.5.5" targetFramework="net40" />
<package id="System.Spatial" version="5.5.0" targetFramework="net40" />
<package id="System.Web.Providers" version="1.2" targetFramework="net40" />
<package id="Unity" version="2.1.505.2" targetFramework="net40" />
<package id="Unity.Interception" version="2.1.505.2" targetFramework="net40" />
<package id="WebGrease" version="1.1.0" targetFramework="net40" />
<package id="WindowsAzure.Storage" version="2.0.5.1" targetFramework="net40" />
<package id="WindowsAzure.Storage" version="2.0.6.0" targetFramework="net40" />
</packages>
It turns out there are 2 Web Role instances running in my Windows Azure configuration. When there are multiple Azure instances running, a "backplane" needs to be used since we have no control over which instance the Azure Load Balancer chooses. This is why the messages sent back from the server to client were failing 50% of the time.
http://www.asp.net/signalr/overview/performance-and-scaling/scaleout-in-signalr

Resources