ASP.NET SignalR Deployment & Usage Guide
⚠️ Maintenance Mode Notice: ASP.NET SignalR is in maintenance mode. No new features will be added. This guide applies to .NET Framework applications only. For new projects using .NET Core/.NET 5+, use ASP.NET Core SignalR.
1. Prerequisites
Development Environment
- .NET Framework 4.5 or higher (required for SignalR 2.x)
- Visual Studio 2017 or later (VS 2022 recommended for compatibility)
- IIS 7.5 or higher with WebSocket Protocol enabled (for WebSocket transport support)
- NuGet Package Manager (included with Visual Studio)
- Git (for source builds only)
Runtime Requirements
- Windows Server 2012+ or Windows 10/11 (for server deployment)
- Full .NET Framework (not .NET Core/.NET 5+)
- For self-hosting: OWIN compatible host
Optional for Scale-Out
- SQL Server 2008+ (for SQL Server backplane)
- Redis 2.6+ (for Redis backplane)
- Azure Service Bus (for cloud scale-out)
2. Installation
Option A: NuGet Package Installation (Recommended)
Install the server package in your ASP.NET web application:
Install-Package Microsoft.AspNet.SignalR
Install the client package in your client application (WPF, Console, Web, etc.):
Install-Package Microsoft.AspNet.SignalR.Client
Install the official sample to explore features:
Install-Package Microsoft.AspNet.SignalR.Sample
Option B: Building from Source
For contributors or custom builds:
# Clone the repository
git clone https://github.com/SignalR/SignalR.git
cd SignalR
# Build (Windows only)
build.cmd
Note: The solution requires Visual Studio 2017 or later to open. The build script handles NuGet package restoration automatically.
3. Configuration
OWIN Startup Configuration
Create or modify Startup.cs in your web application root:
using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(YourNamespace.Startup))]
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Basic SignalR configuration
var config = new HubConfiguration
{
EnableDetailedErrors = true, // Set false in production
EnableJavaScriptProxies = true,
Resolver = new DefaultDependencyResolver()
};
app.MapSignalR(config);
}
}
Web.config Settings
Add or verify these settings in Web.config:
<system.webServer>
<handlers>
<!-- Ensure SignalR handlers are not blocked -->
<remove name="WebDAV" />
<add name="SignalR" path="signalr/hubs" verb="*" type="Microsoft.AspNet.SignalR.Hubs.HubDispatcher" />
</handlers>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
<system.web>
<httpRuntime targetFramework="4.5" />
<compilation debug="true" targetFramework="4.5" />
</system.web>
Transport Configuration
To force specific transports or configure timeouts, modify HubConfiguration:
var config = new HubConfiguration
{
// Transport timeout settings
EnableJSONP = true, // For cross-domain support
// Note: Transport selection is typically handled client-side
};
Scale-Out Configuration (Redis Example)
Install the Redis package:
Install-Package Microsoft.AspNet.SignalR.Redis
Configure in Startup.cs:
GlobalHost.DependencyResolver.UseRedis("server", port, "password", "SignalRApp");
4. Build & Run
Local Development with IIS Express
- Create a Hub:
public class ChatHub : Hub
{
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
}
- Create Client Page (
index.html):
<!DOCTYPE html>
<html>
<head>
<script src="Scripts/jquery-3.6.0.min.js"></script>
<script src="Scripts/jquery.signalR-2.4.3.min.js"></script>
<script src="/signalr/hubs"></script>
</head>
<body>
<script>
$(function () {
var chat = $.connection.chatHub;
chat.client.broadcastMessage = function (name, message) {
console.log(name + ': ' + message);
};
$.connection.hub.start().done(function () {
chat.server.send('System', 'Connected');
});
});
</script>
</body>
</html>
- Run: Press F5 in Visual Studio (IIS Express) or run:
# If using full IIS
iisexpress /path:"C:\path\to\your\app" /port:8080
Self-Hosting (Console/Windows Service)
For desktop applications or Windows Services:
using Microsoft.Owin.Hosting;
using Microsoft.AspNet.SignalR;
using System;
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:8080";
using (WebApp.Start<Startup>(url))
{
Console.WriteLine($"Server running at {url}");
Console.ReadLine();
}
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
Note: Self-host requires running with administrator privileges or reserving the URL:
netsh http add urlacl url=http://+:8080/ user=DOMAIN\Username
5. Deployment
IIS Deployment (Traditional)
- Publish from Visual Studio: Right-click project → Publish → File System
- Configure IIS:
- Create Application Pool running .NET CLR Version 4.0
- Enable WebSocket Protocol (Server Manager → Add Roles and Features)
- Set Application Request Routing (ARR) if using load balancer
- Web.config Production Settings:
<configuration>
<system.web>
<customErrors mode="RemoteOnly" />
<compilation debug="false" targetFramework="4.5" />
</system.web>
</configuration>
Azure Web Apps (Classic)
- Deploy via Git, FTP, or Web Deploy
- Enable WebSockets: Azure Portal → App Service → Configuration → General Settings → Web sockets: On
- ARR Affinity: Disable for SignalR (stateless) unless using sticky sessions for other reasons
- Scale-Out: Use Azure Service Bus or Redis backplane for multiple instances
Windows Service Deployment
- Create a Windows Service project
- Install the OWIN self-host package:
Install-Package Microsoft.Owin.Host.HttpListener
Install-Package Microsoft.Owin.Hosting
- Install the service using
sc.exeor Topshelf:
sc create SignalRService binPath= "C:\path\to\your\service.exe"
Performance Counter Considerations
SignalR installs performance counters on first run. For production servers:
- Ensure the application pool identity has permissions to create performance counter categories, OR
- Run the application once as Administrator to initialize counters, OR
- Disable performance counters if not needed:
var config = new HubConfiguration
{
Resolver = new DefaultDependencyResolver()
};
// Replace PerformanceCounterManager with no-op
config.Resolver.Register(typeof(IPerformanceCounterManager), () => new NoOpPerformanceCounter());
6. Troubleshooting
Connection Issues
Symptom: 404 errors on /signalr/hubs or /signalr/negotiate
- Solution: Verify OWIN Startup class is discoverable. Check that
Microsoft.Owin.Host.SystemWebis installed for IIS hosting:
Install-Package Microsoft.Owin.Host.SystemWeb
WebSocket Transport Fails
Symptom: Client falls back to Server-Sent Events or Long Polling
- IIS: Ensure WebSocket Protocol is installed (Control Panel → Programs → Turn Windows features on or off → IIS → Application Development Features → WebSocket Protocol)
- Azure: Enable WebSockets in Portal (see Deployment section)
- Proxy: Check that intermediate proxies support WebSocket upgrade
Cross-Domain Issues
Symptom: CORS errors in browser console
- Solution: Install OWIN CORS package and configure:
Install-Package Microsoft.Owin.Cors
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
Version Mismatch
Symptom: "Protocol error" or negotiation failures
- Solution: Ensure client and server versions match. Check
jquery.signalR-{version}.jsmatches the server assembly version (2.4.x).
Performance Counter Errors
Symptom: "Access denied" or "Category does not exist" in logs
- Solution: Run as Administrator once to initialize, or disable counters (see Configuration section). This is common on locked-down production servers.
Memory Leaks in Long-Running Processes
Symptom: Memory growth in self-hosted services
- Solution: Ensure proper disposal of
HubConnectionon client side. On server, verifyIConnectionobjects are being cleaned up after disconnect timeout (default 30 seconds).
Load Balancer Issues
Symptom: Random disconnections with multiple servers
- Solution: Configure a backplane (Redis, SQL Server, or Service Bus). Without sticky sessions, SignalR requires a backplane to synchronize across instances.
Debug Logging
Enable detailed tracing in Web.config:
<system.diagnostics>
<sources>
<source name="Microsoft.AspNet.SignalR" switchValue="Verbose">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" />
<add name="SignalRListener" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="SignalRListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="signalr.log" />
</sharedListeners>
</system.diagnostics>